Cropped RAW stream when the client chooses to crop the field of view.
+ * Certain types of image sensors can run in binned modes in order to improve signal to
+ * noise ratio while capturing frames. However, at certain zoom levels and / or when
+ * other scene conditions are deemed fit, the camera sub-system may choose to un-bin and
+ * remosaic the sensor's output. This results in a RAW frame which is cropped in field
+ * of view and yet has the same number of pixels as full field of view RAW, thereby
+ * improving image detail.
+ * The resultant field of view of the RAW stream will be greater than or equal to
+ * croppable non-RAW streams. The effective crop region for this RAW stream will be
+ * reflected in the CaptureResult key {@link CaptureResult#SCALER_RAW_CROP_REGION android.scaler.rawCropRegion}.
+ * If this stream use case is set on a non-RAW stream, i.e. not one of :
+ * session configuration is not guaranteed to succeed.
+ * This stream use case may not be supported on some devices.
+ *
+ * @see CaptureResult#SCALER_RAW_CROP_REGION
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ */
+ public static final int SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW = 0x6;
+
/**
* Vendor defined use cases. These depend on the vendor implementation.
* @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 43bfdcc8d8986..3d8300933054d 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -3086,9 +3086,9 @@ public final class CaptureRequest extends CameraMetadata>
* Output streams use this rectangle to produce their output, cropping to a smaller region
* if necessary to maintain the stream's aspect ratio, then scaling the sensor input to
* match the output's configured resolution.
- * The crop region is applied after the RAW to other color space (e.g. YUV)
- * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage, they are not
- * croppable. The crop region will be ignored by raw streams.
+ * The crop region is usually applied after the RAW to other color space (e.g. YUV)
+ * conversion. As a result RAW streams are not croppable unless supported by the
+ * camera device. See {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES android.scaler.availableStreamUseCases}#CROPPED_RAW for details.
* For non-raw streams, any additional per-stream cropping will be done to maximize the
* final pixel area of the stream.
* For example, if the crop region is set to a 4:3 aspect ratio, then 4:3 streams will use
@@ -3183,6 +3183,7 @@ public final class CaptureRequest extends CameraMetadata>
* @see CaptureRequest#CONTROL_ZOOM_RATIO
* @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
* @see CameraCharacteristics#SCALER_CROPPING_TYPE
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index fb52cc6a01963..dad7d3eb68423 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3748,9 +3748,9 @@ public class CaptureResult extends CameraMetadata> {
* Output streams use this rectangle to produce their output, cropping to a smaller region
* if necessary to maintain the stream's aspect ratio, then scaling the sensor input to
* match the output's configured resolution.
- * The crop region is applied after the RAW to other color space (e.g. YUV)
- * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage, they are not
- * croppable. The crop region will be ignored by raw streams.
+ * The crop region is usually applied after the RAW to other color space (e.g. YUV)
+ * conversion. As a result RAW streams are not croppable unless supported by the
+ * camera device. See {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES android.scaler.availableStreamUseCases}#CROPPED_RAW for details.
* For non-raw streams, any additional per-stream cropping will be done to maximize the
* final pixel area of the stream.
* For example, if the crop region is set to a 4:3 aspect ratio, then 4:3 streams will use
@@ -3845,6 +3845,7 @@ public class CaptureResult extends CameraMetadata> {
* @see CaptureRequest#CONTROL_ZOOM_RATIO
* @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
* @see CameraCharacteristics#SCALER_CROPPING_TYPE
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
@@ -3951,6 +3952,60 @@ public class CaptureResult extends CameraMetadata> {
public static final Key SCALER_ROTATE_AND_CROP =
new Key("android.scaler.rotateAndCrop", int.class);
+ /**
+ * The region of the sensor that corresponds to the RAW read out for this
+ * capture when the stream use case of a RAW stream is set to CROPPED_RAW.
+ * The coordinate system follows that of {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}.
+ * This CaptureResult key will be set when the corresponding CaptureRequest has a RAW target
+ * with stream use case set to
+ * {@link android.hardware.camera2.CameraMetadata#SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW },
+ * otherwise it will be {@code null}.
+ * The value of this key specifies the region of the sensor used for the RAW capture and can
+ * be used to calculate the corresponding field of view of RAW streams.
+ * This field of view will always be >= field of view for (processed) non-RAW streams for the
+ * capture. Note: The region specified may not necessarily be centered.
+ * For example: Assume a camera device has a pre correction active array size of
+ * {@code {0, 0, 1500, 2000}}. If the RAW_CROP_REGION is {@code {500, 375, 1500, 1125}}, that
+ * corresponds to a centered crop of 1/4th of the full field of view RAW stream.
+ * The metadata keys which describe properties of RAW frames:
+ *
+ * - {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}
+ * - {@link CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP android.statistics.lensShadingCorrectionMap}
+ * - {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}
+ * - {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}
+ * - {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
+ * - {@link CameraCharacteristics#LENS_DISTORTION android.lens.distortion}
+ * - {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
+ *
+ * should be interpreted in the effective after raw crop field-of-view coordinate system.
+ * In this coordinate system,
+ * {preCorrectionActiveArraySize.left, preCorrectionActiveArraySize.top} corresponds to the
+ * the top left corner of the cropped RAW frame and
+ * {preCorrectionActiveArraySize.right, preCorrectionActiveArraySize.bottom} corresponds to
+ * the bottom right corner. Client applications must use the values of the keys
+ * in the CaptureResult metadata if present.
+ * Crop regions (android.scaler.CropRegion), AE/AWB/AF regions and face coordinates still
+ * use the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate system as usual.
+ * Units: Pixel coordinates relative to
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} depending on distortion correction
+ * capability and mode
+ * Optional - The value for this key may be {@code null} on some devices.
+ *
+ * @see CameraCharacteristics#LENS_DISTORTION
+ * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
+ * @see CameraCharacteristics#LENS_POSE_ROTATION
+ * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
+ * @see CaptureResult#STATISTICS_LENS_SHADING_CORRECTION_MAP
+ */
+ @PublicKey
+ @NonNull
+ public static final Key SCALER_RAW_CROP_REGION =
+ new Key("android.scaler.rawCropRegion", android.graphics.Rect.class);
+
/**
* Duration each pixel is exposed to
* light.
@@ -5643,4 +5698,5 @@ public class CaptureResult extends CameraMetadata> {
+
}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 9a164743bc8d1..8d742b5a95f3d 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1461,6 +1461,23 @@ public class CameraMetadataNative implements Parcelable {
return ret;
}
+ private boolean isCroppedRawSupported() {
+ boolean ret = false;
+
+ long[] streamUseCases =
+ getBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES);
+ if (streamUseCases == null) {
+ return false;
+ }
+ for (long useCase : streamUseCases) {
+ if (useCase == CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW) {
+ return true;
+ }
+ }
+
+ return ret;
+ }
+
private MandatoryStreamCombination[] getMandatoryStreamCombinationsHelper(
int mandatoryStreamsType) {
int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
@@ -1472,7 +1489,8 @@ public class CameraMetadataNative implements Parcelable {
int hwLevel = getBase(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
MandatoryStreamCombination.Builder build = new MandatoryStreamCombination.Builder(
mCameraId, hwLevel, mDisplaySize, caps, getStreamConfigurationMap(),
- getStreamConfigurationMapMaximumResolution(), isPreviewStabilizationSupported());
+ getStreamConfigurationMapMaximumResolution(), isPreviewStabilizationSupported(),
+ isCroppedRawSupported());
List combs = null;
switch (mandatoryStreamsType) {
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 0905e1b9f5b30..6f77d12cc4630 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -375,6 +375,8 @@ public final class MandatoryStreamCombination {
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
private static final long STREAM_USE_CASE_VIDEO_CALL =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+ private static final long STREAM_USE_CASE_CROPPED_RAW =
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW;
/**
* Create a new {@link MandatoryStreamCombination}.
@@ -1262,6 +1264,86 @@ public final class MandatoryStreamCombination {
"Preview, in-application image processing, and YUV still image capture"),
};
+ private static StreamCombinationTemplate sCroppedRawStreamUseCaseCombinations[] = {
+ // Single stream combination
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "Cropped RAW still image capture without preview"),
+
+ // 2 Stream combinations
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "Cropped RAW still image capture with preview"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "In-app image processing with cropped RAW still image capture"),
+
+ // 3 stream combinations
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "Preview with YUV and RAW still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "In-app image processing with YUV and RAW still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "Preview with JPEG and RAW still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "In-app image processing with JPEG and RAW still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_RECORD),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "Preview with video recording and RAW snapshot"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "Preview with in-app image processing and RAW still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_CROPPED_RAW)},
+ "Two input in-app processing and RAW still image capture"),
+ };
+
private static StreamCombinationTemplate sPreviewStabilizedStreamCombinations[] = {
// 1 stream combinations
new StreamCombinationTemplate(new StreamTemplate [] {
@@ -1317,7 +1399,8 @@ public final class MandatoryStreamCombination {
private StreamConfigurationMap mStreamConfigMap;
private StreamConfigurationMap mStreamConfigMapMaximumResolution;
private boolean mIsHiddenPhysicalCamera;
- private boolean mIsPreviewStabilizationSupported;
+ private boolean mIsPreviewStabilizationSupported = false;
+ private boolean mIsCroppedRawSupported = false;
private final Size kPreviewSizeBound = new Size(1920, 1088);
@@ -1331,10 +1414,13 @@ public final class MandatoryStreamCombination {
* @param sm The camera device stream configuration map.
* @param smMaxResolution The camera device stream configuration map when it runs in max
* resolution mode.
+ * @param previewStabilization The camera device supports preview stabilization.
+ * @param croppedRaw The camera device supports the cropped raw stream use case.
*/
public Builder(int cameraId, int hwLevel, @NonNull Size displaySize,
@NonNull List capabilities, @NonNull StreamConfigurationMap sm,
- StreamConfigurationMap smMaxResolution, boolean previewStabilization) {
+ StreamConfigurationMap smMaxResolution, boolean previewStabilization,
+ boolean isCroppedRawSupported) {
mCameraId = cameraId;
mDisplaySize = displaySize;
mCapabilities = capabilities;
@@ -1344,6 +1430,7 @@ public final class MandatoryStreamCombination {
mIsHiddenPhysicalCamera =
CameraManager.isHiddenPhysicalCamera(Integer.toString(mCameraId));
mIsPreviewStabilizationSupported = previewStabilization;
+ mIsCroppedRawSupported = isCroppedRawSupported;
}
private @Nullable List
@@ -1483,10 +1570,23 @@ public final class MandatoryStreamCombination {
Log.e(TAG, "Available size enumeration failed!");
return null;
}
+ ArrayList availableTemplates =
+ new ArrayList ();
+ availableTemplates.addAll(Arrays.asList(sStreamUseCaseCombinations));
ArrayList availableStreamCombinations = new ArrayList<>();
- availableStreamCombinations.ensureCapacity(sStreamUseCaseCombinations.length);
- for (StreamCombinationTemplate combTemplate : sStreamUseCaseCombinations) {
+ int capacity = sStreamUseCaseCombinations.length;
+ if (mIsCroppedRawSupported) {
+ capacity += sCroppedRawStreamUseCaseCombinations.length;
+ availableStreamCombinations.ensureCapacity(capacity);
+ availableTemplates.addAll(Arrays.asList(sCroppedRawStreamUseCaseCombinations));
+ }
+ else {
+ availableStreamCombinations.ensureCapacity(capacity);
+ }
+
+
+ for (StreamCombinationTemplate combTemplate : availableTemplates) {
ArrayList streamsInfo =
new ArrayList();
streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
@@ -2012,6 +2112,7 @@ public final class MandatoryStreamCombination {
private @Nullable HashMap, List>
enumerateAvailableSizes() {
final int[] formats = {
+ ImageFormat.RAW_SENSOR,
ImageFormat.PRIVATE,
ImageFormat.YUV_420_888,
ImageFormat.JPEG,
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 65df5d1d43597..8b7c5ec57516d 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -289,7 +289,8 @@ public final class OutputConfiguration implements Parcelable {
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE,
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD,
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL,
- CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL})
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW})
public @interface StreamUseCase {};
/**
@@ -998,7 +999,7 @@ public final class OutputConfiguration implements Parcelable {
*/
public void setStreamUseCase(@StreamUseCase long streamUseCase) {
// Verify that the value is in range
- long maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+ long maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW;
if (streamUseCase > maxUseCaseValue &&
streamUseCase < CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) {
throw new IllegalArgumentException("Not a valid stream use case value " +