diff --git a/api/current.txt b/api/current.txt index 5cef398a8a81a..46a4741080932 100644 --- a/api/current.txt +++ b/api/current.txt @@ -17036,6 +17036,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PARTIAL_RESULT_COUNT; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PIPELINE_MAX_DEPTH; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; + field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_ROTATE_AND_CROP_MODES; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_CROPPING_TYPE; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_MANDATORY_STREAM_COMBINATIONS; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_STREAM_CONFIGURATION_MAP; @@ -17313,6 +17314,11 @@ package android.hardware.camera2 { field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7 field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0 field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1 + field public static final int SCALER_ROTATE_AND_CROP_180 = 2; // 0x2 + field public static final int SCALER_ROTATE_AND_CROP_270 = 3; // 0x3 + field public static final int SCALER_ROTATE_AND_CROP_90 = 1; // 0x1 + field public static final int SCALER_ROTATE_AND_CROP_AUTO = 4; // 0x4 + field public static final int SCALER_ROTATE_AND_CROP_NONE = 0; // 0x0 field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR = 3; // 0x3 field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG = 2; // 0x2 field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG = 1; // 0x1 @@ -17434,6 +17440,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CaptureRequest.Key NOISE_REDUCTION_MODE; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key REPROCESS_EFFECTIVE_EXPOSURE_FACTOR; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key SCALER_CROP_REGION; + field @NonNull public static final android.hardware.camera2.CaptureRequest.Key SCALER_ROTATE_AND_CROP; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key SENSOR_EXPOSURE_TIME; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key SENSOR_FRAME_DURATION; field @NonNull public static final android.hardware.camera2.CaptureRequest.Key SENSOR_SENSITIVITY; @@ -17530,6 +17537,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CaptureResult.Key REPROCESS_EFFECTIVE_EXPOSURE_FACTOR; field @NonNull public static final android.hardware.camera2.CaptureResult.Key REQUEST_PIPELINE_DEPTH; field @NonNull public static final android.hardware.camera2.CaptureResult.Key SCALER_CROP_REGION; + field @NonNull public static final android.hardware.camera2.CaptureResult.Key SCALER_ROTATE_AND_CROP; field @NonNull public static final android.hardware.camera2.CaptureResult.Key SENSOR_DYNAMIC_BLACK_LEVEL; field @NonNull public static final android.hardware.camera2.CaptureResult.Key SENSOR_DYNAMIC_WHITE_LEVEL; field @NonNull public static final android.hardware.camera2.CaptureResult.Key SENSOR_EXPOSURE_TIME; diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index a45648f060937..160505aa6d17d 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -2848,6 +2848,23 @@ public final class CameraCharacteristics extends CameraMetadata SCALER_MANDATORY_STREAM_COMBINATIONS = new Key("android.scaler.mandatoryStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class); + /** + *

List of rotate-and-crop modes for {@link CaptureRequest#SCALER_ROTATE_AND_CROP android.scaler.rotateAndCrop} that are supported by this camera device.

+ *

This entry lists the valid modes for {@link CaptureRequest#SCALER_ROTATE_AND_CROP android.scaler.rotateAndCrop} for this camera device.

+ *

Starting with API level 30, all devices will list at least ROTATE_AND_CROP_NONE. + * Devices with support for rotate-and-crop will additionally list at least + * ROTATE_AND_CROP_AUTO and ROTATE_AND_CROP_90.

+ *

Range of valid values:
+ * Any value listed in {@link CaptureRequest#SCALER_ROTATE_AND_CROP android.scaler.rotateAndCrop}

+ *

Optional - The value for this key may be {@code null} on some devices.

+ * + * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + @PublicKey + @NonNull + public static final Key SCALER_AVAILABLE_ROTATE_AND_CROP_MODES = + new Key("android.scaler.availableRotateAndCropModes", int[].class); + /** *

The area of the image sensor which corresponds to active pixels after any geometric * distortion correction has been applied.

diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index ec13a36ca1d28..b28958abed8a3 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -2714,6 +2714,56 @@ public abstract class CameraMetadata { */ public static final int NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG = 4; + // + // Enumeration values for CaptureRequest#SCALER_ROTATE_AND_CROP + // + + /** + *

No rotate and crop is applied. Processed outputs are in the sensor orientation.

+ * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + public static final int SCALER_ROTATE_AND_CROP_NONE = 0; + + /** + *

Processed images are rotated by 90 degrees clockwise, and then cropped + * to the original aspect ratio.

+ * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + public static final int SCALER_ROTATE_AND_CROP_90 = 1; + + /** + *

Processed images are rotated by 180 degrees. Since the aspect ratio does not + * change, no cropping is performed.

+ * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + public static final int SCALER_ROTATE_AND_CROP_180 = 2; + + /** + *

Processed images are rotated by 270 degrees clockwise, and then cropped + * to the original aspect ratio.

+ * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + public static final int SCALER_ROTATE_AND_CROP_270 = 3; + + /** + *

The camera API automatically selects the best concrete value for + * rotate-and-crop based on the application's support for resizability and the current + * multi-window mode.

+ *

If the application does not support resizing but the display mode for its main + * Activity is not in a typical orientation, the camera API will set ROTATE_AND_CROP_90 + * or some other supported rotation value, depending on device configuration, + * to ensure preview and captured images are correctly shown to the user. Otherwise, + * ROTATE_AND_CROP_NONE will be selected.

+ *

When a value other than NONE is selected, several metadata fields will also be parsed + * differently to ensure that coordinates are correctly handled for features like drawing + * face detection boxes or passing in tap-to-focus coordinates. The camera API will + * convert positions in the active array coordinate system to/from the cropped-and-rotated + * coordinate system to make the operation transparent for applications.

+ *

No coordinate mapping will be done when the application selects a non-AUTO mode.

+ * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + public static final int SCALER_ROTATE_AND_CROP_AUTO = 4; + // // Enumeration values for CaptureRequest#SENSOR_TEST_PATTERN_MODE // diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index b9af8f517985f..30fbde255201f 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -2844,6 +2844,99 @@ public final class CaptureRequest extends CameraMetadata> public static final Key SCALER_CROP_REGION = new Key("android.scaler.cropRegion", android.graphics.Rect.class); + /** + *

Whether a rotation-and-crop operation is applied to processed + * outputs from the camera.

+ *

This control is primarily intended to help camera applications with no support for + * multi-window modes to work correctly on devices where multi-window scenarios are + * unavoidable, such as foldables or other devices with variable display geometry or more + * free-form window placement (such as laptops, which often place portrait-orientation apps + * in landscape with pillarboxing).

+ *

If supported, the default value is ROTATE_AND_CROP_AUTO, which allows the camera API + * to enable backwards-compatibility support for applications that do not support resizing + * / multi-window modes, when the device is in fact in a multi-window mode (such as inset + * portrait on laptops, or on a foldable device in some fold states). In addition, + * ROTATE_AND_CROP_NONE and ROTATE_AND_CROP_90 will always be available if this control + * is supported by the device. If not supported, devices API level 30 or higher will always + * list only ROTATE_AND_CROP_NONE.

+ *

When CROP_AUTO is in use, and the camera API activates backward-compatibility mode, + * several metadata fields will also be parsed differently to ensure that coordinates are + * correctly handled for features like drawing face detection boxes or passing in + * tap-to-focus coordinates. The camera API will convert positions in the active array + * coordinate system to/from the cropped-and-rotated coordinate system to make the + * operation transparent for applications. The following controls are affected:

+ *
    + *
  • {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}
  • + *
  • {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}
  • + *
  • {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}
  • + *
  • {@link CaptureResult#STATISTICS_FACES android.statistics.faces}
  • + *
+ *

Capture results will contain the actual value selected by the API; + * ROTATE_AND_CROP_AUTO will never be seen in a capture result.

+ *

Applications can also select their preferred cropping mode, either to opt out of the + * backwards-compatibility treatment, or to use the cropping feature themselves as needed. + * In this case, no coordinate translation will be done automatically, and all controls + * will continue to use the normal active array coordinates.

+ *

Cropping and rotating is done after the application of digital zoom (via either + * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}), but before each individual + * output is further cropped and scaled. It only affects processed outputs such as + * YUV, PRIVATE, and JPEG. It has no effect on RAW outputs.

+ *

When CROP_90 or CROP_270 are selected, there is a significant loss to the field of + * view. For example, with a 4:3 aspect ratio output of 1600x1200, CROP_90 will still + * produce 1600x1200 output, but these buffers are cropped from a vertical 3:4 slice at the + * center of the 4:3 area, then rotated to be 4:3, and then upscaled to 1600x1200. Only + * 56.25% of the original FOV is still visible. In general, for an aspect ratio of w:h, + * the crop and rotate operation leaves (h/w)^2 of the field of view visible. For 16:9, + * this is ~31.6%.

+ *

As a visual example, the figure below shows the effect of ROTATE_AND_CROP_90 on the + * outputs for the following parameters:

+ *
    + *
  • Sensor active array: 2000x1500
  • + *
  • Crop region: top-left: (500, 375), size: (1000, 750) (4:3 aspect ratio)
  • + *
  • Output streams: YUV 640x480 and YUV 1280x720
  • + *
  • ROTATE_AND_CROP_90
  • + *
+ *

Effect of ROTATE_AND_CROP_90

+ *

With these settings, the regions of the active array covered by the output streams are:

+ *
    + *
  • 640x480 stream crop: top-left: (219, 375), size: (562, 750)
  • + *
  • 1280x720 stream crop: top-left: (289, 375), size: (422, 750)
  • + *
+ *

Since the buffers are rotated, the buffers as seen by the application are:

+ *
    + *
  • 640x480 stream: top-left: (781, 375) on active array, size: (640, 480), downscaled 1.17x from sensor pixels
  • + *
  • 1280x720 stream: top-left: (711, 375) on active array, size: (1280, 720), upscaled 1.71x from sensor pixels
  • + *
+ *

Possible values: + *

    + *
  • {@link #SCALER_ROTATE_AND_CROP_NONE NONE}
  • + *
  • {@link #SCALER_ROTATE_AND_CROP_90 90}
  • + *
  • {@link #SCALER_ROTATE_AND_CROP_180 180}
  • + *
  • {@link #SCALER_ROTATE_AND_CROP_270 270}
  • + *
  • {@link #SCALER_ROTATE_AND_CROP_AUTO AUTO}
  • + *

+ *

Available values for this device:
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES android.scaler.availableRotateAndCropModes}

+ *

Optional - The value for this key may be {@code null} on some devices.

+ * + * @see CaptureRequest#CONTROL_AE_REGIONS + * @see CaptureRequest#CONTROL_AF_REGIONS + * @see CaptureRequest#CONTROL_AWB_REGIONS + * @see CaptureRequest#CONTROL_ZOOM_RATIO + * @see CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES + * @see CaptureRequest#SCALER_CROP_REGION + * @see CaptureResult#STATISTICS_FACES + * @see #SCALER_ROTATE_AND_CROP_NONE + * @see #SCALER_ROTATE_AND_CROP_90 + * @see #SCALER_ROTATE_AND_CROP_180 + * @see #SCALER_ROTATE_AND_CROP_270 + * @see #SCALER_ROTATE_AND_CROP_AUTO + */ + @PublicKey + @NonNull + public static final Key SCALER_ROTATE_AND_CROP = + new Key("android.scaler.rotateAndCrop", int.class); + /** *

Duration each pixel is exposed to * light.

diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 9b305b32b61d8..26f29e38d37e8 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -3483,6 +3483,99 @@ public class CaptureResult extends CameraMetadata> { public static final Key SCALER_CROP_REGION = new Key("android.scaler.cropRegion", android.graphics.Rect.class); + /** + *

Whether a rotation-and-crop operation is applied to processed + * outputs from the camera.

+ *

This control is primarily intended to help camera applications with no support for + * multi-window modes to work correctly on devices where multi-window scenarios are + * unavoidable, such as foldables or other devices with variable display geometry or more + * free-form window placement (such as laptops, which often place portrait-orientation apps + * in landscape with pillarboxing).

+ *

If supported, the default value is ROTATE_AND_CROP_AUTO, which allows the camera API + * to enable backwards-compatibility support for applications that do not support resizing + * / multi-window modes, when the device is in fact in a multi-window mode (such as inset + * portrait on laptops, or on a foldable device in some fold states). In addition, + * ROTATE_AND_CROP_NONE and ROTATE_AND_CROP_90 will always be available if this control + * is supported by the device. If not supported, devices API level 30 or higher will always + * list only ROTATE_AND_CROP_NONE.

+ *

When CROP_AUTO is in use, and the camera API activates backward-compatibility mode, + * several metadata fields will also be parsed differently to ensure that coordinates are + * correctly handled for features like drawing face detection boxes or passing in + * tap-to-focus coordinates. The camera API will convert positions in the active array + * coordinate system to/from the cropped-and-rotated coordinate system to make the + * operation transparent for applications. The following controls are affected:

+ *
    + *
  • {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}
  • + *
  • {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}
  • + *
  • {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}
  • + *
  • {@link CaptureResult#STATISTICS_FACES android.statistics.faces}
  • + *
+ *

Capture results will contain the actual value selected by the API; + * ROTATE_AND_CROP_AUTO will never be seen in a capture result.

+ *

Applications can also select their preferred cropping mode, either to opt out of the + * backwards-compatibility treatment, or to use the cropping feature themselves as needed. + * In this case, no coordinate translation will be done automatically, and all controls + * will continue to use the normal active array coordinates.

+ *

Cropping and rotating is done after the application of digital zoom (via either + * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}), but before each individual + * output is further cropped and scaled. It only affects processed outputs such as + * YUV, PRIVATE, and JPEG. It has no effect on RAW outputs.

+ *

When CROP_90 or CROP_270 are selected, there is a significant loss to the field of + * view. For example, with a 4:3 aspect ratio output of 1600x1200, CROP_90 will still + * produce 1600x1200 output, but these buffers are cropped from a vertical 3:4 slice at the + * center of the 4:3 area, then rotated to be 4:3, and then upscaled to 1600x1200. Only + * 56.25% of the original FOV is still visible. In general, for an aspect ratio of w:h, + * the crop and rotate operation leaves (h/w)^2 of the field of view visible. For 16:9, + * this is ~31.6%.

+ *

As a visual example, the figure below shows the effect of ROTATE_AND_CROP_90 on the + * outputs for the following parameters:

+ *
    + *
  • Sensor active array: 2000x1500
  • + *
  • Crop region: top-left: (500, 375), size: (1000, 750) (4:3 aspect ratio)
  • + *
  • Output streams: YUV 640x480 and YUV 1280x720
  • + *
  • ROTATE_AND_CROP_90
  • + *
+ *

Effect of ROTATE_AND_CROP_90

+ *

With these settings, the regions of the active array covered by the output streams are:

+ *
    + *
  • 640x480 stream crop: top-left: (219, 375), size: (562, 750)
  • + *
  • 1280x720 stream crop: top-left: (289, 375), size: (422, 750)
  • + *
+ *

Since the buffers are rotated, the buffers as seen by the application are:

+ *
    + *
  • 640x480 stream: top-left: (781, 375) on active array, size: (640, 480), downscaled 1.17x from sensor pixels
  • + *
  • 1280x720 stream: top-left: (711, 375) on active array, size: (1280, 720), upscaled 1.71x from sensor pixels
  • + *
+ *

Possible values: + *

    + *
  • {@link #SCALER_ROTATE_AND_CROP_NONE NONE}
  • + *
  • {@link #SCALER_ROTATE_AND_CROP_90 90}
  • + *
  • {@link #SCALER_ROTATE_AND_CROP_180 180}
  • + *
  • {@link #SCALER_ROTATE_AND_CROP_270 270}
  • + *
  • {@link #SCALER_ROTATE_AND_CROP_AUTO AUTO}
  • + *

+ *

Available values for this device:
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES android.scaler.availableRotateAndCropModes}

+ *

Optional - The value for this key may be {@code null} on some devices.

+ * + * @see CaptureRequest#CONTROL_AE_REGIONS + * @see CaptureRequest#CONTROL_AF_REGIONS + * @see CaptureRequest#CONTROL_AWB_REGIONS + * @see CaptureRequest#CONTROL_ZOOM_RATIO + * @see CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES + * @see CaptureRequest#SCALER_CROP_REGION + * @see CaptureResult#STATISTICS_FACES + * @see #SCALER_ROTATE_AND_CROP_NONE + * @see #SCALER_ROTATE_AND_CROP_90 + * @see #SCALER_ROTATE_AND_CROP_180 + * @see #SCALER_ROTATE_AND_CROP_270 + * @see #SCALER_ROTATE_AND_CROP_AUTO + */ + @PublicKey + @NonNull + public static final Key SCALER_ROTATE_AND_CROP = + new Key("android.scaler.rotateAndCrop", int.class); + /** *

Duration each pixel is exposed to * light.

diff --git a/docs/html/reference/images/camera2/metadata/android.scaler.rotateAndCrop/crop-region-rotate-90-43-ratio.png b/docs/html/reference/images/camera2/metadata/android.scaler.rotateAndCrop/crop-region-rotate-90-43-ratio.png new file mode 100644 index 0000000000000..2633996521b5d Binary files /dev/null and b/docs/html/reference/images/camera2/metadata/android.scaler.rotateAndCrop/crop-region-rotate-90-43-ratio.png differ