闽公网安备 35020302035485号
最近在开发个Android应用,本来是想通过CameraX实现同时预览多个摄像头,通过官网文档介绍,在CameraX 1.3 后通过ConcurrentCamera运行多个摄像头,但实际在小米10(Android 13)运行,报错当前设备不支持ConcurrentCamera,代码CameraProvider.availableConcurrentCameraInfos查询也是返回数量0,表示设备不支持。
val cameraSelector =builder
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.requireLensFacing(CameraSelector.LENS_FACING_FRONT)
.build()
因此个人下定义是在cameraX 1.3.0-alpha07前应该是不支持预览多摄像头的。如果有小伙伴验证OK,希望可以告知,多谢。故采用Camera2来实现多摄像头同时预览。
<uses-feature android:name="android.hardware.camera.any" /> <uses-permission android:name="android.permission.CAMERA" />记得先申请权限,以及动态申请!!
fun isSupportCamera(): Boolean {
// 堆代码 duidaima.com
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、获取摄像头列表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、打开摄像头fun openCamera(cameraId: String) {
initCameraManager()
cameraManager?.openCamera(cameraId, stateCallback, handler)
}
我们一起看看stateCallback函数的实现。也就是当我们打开摄像头,摄像头相关状态会通过下面三个函数进行回调,因为这里采用ViewModel方式,所以会多一份回调到Activity。不用着急,最后有完整代码。 private val stateCallback=object : StateCallback() {
// 堆代码 duidaima.com
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、效果