尝试使用 Android Camera2 API 捕获图像时出错:CaptureRequest 包含未配置的输入/输出表面
Posted
技术标签:
【中文标题】尝试使用 Android Camera2 API 捕获图像时出错:CaptureRequest 包含未配置的输入/输出表面【英文标题】:Error while trying to capture Image using Android Camera2 API : CaptureRequest contains unconfigured Input/Output Surface 【发布时间】:2021-03-26 13:36:33 【问题描述】:我正在尝试使用 android 的 Camera2 API 捕获图像。但是,当我尝试将ImageReader
的表面添加为监听表面时,我遇到了这个错误。我已经尝试查看 API 的源代码,当 Surface
无法转换为 Stream
时,似乎会引发错误。这可以在 Android 的源代码中查看 CaptureRequest.java
靠近第 738 行。
我的代码如下。
private fun startCameraSession()
val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
if (cameraManager.cameraIdList.isEmpty())
// no cameras
return
val firstCamera = cameraManager.cameraIdList[1]
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
val toast = Toast(this)
toast.setText("No Permission Granted!")
toast.show()
return
cameraManager.openCamera(firstCamera, object: CameraDevice.StateCallback()
override fun onDisconnected(p0: CameraDevice)
override fun onError(p0: CameraDevice, p1: Int)
override fun onOpened(cameraDevice: CameraDevice)
// use the camera
val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraDevice.id)
cameraCharacteristics[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]?.let streamConfigurationMap ->
streamConfigurationMap.getOutputSizes(ImageFormat.YUV_420_888)?.let yuvSizes ->
val previewSize = yuvSizes.last()
// cont.
val displayRotation = windowManager.defaultDisplay.rotation
val swappedDimensions = areDimensionsSwapped(displayRotation, cameraCharacteristics)
// swap width and height if needed
val rotatedPreviewWidth = if (swappedDimensions) previewSize.height else previewSize.width
val rotatedPreviewHeight = if (swappedDimensions) previewSize.width else previewSize.height
surfaceView.holder.setFixedSize(rotatedPreviewWidth, rotatedPreviewHeight)
// Configure Image Reader
val imageReader = ImageReader.newInstance(rotatedPreviewWidth, rotatedPreviewHeight,
ImageFormat.YUV_420_888, 2)
imageReader.setOnImageAvailableListener(
val previewSurface = surfaceView.holder.surface
imageReader.setOnImageAvailableListener(
Log.d("camera","setOnImageAvailableListener")
imageReader.acquireLatestImage()?.let image ->
Log.d("camera","acquireLatestImage")
, Handler true )
, Handler true )
val previewSurface = surfaceView.holder.surface
val recordingSurface = imageReader.surface
val captureCallback = object : CameraCaptureSession.StateCallback()
override fun onConfigureFailed(session: CameraCaptureSession)
override fun onConfigured(session: CameraCaptureSession)
// session configured
val previewRequestBuilder = cameraDevice.createCaptureRequest(TEMPLATE_PREVIEW).apply
addTarget(recordingSurface)
session.setRepeatingRequest(
previewRequestBuilder.build(),
object: CameraCaptureSession.CaptureCallback() ,
Handler true
)
cameraDevice.createCaptureSession(mutableListOf(previewSurface), captureCallback, Handler true )
, Handler true )
以下是错误的堆栈跟踪。
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.security.camerapractice, PID: 15957
java.lang.IllegalArgumentException: CaptureRequest contains unconfigured Input/Output Surface!
at android.hardware.camera2.CaptureRequest.convertSurfaceToStreamId(CaptureRequest.java:738)
at android.hardware.camera2.impl.CameraDeviceImpl.submitCaptureRequest(CameraDeviceImpl.java:1179)
at android.hardware.camera2.impl.CameraDeviceImpl.setRepeatingRequest(CameraDeviceImpl.java:1227)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:312)
at com.security.camerapractice.MainActivity$startCameraSession$1$onOpened$$inlined$let$lambda$2.onConfigured(MainActivity.kt:179)
at android.hardware.camera2.impl.CallbackProxies$SessionStateCallbackProxy.lambda$onConfigured$0$CallbackProxies$SessionStateCallbackProxy(CallbackProxies.java:53)
at android.hardware.camera2.impl.-$$Lambda$CallbackProxies$SessionStateCallbackProxy$soW0qC12Osypoky6AfL3P2-TeDw.run(Unknown Source:4)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
【问题讨论】:
我无法从您的 sn-p 中看出,但您是否在等待SurfaceView
的表面准备好后再将其传递给相机? SurfaceView 的表面只能在其surfaceCreated() 和surfaceDestroyed() 回调之间使用。
不是SurfaceView的Surface。它是 ImageReader 的一个 Surface。
从 sn-p 看来,您正在使用错误的目标构建捕获会话,您正在传递 surfaceView 的表面,但您正在使用 imageReader 的表面构建捕获请求。
【参考方案1】:
正如@Husayn 在他的 cmets 中所指出的,错误的目标被传递给捕获请求。以下更改解决了该问题。
cameraDevice.createCaptureSession(mutableListOf(recordingSurface), captureCallback, Handler true )
【讨论】:
以上是关于尝试使用 Android Camera2 API 捕获图像时出错:CaptureRequest 包含未配置的输入/输出表面的主要内容,如果未能解决你的问题,请参考以下文章
使用 Camera2(Android 版本 21)API 录制 60fps 视频
使用 Android Camera2 API 进行人脸检测和画圆