I am trying to capture image using Camera2 API of Android. However, I am having this error when I try to add an ImageReader
's surface as a listening surface. I have tried looking into the source code of the API and it looks like the error is thrown when a Surface
cannot be converted into a Stream
. This can be looked in Android's source in CaptureRequest.java
near line 738.
My code is following.
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 })
}
The following is the stack trace for the error.
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)
As pointed out by @Husayn in his comments, the wrong target was being passed to the capture request. The following changes solved the problem.
cameraDevice.createCaptureSession(mutableListOf(recordingSurface), captureCallback, Handler { true })