I am working on a Camera2 library that has a auto-focusing preview, and should support "tap to focus" to focus to a specific area.
I tried to follow tutorials in the internet, read Google's camera-samples code as well as browsing camerakit-android, CameraView and react-native-camera, but none of them showed a complete example or were simply not doing anything/no focusing, so I couldn't get it to work.
This is my code:
suspend fun focus(point: Point) {
// prepare variables...
// 1. stop repeating
session.stopRepeating()
// 2. submit repeating request to cancel any ongoing focus?
val request1 = createBaseCaptureRequest(device, outputs)
request1.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO)
request1.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO)
request1.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START)
session.setRepeatingRequest(request1.build(), null, null)
// 3. capture one request to start the trigger?
val request2 = createBaseCaptureRequest(device, outputs)
request2.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO)
request2.set(CaptureRequest.CONTROL_AF_REGIONS, arrayOf(meteringRectangle))
request2.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START)
// this waits until onCaptureCompleted, coroutine helper func!
session.capture(request2.build(), false)
// 4. stop repeating again?
session.stopRepeating()
// 5. set it to idle
val request3 = createBaseCaptureRequest(device, outputs)
request3.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO)
request3.set(CaptureRequest.CONTROL_AF_REGIONS, arrayOf(meteringRectangle))
request3.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE)
session.setRepeatingRequest(request3.build(), null, null)
coroutineScope {
launch {
delay(FOCUS_RESET_TIMEOUT)
Log.i(TAG, "Resetting focus to auto-focus...")
// 6. stop repeating again?
session.stopRepeating()
// 7. set new repeating request without any AF options to go back
val request4 = createBaseCaptureRequest(device, outputs)
session.setRepeatingRequest(request4.build(), null, null)
}
}
}
As you might've noticed, I'm trying to do this without introducing a lot of callbacks as those are hard to follow - I'm trying to use Kotlin coroutines/suspend functions to make this as simple as possible, and possibly also cancelable.
Source code:
For some reason, it does auto-focus to the top of the screen, but not to the bottom of the screen. I tried to hardcode the point to eliminate my error:
val activeArea = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)
// this should be the "bottom/center" point of the preview view,
// as camera sensor orientation is landscape
val point = Point(activeArea.width(), activeArea.centerY())
val meteringRectangle = MeteringRectangle(point,
DEFAULT_METERING_SIZE,
MeteringRectangle.METERING_WEIGHT_MAX - 1)
Is there any resource available for reliably focusing to a specific point of interest, without dropping too many preview frames? I simply can't get it to work now.