以前學習了圖片和音頻,此次咱們嘗試使用 Android Camera API 獲取到視頻數據。git
此次使用的 API 是 Camera2
。Camera2
是 Google 在 Android L 以後推出的全新的相機 API。Camera2
支持的功能要比 Camera
豐富不少,可是相應的,也增長了 API 的使用難度。github
這是使用 Camera2 打開相機獲取預覽數據的流程圖:微信
NV21
是 YUV420p
的一種存儲模式。存儲順序是先存 Y
,再存 U
,而後再 VU
交替存儲。session
那麼問題來了,YUV 是啥?ide
這裏簡要介紹下,後續能夠專門一篇文章來介紹,固然你也能夠在網上尋找其餘資料來了解這個。學習
YUV 是一種顏色編碼方法,主要應用於電視系統和模擬視頻領域。其中 YUV 表明三個份量,Y
表明明亮度,U
和 V
表示的是色度。ui
此次咱們關注的是獲取視頻數據,因此對於相機相關的一些東西不會涉及。編碼
CameraManager
:攝像頭的管理類。 CameraCharacteristics
:用於描述特定攝像頭所支持的特性。 CameraDevice
:表明攝像頭。 CameraCaptureSession
:相機實際的控制端,咱們須要在相機上作什麼操做,都是由這個類發出相應的指令。 CameraRequest
:每次發起捕獲請求的時候都須要傳遞這個對象,這個類表明了一次捕獲請求,用於描述捕獲的各類參數。 此次咱們要獲取視頻數據,還有一個類很重要:spa
ImageReader
:能夠從 Surface
直接接收渲染的數據。須要注意的是,它並非專爲 Camera
設計的。 接下來用簡潔的代碼描述下如何使用 Camera2
API:設計
private fun configCamera(cameraManager: CameraManager, cameraId: String): Boolean {
val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId)
val facing = cameraCharacteristics[LENS_FACING]
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
// 不使用前置攝像頭
return false
}
val streamConfigurationMap =
(cameraCharacteristics[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]
?: return false)
mImageReader = ImageReader.newInstance(
mSurfaceView.width,
mSurfaceView.height,
ImageFormat.YUV_420_888,
2
)
mImageReader.setOnImageAvailableListener(ImageReaderAvailableListenerImp(), mBackgroundHandler)
mCameraId = cameraId
return true
}複製代碼
這裏是獲取目標相機的 ID,還有初始化 ImageReader
。
openCamera()
。 openCamera
以後在 onOpened
回調中初始化 Session
。 private fun createCameraPreviewSession(camera: CameraDevice) {
mPreviewRequestBuilder = camera.createCaptureRequest(TEMPLATE_PREVIEW)
mPreviewRequestBuilder.addTarget(mSurfaceView.holder.surface)
mPreviewRequestBuilder.addTarget(mImageReader.surface)
camera.createCaptureSession(
listOf(
mSurfaceView.holder.surface,
mImageReader.surface
), mCameraSessionStateCallback, mBackgroundHandler
)
}複製代碼
Session
建立完成後,在 onConfigured
回調中,發送請求。 override fun onConfigured(session: CameraCaptureSession) {
Log.d(TAG, "onConfigured")
session.setRepeatingRequest(
mPreviewRequestBuilder.build(),
object : CameraCaptureSession.CaptureCallback() {},
mBackgroundHandler
)
}複製代碼
ImageReader
,因此會在 onImageAvailable
回調中收到圖像的回傳。 override fun onImageAvailable(reader: ImageReader) {
val image = reader.acquireNextImage()
if (image.format == ImageFormat.YUV_420_888) {
val planes = image.planes
lock.lock()
if (!::y.isInitialized) {
y = ByteArray(planes[0].buffer.limit() - planes[0].buffer.position())
u = ByteArray(planes[1].buffer.limit() - planes[1].buffer.position())
v = ByteArray(planes[2].buffer.limit() - planes[2].buffer.position())
}
if (planes[0].buffer.remaining() == y.size) {
planes[0].buffer.get(y)
planes[1].buffer.get(u)
planes[2].buffer.get(v)
// 接下來經過轉換,能夠轉換爲 Bitmap 進行展現
}
lock.unlock()
}
image.close()
}複製代碼
這部分的完整代碼能夠在倉庫的 Camera2Helper
類中看到。
代碼仍是要有的,能夠在 GitHub 倉庫中找到:https://github.com/T-Oner/MediaPractice
最新更新請關注微信公衆號