class AutomaticCapture(private val arguments: IntentArguments,
override val cameraCharacteristics: CameraCharacteristics,
override val imageReader: ImageReader = ImageReader.newInstance(arguments.resX, arguments.resY, if (arguments.rawImage) ImageFormat.RAW_SENSOR else ImageFormat.JPEG, 2)) : Capture {
override fun takeCapture(cameraDevice: CameraDevice, cameraCaptureSession: CameraCaptureSession, handler: Handler) {
Log.d("DebugInfo", "takeCapture() Automatic")
val captureRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
captureRequest.addTarget(imageReader.surface)
captureRequest.set(CaptureRequest.CONTROL_CAPTURE_INTENT, CaptureRequest.CONTROL_CAPTURE_INTENT_STILL_CAPTURE)
captureRequest.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO)
captureRequest.set(CaptureRequest.JPEG_ORIENTATION, arguments.orientation)
cameraCaptureSession.capture(captureRequest.build(), object: CameraCaptureSession.CaptureCallback() {
override fun onCaptureCompleted(
session: CameraCaptureSession,
request: CaptureRequest,
result: TotalCaptureResult
) {
super.onCaptureCompleted(session, request, result)
Log.d("DebugInfo", "Automatic Capture completed. RawImage: ${arguments.rawImage}")
var image: Image? = null
//Have to wait for image to become available on imageReader
while (image == null) {
image = imageReader.acquireLatestImage()
}
when (arguments.rawImage) {
true -> RawFileSaver().saveFileToLocation(image, arguments.filePath, arguments.fileName, cameraCharacteristics, result)
false -> JpegFileSaver().saveFileToLocation(image, arguments.filePath, arguments.fileName)
}
if (!arguments.doNotSaveJson) {
JsonFileSaver().saveCaptureResultToJson(arguments, result)
}
imageReader.close()
}
override fun onCaptureFailed(
session: CameraCaptureSession,
request: CaptureRequest,
failure: CaptureFailure
) {
super.onCaptureFailed(session, request, failure)
Log.d("DebugInfo", "Automatic Capture failed. Reason: ${failure.reason}, rawImage: ${arguments.rawImage}, wasImageCaptured: ${failure.wasImageCaptured()}")
takeCapture(cameraDevice, cameraCaptureSession, handler)
}
}, handler)
}
}
fun openCamera() {
cameraManager.openCamera(cameraId,
object: CameraDevice.StateCallback(){
override fun onOpened(camera: CameraDevice) {
Log.d("DebugInfo", "Inside openCamera()")
cameraDevice = camera
cameraDevice.createCaptureSession(listOf(capture.imageReader.surface),
object: CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
cameraCaptureSession = session
//Take capture here when everything is set and configured
capture.takeCapture(cameraDevice, session, handler)
//exit Activity here.
finish()
}
override fun onConfigureFailed(session: CameraCaptureSession) {
Log.d("DebugInfo", "onConfigureFailed()")
cameraDevice.close() }
}, handler)
}
override fun onDisconnected(camera: CameraDevice) {
Log.d("DebugInfo", "onDisconnected()")
camera.close()
}
override fun onError(camera: CameraDevice, error: Int) {
Log.d("DebugInfo", "onError() with error: $error")
camera.close()
}
}, handler)
}
I have a camera device that goes to onCaptureFailed() after the first try and manages to succeed after the second call to the takeCapture()-function inside the onCaptureFailed(). After the second call it goes onCaptureCompleted() and all goes well after that.
This code works on most devices I have tested but on one particular device it somehow needs to fail first once before succeeding. It takes about 4-5 seconds before the onCaptureFailed() gets called. The reason for failure is REASON_ERROR defined in CaptureFailure-class.
I have tried to prepare the captureSession and call onSurfacePrepared() but that didn’t change the outcome. I have also tried to captureRequest.build() and then sleep the Thread for a while but that also didn’t do anything.
I find it really interesting behaviour that somehow the second call always succeeds after the capture has failed once.
Antti Niemi is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.