本来是想经过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