Search code examples
javaandroidandroid-camera2

Camera zoom setting using Camera2 API


I'm trying to use the new Camera2 API to access camera setting and apply a zoom. In old deprecated Camera API, the code was like follows:

Camera.Parameters parameters = mCamera.getParameters();
parameters.setZoom(zoomValue);
mCamera.setParameters(parameters);

How can we achieve the same, considering that CameraManager is used to open the camera?

CameraManager.openCamera(cameraId, stateCallback, backgroundHandler);

Solution

  • Use the next code. Call setZoom with your target CaptureRequest.Builder, so the preview or picture tacking builder whenever is needed.

    Use maxZoom to get the threshold at which your UI should compute the zoom range. The zoom range will be always between DEFAULT_ZOOM_FACTOR and maxZoom.

    After calling setZoom, to make the new zoom active you still need to send it to the current CameraCaptureSession with a Repeating Request.

    Snippet to compute a new zoom factor:

    public final class Zoom
    {
        private static final float DEFAULT_ZOOM_FACTOR = 1.0f;
    
        @NonNull
        private final Rect mCropRegion = new Rect();
    
        public final float maxZoom;
    
        @Nullable
        private final Rect mSensorSize;
    
        public final boolean hasSupport;
    
        public Zoom(@NonNull final CameraCharacteristics characteristics)
        {
            this.mSensorSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
    
            if (this.mSensorSize == null)
            {
                this.maxZoom = Zoom.DEFAULT_ZOOM_FACTOR;
                this.hasSupport = false;
                return;
            }
    
            final Float value = characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
    
            this.maxZoom = ((value == null) || (value < Zoom.DEFAULT_ZOOM_FACTOR))
                    ? Zoom.DEFAULT_ZOOM_FACTOR
                    : value;
    
            this.hasSupport = (Float.compare(this.maxZoom, Zoom.DEFAULT_ZOOM_FACTOR) > 0);
        }
    
        public void setZoom(@NonNull final CaptureRequest.Builder builder, final float zoom)
        {
            if (this.hasSupport == false)
            {
                return;
            }
    
            final float newZoom = MathUtils.clamp(zoom, Zoom.DEFAULT_ZOOM_FACTOR, this.maxZoom);
    
            final int centerX = this.mSensorSize.width() / 2;
            final int centerY = this.mSensorSize.height() / 2;
            final int deltaX  = (int)((0.5f * this.mSensorSize.width()) / newZoom);
            final int deltaY  = (int)((0.5f * this.mSensorSize.height()) / newZoom);
    
            this.mCropRegion.set(centerX - deltaX,
                    centerY - deltaY,
                    centerX + deltaX,
                    centerY + deltaY);
    
            builder.set(CaptureRequest.SCALER_CROP_REGION, this.mCropRegion);
        }
    }
    

    Snippet to apply the new computed zoom:

    yourCameraSession.setRepeatingRequest(builder.build(), yourPreviewOrCaptureSessionCallback, yourCameraThreadHandler);