Camera2 同时预览多个摄像头,CameraX不行?
本来是想通过CameraX
实现同时预览多个摄像头,通过官网文档介绍,在CameraX 1.3
后通过ConcurrentCamera
运行多个摄像头,但实际在小米10(Android 13)运行,报错当前设备不支持ConcurrentCamera
,代码CameraProvider.availableConcurrentCameraInfos
查询也是返回数量0,表示设备不支持。
请教ChatGPT
回答,来进行编写,回答可以通过代码创建多个preview
和requireLensFacing
,但是实际运行时不可行的。程序会报下面代码问题,选择摄像头设备异常。
val cameraSelector =builder
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build()
因此个人下定义是在cameraX 1.3.0-alpha07
前应该是不支持预览多摄像头的。如果有小伙伴验证OK,希望可以告知,多谢。
故采用Camera2
来实现多摄像头同时预览。
Camera2 同时预览摄像头
记得先申请权限,以及动态申请!!
<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />
记得先申请权限,以及动态申请!!
1、判断设备是否支持摄像头
fun isSupportCamera(): Boolean {
initCameraManager()
return cameraManager!!.cameraIdList.isNotEmpty()
}
initCameraManager
主要是初始化CameraManager
对象cameraManager
。我们通过cameraIdList
列表是否空来判断是否有摄像头。
private fun initCameraManager() {
if (cameraManager == null) {
cameraManager = getApplication<Application>().getSystemService(AppCompatActivity.CAMERA_SERVICE) as CameraManager
}
}
2、获取摄像头列表
我们遍历第1步获取到的摄像头ID列表,然后通过getCameraCharacteristics
查询该摄像头相关的数据,封装到NCameraInfo
对象中。这里我们只查询几个简单的信息。
fun getCameraListInfo() {
initCameraManager()
if (cameraManager.cameraIdList.isNotEmpty()) {
for (cameraId in cameraManager.cameraIdList) {
val cameInfo = NCameraInfo()
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
cameInfo.id = cameraId
cameInfo.face ="${ getFaceStr(facing)},CameraId:${cameraId}"
cameraMap[cameraId] = cameInfo
}
cameraInfo.value = cameraMap.values.toList()
}
}
3、打开摄像头
打开摄像头非常简单,只需要调用openCamera
函数即可,主要是stateCallback
函数的实现。其中handler,是用来切换到主线程var handler = Handler(Looper.getMainLooper())
。
fun openCamera(cameraId: String) {
initCameraManager()
cameraManager?.openCamera(cameraId, stateCallback, handler)
}
我们一起看看stateCallback
函数的实现。也就是当我们打开摄像头,摄像头相关状态会通过下面三个函数进行回调,因为这里采用ViewModel
方式,所以会多一份回调到Activity
。不用着急,最后有完整代码。
private val stateCallback=object : StateCallback() {
override fun onOpened(camera: CameraDevice) {
cameraMap[camera.id]?.apply {
cameraDevice = camera
state = 1
cameraCallback?.onCameraOpen(this)
}
}
override fun onDisconnected(camera: CameraDevice) {
cameraMap[camera.id]?.apply {
cameraDevice = camera
state = 0
cameraCallback?.onCameraClose(this)
}
}
override fun onError(camera: CameraDevice, error: Int) {
Log.e(TAG, "camera ${camera.id} error code:${error}")
cameraMap[camera.id]?.apply {
cameraDevice = camera
state = 3
cameraCallback?.onCameraError(this,error)
}
}
}
我们查看Activity
中的实现。onCameraOpen
函数主要动态创建TextureView
对象,添加到界面中,用于预览摄像头内容。
override fun onCameraOpen(camera: NCameraInfo) {
adapter.notifyItemChanged(adapter.items.indexOf(camera))
//创建TextureView
val textureView = TextureView(this)
textureView.id = View.generateViewId()
camera.previewId=textureView.id
val layoutParams = LinearLayout.LayoutParams(previewWidth, LayoutParams.MATCH_PARENT)
viewBinding.llCameraPreview.addView(textureView, layoutParams)
//textureview 与摄像头绑定
textureView.surfaceTextureListener=object:SurfaceTextureListener{
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
//创建Surface并用于摄像头渲染
val surface = Surface(textureView.surfaceTexture)
val builder = camera.cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)!!
builder.addTarget(surface)
camera.cameraDevice?.createCaptureSession(listOf(surface), object : StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
session.setRepeatingRequest(builder.build(),null,model.handler)
}
override fun onConfigureFailed(session: CameraCaptureSession) {
}
}, model.handler)
}
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
Log.d(TAG,"onSurfaceTextureSizeChanged")
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
Log.d(TAG,"onSurfaceTextureDestroyed")
return true
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
//Log.d(TAG,"onSurfaceTextureUpdated")
}
}
}
override fun onCameraClose(camera: NCameraInfo) {
Log.d(TAG,"onCameraClose:${camera}")
adapter.notifyItemChanged(adapter.items.indexOf(camera))
camera.cameraDevice?.close()
val view=viewBinding.llCameraPreview.findViewById<TextureView>(camera.previewId)
viewBinding.llCameraPreview.removeView(view)
}
override fun onCameraError(camera: NCameraInfo, error: Int) {
Log.e(TAG,"onCameraError:${camera},${error}")
adapter.notifyItemChanged(adapter.items.indexOf(camera))
camera.cameraDevice?.close()
}
4、效果
5、小坑
- 实测在小米10手机,先开启后摄,再开启前摄,前摄无法打开=》异常。先开前摄,再开后摄正常。
- 小米11、诺基亚x7实测正常。
项目地址,点我跳战,关键类:Camera2Activity
来源:juejin.cn/post/7244783947821236285