Add OnCameraBoundListener and support for landscape orientation to CameraXPreviewHelper

PiperOrigin-RevId: 572054649
This commit is contained in:
MediaPipe Team 2023-10-09 15:19:26 -07:00 committed by Copybara-Service
parent 3dd6480705
commit 3adc068e97

View File

@ -59,6 +59,14 @@ import javax.microedition.khronos.egl.EGLSurface;
* <p>{@link CameraX} connects to the camera and provides video frames. * <p>{@link CameraX} connects to the camera and provides video frames.
*/ */
public class CameraXPreviewHelper extends CameraHelper { public class CameraXPreviewHelper extends CameraHelper {
/** Listener invoked when the camera instance is available. */
public interface OnCameraBoundListener {
/**
* Called after CameraX has been bound to the lifecycle and the camera instance is available.
*/
public void onCameraBound(Camera camera);
}
/** /**
* Provides an Executor that wraps a single-threaded Handler. * Provides an Executor that wraps a single-threaded Handler.
* *
@ -130,6 +138,10 @@ public class CameraXPreviewHelper extends CameraHelper {
// the source is CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN. // the source is CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN.
private int cameraTimestampSource = CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN; private int cameraTimestampSource = CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
@Nullable private OnCameraBoundListener onCameraBoundListener = null;
private boolean isLandscapeOrientation = false;
/** /**
* Initializes the camera and sets it up for accessing frames, using the default 1280 * 720 * Initializes the camera and sets it up for accessing frames, using the default 1280 * 720
* preview size. * preview size.
@ -211,7 +223,7 @@ public class CameraXPreviewHelper extends CameraHelper {
* @param targetSize a predefined constant {@link #TARGET_SIZE}. If set to {@code null}, the * @param targetSize a predefined constant {@link #TARGET_SIZE}. If set to {@code null}, the
* helper will default to 1280 * 720. * helper will default to 1280 * 720.
*/ */
private void startCamera( public void startCamera(
Context context, Context context,
LifecycleOwner lifecycleOwner, LifecycleOwner lifecycleOwner,
CameraFacing cameraFacing, CameraFacing cameraFacing,
@ -237,9 +249,11 @@ public class CameraXPreviewHelper extends CameraHelper {
// (https://developer.android.com/training/camerax/configuration#specify-resolution): // (https://developer.android.com/training/camerax/configuration#specify-resolution):
// "Express the resolution Size in the coordinate frame after rotating the supported sizes by // "Express the resolution Size in the coordinate frame after rotating the supported sizes by
// the target rotation." // the target rotation."
// Since we only support portrait orientation, we unconditionally transpose width and height. // Transpose width and height if using portrait orientation.
Size rotatedSize = Size rotatedSize =
new Size(/* width= */ targetSize.getHeight(), /* height= */ targetSize.getWidth()); isLandscapeOrientation
? new Size(/* width= */ targetSize.getWidth(), /* height= */ targetSize.getHeight())
: new Size(/* width= */ targetSize.getHeight(), /* height= */ targetSize.getWidth());
cameraProviderFuture.addListener( cameraProviderFuture.addListener(
() -> { () -> {
@ -325,15 +339,22 @@ public class CameraXPreviewHelper extends CameraHelper {
cameraProvider.unbindAll(); cameraProvider.unbindAll();
// Bind use case(s) to camera. // Bind use case(s) to camera.
final Camera boundCamera;
if (imageCaptureBuilder != null) { if (imageCaptureBuilder != null) {
imageCapture = imageCaptureBuilder.build(); imageCapture = imageCaptureBuilder.build();
camera = boundCamera =
cameraProvider.bindToLifecycle( cameraProvider.bindToLifecycle(
lifecycleOwner, cameraSelector, preview, imageCapture); lifecycleOwner, cameraSelector, preview, imageCapture);
imageCaptureExecutorService = Executors.newSingleThreadExecutor(); imageCaptureExecutorService = Executors.newSingleThreadExecutor();
isImageCaptureEnabled = true; isImageCaptureEnabled = true;
} else { } else {
camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview); boundCamera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview);
}
CameraXPreviewHelper.this.camera = boundCamera;
OnCameraBoundListener listener = onCameraBoundListener;
if (listener != null) {
ContextCompat.getMainExecutor(context)
.execute(() -> listener.onCameraBound(boundCamera));
} }
}, },
mainThreadExecutor); mainThreadExecutor);
@ -462,6 +483,26 @@ public class CameraXPreviewHelper extends CameraHelper {
return frameSize; return frameSize;
} }
/**
* Sets whether the device is in landscape orientation.
*
* <p>Must be called before {@link #startCamera}. Portrait orientation is assumed by default.
*/
public void setLandscapeOrientation(boolean landscapeOrientation) {
this.isLandscapeOrientation = landscapeOrientation;
}
/**
* Sets a listener that will be invoked when CameraX is bound.
*
* <p>The listener will be invoked on the main thread after the next call to {@link #startCamera}.
* The {@link Camera} instance can be used to get camera info and control the camera (e.g. zoom
* level).
*/
public void setOnCameraBoundListener(@Nullable OnCameraBoundListener listener) {
this.onCameraBoundListener = listener;
}
private void updateCameraCharacteristics() { private void updateCameraCharacteristics() {
if (cameraCharacteristics != null) { if (cameraCharacteristics != null) {
// Queries camera timestamp source. It should be one of REALTIME or UNKNOWN // Queries camera timestamp source. It should be one of REALTIME or UNKNOWN