diff options
21 files changed, 1514 insertions, 828 deletions
diff --git a/api/current.txt b/api/current.txt index 2358291..b52b2e1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11859,16 +11859,8 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_MAX_NUM_OUTPUT_STREAMS; field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PARTIAL_RESULT_COUNT; field public static final android.hardware.camera2.CameraMetadata.Key REQUEST_PIPELINE_MAX_DEPTH; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_FORMATS; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_MIN_DURATIONS; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_JPEG_SIZES; field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_MIN_FRAME_DURATIONS; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_PROCESSED_SIZES; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STALL_DURATIONS; - field public static final android.hardware.camera2.CameraMetadata.Key SCALER_AVAILABLE_STREAM_CONFIGURATIONS; + field public static final android.hardware.camera2.CameraMetadata.Key SCALER_STREAM_CONFIGURATION_MAP; field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES; field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BASE_GAIN_FACTOR; field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_BLACK_LEVEL_PATTERN; @@ -12078,8 +12070,6 @@ package android.hardware.camera2 { field public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // 0x5 field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 2; // 0x2 field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4 - field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1; // 0x1 - field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 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 @@ -12360,6 +12350,22 @@ package android.hardware.camera2 { method public final int getWidth(); } + public final class TonemapCurve { + method public void copyColorCurve(int, float[], int); + method public android.graphics.PointF getPoint(int, int); + method public int getPointCount(int); + field public static final int CHANNEL_BLUE = 2; // 0x2 + field public static final int CHANNEL_GREEN = 1; // 0x1 + field public static final int CHANNEL_RED = 0; // 0x0 + field public static final float LEVEL_BLACK = 0.0f; + field public static final float LEVEL_WHITE = 1.0f; + field public static final int POINT_SIZE = 2; // 0x2 + } + +} + +package android.hardware.camera2.params { + public final class StreamConfigurationMap { method public final int[] getOutputFormats(); method public long getOutputMinFrameDuration(int, android.util.Size); @@ -12373,18 +12379,6 @@ package android.hardware.camera2 { method public boolean isOutputSupportedFor(android.view.Surface); } - public final class TonemapCurve { - method public void copyColorCurve(int, float[], int); - method public android.graphics.PointF getPoint(int, int); - method public int getPointCount(int); - field public static final int CHANNEL_BLUE = 2; // 0x2 - field public static final int CHANNEL_GREEN = 1; // 0x1 - field public static final int CHANNEL_RED = 0; // 0x0 - field public static final float LEVEL_BLACK = 0.0f; - field public static final float LEVEL_WHITE = 1.0f; - field public static final int POINT_SIZE = 2; // 0x2 - } - } package android.hardware.display { diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 5f2af8c..b1c1005 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -307,16 +307,14 @@ public final class CameraCharacteristics extends CameraMetadata { * <li>The sizes will be sorted by increasing pixel area (width x height). * If several resolutions have the same area, they will be sorted by increasing width.</li> * <li>The aspect ratio of the largest thumbnail size will be same as the - * aspect ratio of largest JPEG output size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}. + * aspect ratio of largest JPEG output size in android.scaler.availableStreamConfigurations. * The largest size is defined as the size that has the largest pixel area * in a given size list.</li> - * <li>Each output JPEG size in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} will have at least + * <li>Each output JPEG size in android.scaler.availableStreamConfigurations will have at least * one corresponding size that has the same aspect ratio in availableThumbnailSizes, * and vice versa.</li> * <li>All non (0, 0) sizes will have non-zero widths and heights.</li> * </ul> - * - * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS */ public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES = new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class); @@ -445,8 +443,10 @@ public final class CameraCharacteristics extends CameraMetadata { * working at that point; DO NOT USE without careful * consideration of future support.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @deprecated * @hide */ + @Deprecated public static final Key<Byte> QUIRKS_USE_PARTIAL_RESULT = new Key<Byte>("android.quirks.usePartialResult", byte.class); @@ -461,8 +461,8 @@ public final class CameraCharacteristics extends CameraMetadata { * <p>This lists the upper bound of the number of output streams supported by * the camera device. Using more streams simultaneously may require more hardware and * CPU resources that will consume more power. The image format for a output stream can - * be any supported format provided by {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}. - * The formats defined in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} can be catergorized + * be any supported format provided by android.scaler.availableStreamConfigurations. + * The formats defined in android.scaler.availableStreamConfigurations can be catergorized * into the 3 stream types as below:</p> * <ul> * <li>Processed (but stalling): any non-RAW format with a stallDurations > 0. @@ -471,8 +471,6 @@ public final class CameraCharacteristics extends CameraMetadata { * <li>Processed (but not-stalling): any non-RAW format without a stall duration. * Typically ImageFormat#YUV_420_888, ImageFormat#NV21, ImageFormat#YV12.</li> * </ul> - * - * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS */ public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS = new Key<int[]>("android.request.maxNumOutputStreams", int[].class); @@ -483,14 +481,12 @@ public final class CameraCharacteristics extends CameraMetadata { * <p>When set to 0, it means no input stream is supported.</p> * <p>The image format for a input stream can be any supported * format provided by - * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP android.scaler.availableInputOutputFormatsMap}. When using an + * android.scaler.availableInputOutputFormatsMap. When using an * input stream, there must be at least one output stream * configured to to receive the reprocessed images.</p> * <p>For example, for Zero Shutter Lag (ZSL) still capture use case, the input * stream image format will be RAW_OPAQUE, the associated output stream image format * should be JPEG.</p> - * - * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP */ public static final Key<Integer> REQUEST_MAX_NUM_INPUT_STREAMS = new Key<Integer>("android.request.maxNumInputStreams", int.class); @@ -629,22 +625,26 @@ public final class CameraCharacteristics extends CameraMetadata { * camera device for output streams.</p> * <p>All camera devices will support JPEG and YUV_420_888 formats.</p> * <p>When set to YUV_420_888, application can access the YUV420 data directly.</p> + * @deprecated + * @hide */ + @Deprecated public static final Key<int[]> SCALER_AVAILABLE_FORMATS = new Key<int[]>("android.scaler.availableFormats", int[].class); /** * <p>The minimum frame duration that is supported - * for each resolution in {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES android.scaler.availableJpegSizes}.</p> + * for each resolution in android.scaler.availableJpegSizes.</p> * <p>This corresponds to the minimum steady-state frame duration when only * that JPEG stream is active and captured in a burst, with all * processing (typically in android.*.mode) set to FAST.</p> * <p>When multiple streams are configured, the minimum * frame duration will be >= max(individual stream min * durations)</p> - * - * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES + * @deprecated + * @hide */ + @Deprecated public static final Key<long[]> SCALER_AVAILABLE_JPEG_MIN_DURATIONS = new Key<long[]>("android.scaler.availableJpegMinDurations", long[].class); @@ -654,7 +654,10 @@ public final class CameraCharacteristics extends CameraMetadata { * sensor maximum resolution (defined by {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}).</p> * * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @deprecated + * @hide */ + @Deprecated public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES = new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class); @@ -669,16 +672,17 @@ public final class CameraCharacteristics extends CameraMetadata { /** * <p>For each available processed output size (defined in - * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES android.scaler.availableProcessedSizes}), this property lists the + * android.scaler.availableProcessedSizes), this property lists the * minimum supportable frame duration for that size.</p> * <p>This should correspond to the frame duration when only that processed * stream is active, with all processing (typically in android.*.mode) * set to FAST.</p> * <p>When multiple streams are configured, the minimum frame duration will * be >= max(individual stream min durations).</p> - * - * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES + * @deprecated + * @hide */ + @Deprecated public static final Key<long[]> SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS = new Key<long[]>("android.scaler.availableProcessedMinDurations", long[].class); @@ -696,7 +700,10 @@ public final class CameraCharacteristics extends CameraMetadata { * can provide.</p> * <p>Please reference the documentation for the image data destination to * check if it limits the maximum size for image data.</p> + * @deprecated + * @hide */ + @Deprecated public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES = new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class); @@ -746,13 +753,14 @@ public final class CameraCharacteristics extends CameraMetadata { * </table> * <p>For ZSL-capable camera devices, using the RAW_OPAQUE format * as either input or output will never hurt maximum frame rate (i.e. - * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} will not have RAW_OPAQUE).</p> + * StreamConfigurationMap#getOutputStallDuration(int,Size) + * for a <code>format =</code> RAW_OPAQUE is always 0).</p> * <p>Attempting to configure an input stream with output streams not * listed as available in this map is not valid.</p> - * <p>TODO: Add java type mapping for this property.</p> + * <p>TODO: typedef to ReprocessFormatMap</p> * * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS - * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS + * @hide */ public static final Key<int[]> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP = new Key<int[]>("android.scaler.availableInputOutputFormatsMap", int[].class); @@ -775,7 +783,7 @@ public final class CameraCharacteristics extends CameraMetadata { * check if it limits the maximum size for image data.</p> * <p>Not all output formats may be supported in a configuration with * an input stream of a particular format. For more details, see - * {@link CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP android.scaler.availableInputOutputFormatsMap}.</p> + * android.scaler.availableInputOutputFormatsMap.</p> * <p>The following table describes the minimum required output stream * configurations based on the hardware level * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p> @@ -844,13 +852,11 @@ public final class CameraCharacteristics extends CameraMetadata { * * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES - * @see CameraCharacteristics#SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE - * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT - * @see #SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT + * @hide */ - public static final Key<int[]> SCALER_AVAILABLE_STREAM_CONFIGURATIONS = - new Key<int[]>("android.scaler.availableStreamConfigurations", int[].class); + public static final Key<android.hardware.camera2.params.StreamConfiguration[]> SCALER_AVAILABLE_STREAM_CONFIGURATIONS = + new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.scaler.availableStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class); /** * <p>This lists the minimum frame duration for each @@ -863,14 +869,16 @@ public final class CameraCharacteristics extends CameraMetadata { * <p>The minimum frame duration of a stream (of a particular format, size) * is the same regardless of whether the stream is input or output.</p> * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and - * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations} for more details about + * android.scaler.availableStallDurations for more details about * calculating the max frame rate.</p> + * <p>(Keep in sync with + * StreamConfigurationMap#getOutputMinFrameDuration)</p> * - * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS * @see CaptureRequest#SENSOR_FRAME_DURATION + * @hide */ - public static final Key<long[]> SCALER_AVAILABLE_MIN_FRAME_DURATIONS = - new Key<long[]>("android.scaler.availableMinFrameDurations", long[].class); + public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> SCALER_AVAILABLE_MIN_FRAME_DURATIONS = + new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.scaler.availableMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class); /** * <p>This lists the maximum stall duration for each @@ -929,12 +937,105 @@ public final class CameraCharacteristics extends CameraMetadata { * for more details.</p> * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} for more information about * calculating the max frame rate (absent stalls).</p> + * <p>(Keep up to date with + * StreamConfigurationMap#getOutputStallDuration(int, Size) )</p> * * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES * @see CaptureRequest#SENSOR_FRAME_DURATION + * @hide */ - public static final Key<long[]> SCALER_AVAILABLE_STALL_DURATIONS = - new Key<long[]>("android.scaler.availableStallDurations", long[].class); + public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> SCALER_AVAILABLE_STALL_DURATIONS = + new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.scaler.availableStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class); + + /** + * <p>The available stream configurations that this + * camera device supports; also includes the minimum frame durations + * and the stall durations for each format/size combination.</p> + * <p>All camera devices will support sensor maximum resolution (defined by + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}) for the JPEG format.</p> + * <p>For a given use case, the actual maximum supported resolution + * may be lower than what is listed here, depending on the destination + * Surface for the image data. For example, for recording video, + * the video encoder chosen may have a maximum size limit (e.g. 1080p) + * smaller than what the camera (e.g. maximum resolution is 3264x2448) + * can provide.</p> + * <p>Please reference the documentation for the image data destination to + * check if it limits the maximum size for image data.</p> + * <p>Not all output formats may be supported in a configuration with + * an input stream of a particular format. For more details, see + * android.scaler.availableInputOutputFormatsMap.</p> + * <p>The following table describes the minimum required output stream + * configurations based on the hardware level + * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p> + * <table> + * <thead> + * <tr> + * <th align="center">Format</th> + * <th align="center">Size</th> + * <th align="center">Hardware Level</th> + * <th align="center">Notes</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td align="center">JPEG</td> + * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td> + * <td align="center">Any</td> + * <td align="center"></td> + * </tr> + * <tr> + * <td align="center">JPEG</td> + * <td align="center">1920x1080 (1080p)</td> + * <td align="center">Any</td> + * <td align="center">if 1080p <= activeArraySize</td> + * </tr> + * <tr> + * <td align="center">JPEG</td> + * <td align="center">1280x720 (720)</td> + * <td align="center">Any</td> + * <td align="center">if 720p <= activeArraySize</td> + * </tr> + * <tr> + * <td align="center">JPEG</td> + * <td align="center">640x480 (480p)</td> + * <td align="center">Any</td> + * <td align="center">if 480p <= activeArraySize</td> + * </tr> + * <tr> + * <td align="center">JPEG</td> + * <td align="center">320x240 (240p)</td> + * <td align="center">Any</td> + * <td align="center">if 240p <= activeArraySize</td> + * </tr> + * <tr> + * <td align="center">YUV_420_888</td> + * <td align="center">all output sizes available for JPEG</td> + * <td align="center">FULL</td> + * <td align="center"></td> + * </tr> + * <tr> + * <td align="center">YUV_420_888</td> + * <td align="center">all output sizes available for JPEG, up to the maximum video size</td> + * <td align="center">LIMITED</td> + * <td align="center"></td> + * </tr> + * <tr> + * <td align="center">IMPLEMENTATION_DEFINED</td> + * <td align="center">same as YUV_420_888</td> + * <td align="center">Any</td> + * <td align="center"></td> + * </tr> + * </tbody> + * </table> + * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional + * mandatory stream configurations on a per-capability basis.</p> + * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + */ + public static final Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP = + new Key<android.hardware.camera2.params.StreamConfigurationMap>("android.scaler.streamConfigurationMap", android.hardware.camera2.params.StreamConfigurationMap.class); /** * <p>Area of raw data which corresponds to only @@ -982,13 +1083,9 @@ public final class CameraCharacteristics extends CameraMetadata { * being clipped to the maximum. See that control * for a full definition of frame durations.</p> * <p>Refer to - * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS android.scaler.availableProcessedMinDurations}, - * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS android.scaler.availableJpegMinDurations}, and - * android.scaler.availableRawMinDurations for the minimum - * frame duration values.</p> + * StreamConfigurationMap#getOutputMinFrameDuration(int,Size) + * for the minimum frame duration values.</p> * - * @see CameraCharacteristics#SCALER_AVAILABLE_JPEG_MIN_DURATIONS - * @see CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS * @see CaptureRequest#SENSOR_FRAME_DURATION */ public static final Key<Long> SENSOR_INFO_MAX_FRAME_DURATION = @@ -1007,9 +1104,7 @@ public final class CameraCharacteristics extends CameraMetadata { * including black calibration pixels.</p> * <p>Maximum output resolution for raw format must * match this in - * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}.</p> - * - * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS + * android.scaler.availableStreamConfigurations.</p> */ public static final Key<android.hardware.camera2.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE = new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class); @@ -1420,4 +1515,13 @@ public final class CameraCharacteristics extends CameraMetadata { /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ * End generated code *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/ + + + + + + + + + } diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 9d0e0e1..ca03dae 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -16,6 +16,8 @@ package android.hardware.camera2; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.graphics.ImageFormat; import android.os.Handler; import android.view.Surface; @@ -147,7 +149,7 @@ public interface CameraDevice extends AutoCloseable { * the size of the Surface with * {@link android.view.SurfaceHolder#setFixedSize} to be one of the * supported - * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes} + * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes} * before calling {@link android.view.SurfaceHolder#getSurface}.</li> * * <li>For accessing through an OpenGL texture via a @@ -155,14 +157,14 @@ public interface CameraDevice extends AutoCloseable { * the SurfaceTexture with * {@link android.graphics.SurfaceTexture#setDefaultBufferSize} to be one * of the supported - * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes} + * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes} * before creating a Surface from the SurfaceTexture with * {@link Surface#Surface}.</li> * * <li>For recording with {@link android.media.MediaCodec}: Call * {@link android.media.MediaCodec#createInputSurface} after configuring * the media codec to use one of the - * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes} + * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes} * </li> * * <li>For recording with {@link android.media.MediaRecorder}: TODO</li> @@ -171,18 +173,15 @@ public interface CameraDevice extends AutoCloseable { * Create a RenderScript * {@link android.renderscript.Allocation Allocation} with a supported YUV * type, the IO_INPUT flag, and one of the supported - * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed sizes}. Then + * {@link StreamConfigurationMap#getOutputSizes(int) processed sizes}. Then * obtain the Surface with * {@link android.renderscript.Allocation#getSurface}.</li> * - * <li>For access to uncompressed or JPEG data in the application: Create a - * {@link android.media.ImageReader} object with the desired - * {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS image format}, and a - * size from the matching - * {@link CameraCharacteristics#SCALER_AVAILABLE_PROCESSED_SIZES processed}, - * {@link CameraCharacteristics#SCALER_AVAILABLE_JPEG_SIZES jpeg}. Then obtain - * a Surface from it.</li> - * + * <li>For access to uncompressed or {@link ImageFormat#JPEG JPEG} data in the application: + * Create a {@link android.media.ImageReader} object with the desired + * {@link StreamConfigurationMap#getOutputFormats() image format}, and a size from the matching + * {@link StreamConfigurationMap#getOutputSizes(int) processed size} and {@code format}. + * Then obtain a {@link Surface} from it.</li> * </ul> * * </p> diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 6659278..a11390d 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -446,20 +446,6 @@ public abstract class CameraMetadata { public static final int REQUEST_AVAILABLE_CAPABILITIES_DNG = 5; // - // Enumeration values for CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS - // - - /** - * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS - */ - public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0; - - /** - * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS - */ - public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1; - - // // Enumeration values for CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT // diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 0ca9161..8ae21f3 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -1185,7 +1185,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * cannot process more than 1 capture at a time.</li> * </ul> * <p>The necessary information for the application, given the model above, - * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field. + * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field + * using StreamConfigurationMap#getOutputMinFrameDuration(int, Size). * These are used to determine the maximum frame rate / minimum frame * duration that is possible for a given stream configuration.</p> * <p>Specifically, the application can use the following rules to @@ -1195,7 +1196,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * <li>Let the set of currently configured input/output streams * be called <code>S</code>.</li> * <li>Find the minimum frame durations for each stream in <code>S</code>, by - * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with + * looking it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using + * StreamConfigurationMap#getOutputMinFrameDuration(int, Size) (with * its respective size/format). Let this set of frame durations be called * <code>F</code>.</li> * <li>For any given request <code>R</code>, the minimum frame duration allowed @@ -1203,7 +1205,8 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * used in <code>R</code> be called <code>S_r</code>.</li> * </ol> * <p>If none of the streams in <code>S_r</code> have a stall time (listed in - * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in + * StreamConfigurationMap#getOutputStallDuration(int,Size) using its + * respective size/format), then the frame duration in * <code>F</code> determines the steady state frame rate that the application will * get if it uses <code>R</code> as a repeating request. Let this special kind * of request be called <code>Rsimple</code>.</p> @@ -1214,10 +1217,9 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { * if all buffers from the previous <code>Rstall</code> have already been * delivered.</p> * <p>For more details about stalling, see - * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p> + * StreamConfigurationMap#getOutputStallDuration(int,Size).</p> * - * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS - * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS + * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP */ public static final Key<Long> SENSOR_FRAME_DURATION = new Key<Long>("android.sensor.frameDuration", long.class); @@ -1516,4 +1518,12 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ * End generated code *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/ + + + + + + + + } diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 42a3de8..0160622 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -216,18 +216,6 @@ public final class CaptureResult extends CameraMetadata { new Key<float[]>("android.colorCorrection.gains", float[].class); /** - * <p>The ID sent with the latest - * CAMERA2_TRIGGER_PRECAPTURE_METERING call</p> - * <p>Must be 0 if no - * CAMERA2_TRIGGER_PRECAPTURE_METERING trigger received yet - * by HAL. Always updated even if AE algorithm ignores the - * trigger</p> - * @hide - */ - public static final Key<Integer> CONTROL_AE_PRECAPTURE_ID = - new Key<Integer>("android.control.aePrecaptureId", int.class); - - /** * <p>The desired setting for the camera device's auto-exposure * algorithm's antibanding compensation.</p> * <p>Some kinds of lighting fixtures, such as some fluorescent @@ -1068,17 +1056,6 @@ public final class CaptureResult extends CameraMetadata { new Key<Integer>("android.control.afState", int.class); /** - * <p>The ID sent with the latest - * CAMERA2_TRIGGER_AUTOFOCUS call</p> - * <p>Must be 0 if no CAMERA2_TRIGGER_AUTOFOCUS trigger - * received yet by HAL. Always updated even if AF algorithm - * ignores the trigger</p> - * @hide - */ - public static final Key<Integer> CONTROL_AF_TRIGGER_ID = - new Key<Integer>("android.control.afTriggerId", int.class); - - /** * <p>Whether AWB is currently locked to its * latest calculated values.</p> * <p>Note that AWB lock is only meaningful for AUTO @@ -1713,8 +1690,10 @@ public final class CaptureResult extends CameraMetadata { * capture must arrive before the FINAL buffer for that capture. This entry may * only be used by the camera device if quirks.usePartialResult is set to 1.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @deprecated * @hide */ + @Deprecated public static final Key<Boolean> QUIRKS_PARTIAL_RESULT = new Key<Boolean>("android.quirks.partialResult", boolean.class); @@ -1834,7 +1813,8 @@ public final class CaptureResult extends CameraMetadata { * cannot process more than 1 capture at a time.</li> * </ul> * <p>The necessary information for the application, given the model above, - * is provided via the {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} field. + * is provided via the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} field + * using StreamConfigurationMap#getOutputMinFrameDuration(int, Size). * These are used to determine the maximum frame rate / minimum frame * duration that is possible for a given stream configuration.</p> * <p>Specifically, the application can use the following rules to @@ -1844,7 +1824,8 @@ public final class CaptureResult extends CameraMetadata { * <li>Let the set of currently configured input/output streams * be called <code>S</code>.</li> * <li>Find the minimum frame durations for each stream in <code>S</code>, by - * looking it up in {@link CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS android.scaler.availableMinFrameDurations} (with + * looking it up in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap} using + * StreamConfigurationMap#getOutputMinFrameDuration(int, Size) (with * its respective size/format). Let this set of frame durations be called * <code>F</code>.</li> * <li>For any given request <code>R</code>, the minimum frame duration allowed @@ -1852,7 +1833,8 @@ public final class CaptureResult extends CameraMetadata { * used in <code>R</code> be called <code>S_r</code>.</li> * </ol> * <p>If none of the streams in <code>S_r</code> have a stall time (listed in - * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}), then the frame duration in + * StreamConfigurationMap#getOutputStallDuration(int,Size) using its + * respective size/format), then the frame duration in * <code>F</code> determines the steady state frame rate that the application will * get if it uses <code>R</code> as a repeating request. Let this special kind * of request be called <code>Rsimple</code>.</p> @@ -1863,10 +1845,9 @@ public final class CaptureResult extends CameraMetadata { * if all buffers from the previous <code>Rstall</code> have already been * delivered.</p> * <p>For more details about stalling, see - * {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS android.scaler.availableStallDurations}.</p> + * StreamConfigurationMap#getOutputStallDuration(int,Size).</p> * - * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS - * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS + * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP */ public static final Key<Long> SENSOR_FRAME_DURATION = new Key<Long>("android.sensor.frameDuration", long.class); @@ -2141,8 +2122,10 @@ public final class CaptureResult extends CameraMetadata { * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CaptureRequest#COLOR_CORRECTION_GAINS + * @deprecated * @hide */ + @Deprecated public static final Key<float[]> STATISTICS_PREDICTED_COLOR_GAINS = new Key<float[]>("android.statistics.predictedColorGains", float[].class); @@ -2163,8 +2146,10 @@ public final class CaptureResult extends CameraMetadata { * <p>This value should always be calculated by the AWB block, * regardless of the android.control.* current values.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @deprecated * @hide */ + @Deprecated public static final Key<Rational[]> STATISTICS_PREDICTED_COLOR_TRANSFORM = new Key<Rational[]>("android.statistics.predictedColorTransform", Rational[].class); @@ -2441,6 +2426,14 @@ public final class CaptureResult extends CameraMetadata { * End generated code *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/ + + + + + + + + /** * <p> * List of the {@link Face Faces} detected through camera face detection diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl index d77f3d1..0815170 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl @@ -20,7 +20,7 @@ import android.view.Surface; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.CaptureRequest; -import android.hardware.camera2.LongParcelable; +import android.hardware.camera2.utils.LongParcelable; /** @hide */ interface ICameraDeviceUser diff --git a/core/java/android/hardware/camera2/StreamConfigurationMap.java b/core/java/android/hardware/camera2/StreamConfigurationMap.java deleted file mode 100644 index 5ddd7d6..0000000 --- a/core/java/android/hardware/camera2/StreamConfigurationMap.java +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.hardware.camera2; - -import android.graphics.ImageFormat; -import android.graphics.PixelFormat; -import android.hardware.camera2.utils.HashCodeHelpers; -import android.view.Surface; -import android.util.Size; - -import java.util.Arrays; - -import static com.android.internal.util.Preconditions.*; - -/** - * Immutable class to store the available stream - * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used - * when configuring streams with {@link CameraDevice#configureOutputs}. - * <!-- TODO: link to input stream configuration --> - * - * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively - * for that format) that are supported by a camera device.</p> - * - * <p>This also contains the minimum frame durations and stall durations for each format/size - * combination that can be used to calculate effective frame rate when submitting multiple captures. - * </p> - * - * <p>An instance of this object is available from {@link CameraCharacteristics} using - * the {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS} key and the - * {@link CameraCharacteristics#get} method.</p. - * - * <pre>{@code - * CameraCharacteristics characteristics = ...; - * StreamConfigurationMap configs = characteristics.get( - * CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); - * }</pre> - * - * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS - * @see CameraDevice#configureOutputs - */ -public final class StreamConfigurationMap { - - /** - * Create a new {@link StreamConfigurationMap}. - * - * <p>The array parameters ownership is passed to this object after creation; do not - * write to them after this constructor is invoked.</p> - * - * @param configurations a non-{@code null} array of {@link StreamConfiguration} - * @param durations a non-{@code null} array of {@link StreamConfigurationDuration} - * - * @throws NullPointerException if any of the arguments or subelements were {@code null} - * - * @hide - */ - public StreamConfigurationMap( - StreamConfiguration[] configurations, - StreamConfigurationDuration[] durations) { - // TODO: format check against ImageFormat/PixelFormat ? - - mConfigurations = checkArrayElementsNotNull(configurations, "configurations"); - mDurations = checkArrayElementsNotNull(durations, "durations"); - - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get the image {@code format} output formats in this stream configuration. - * - * <p>All image formats returned by this function will be defined in either {@link ImageFormat} - * or in {@link PixelFormat} (and there is no possibility of collision).</p> - * - * <p>Formats listed in this array are guaranteed to return true if queried with - * {@link #isOutputSupportedFor(int).</p> - * - * @return an array of integer format - * - * @see ImageFormat - * @see PixelFormat - */ - public final int[] getOutputFormats() { - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get the image {@code format} input formats in this stream configuration. - * - * <p>All image formats returned by this function will be defined in either {@link ImageFormat} - * or in {@link PixelFormat} (and there is no possibility of collision).</p> - * - * @return an array of integer format - * - * @see ImageFormat - * @see PixelFormat - * - * @hide - */ - public final int[] getInputFormats() { - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get the supported input sizes for this input format. - * - * <p>The format must have come from {@link #getInputFormats}; otherwise - * {@code null} is returned.</p> - * - * @param format a format from {@link #getInputFormats} - * @return a non-empty array of sizes, or {@code null} if the format was not available. - * - * @hide - */ - public Size[] getInputSizes(final int format) { - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Determine whether or not output streams can be - * {@link CameraDevice#configureOutputs configured} with a particular user-defined format. - * - * <p>This method determines that the output {@code format} is supported by the camera device; - * each output {@code surface} target may or may not itself support that {@code format}. - * Refer to the class which provides the surface for additional documentation.</p> - * - * <p>Formats for which this returns {@code true} are guaranteed to exist in the result - * returned by {@link #getOutputSizes}.</p> - * - * @param format an image format from either {@link ImageFormat} or {@link PixelFormat} - * @return - * {@code true} iff using a {@code surface} with this {@code format} will be - * supported with {@link CameraDevice#configureOutputs} - * - * @throws IllegalArgumentException - * if the image format was not a defined named constant - * from either {@link ImageFormat} or {@link PixelFormat} - * - * @see ImageFormat - * @see PixelFormat - * @see CameraDevice#configureOutputs - */ - public boolean isOutputSupportedFor(int format) { - checkArgumentFormat(format); - - final int[] formats = getOutputFormats(); - for (int i = 0; i < formats.length; ++i) { - if (format == formats[i]) { - return true; - } - } - - return false; - } - - /** - * Determine whether or not output streams can be configured with a particular class - * as a consumer. - * - * <p>The following list is generally usable for outputs: - * <ul> - * <li>{@link android.media.ImageReader} - - * Recommended for image processing or streaming to external resources (such as a file or - * network) - * <li>{@link android.media.MediaRecorder} - - * Recommended for recording video (simple to use) - * <li>{@link android.media.MediaCodec} - - * Recommended for recording video (more complicated to use, with more flexibility) - * <li>{@link android.renderscript.Allocation} - - * Recommended for image processing with {@link android.renderscript RenderScript} - * <li>{@link android.view.SurfaceHolder} - - * Recommended for low-power camera preview with {@link android.view.SurfaceView} - * <li>{@link android.graphics.SurfaceTexture} - - * Recommended for OpenGL-accelerated preview processing or compositing with - * {@link android.view.TextureView} - * </ul> - * </p> - * - * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i> - * provide a producer endpoint that is suitable to be used with - * {@link CameraDevice#configureOutputs}.</p> - * - * <p>Since not all of the above classes support output of all format and size combinations, - * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p> - * - * @param klass a non-{@code null} {@link Class} object reference - * @return {@code true} if this class is supported as an output, {@code false} otherwise - * - * @throws NullPointerException if {@code klass} was {@code null} - * - * @see CameraDevice#configureOutputs - * @see #isOutputSupportedFor(Surface) - */ - public static <T> boolean isOutputSupportedFor(final Class<T> klass) { - checkNotNull(klass, "klass must not be null"); - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Determine whether or not the {@code surface} in its current state is suitable to be - * {@link CameraDevice#configureOutputs configured} as an output. - * - * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations - * of that {@code surface} are compatible. Some classes that provide the {@code surface} are - * compatible with the {@link CameraDevice} in general - * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the - * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p> - * - * <p>Reasons for a {@code surface} being specifically incompatible might be: - * <ul> - * <li>Using a format that's not listed by {@link #getOutputFormats} - * <li>Using a format/size combination that's not listed by {@link #getOutputSizes} - * <li>The {@code surface} itself is not in a state where it can service a new producer.</p> - * </li> - * </ul> - * - * This is not an exhaustive list; see the particular class's documentation for further - * possible reasons of incompatibility.</p> - * - * @param surface a non-{@code null} {@link Surface} object reference - * @return {@code true} if this is supported, {@code false} otherwise - * - * @throws NullPointerException if {@code surface} was {@code null} - * - * @see CameraDevice#configureOutputs - * @see #isOutputSupportedFor(Class) - */ - public boolean isOutputSupportedFor(final Surface surface) { - checkNotNull(surface, "surface must not be null"); - - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get a list of sizes compatible with {@code klass} to use as an output. - * - * <p>Since some of the supported classes may support additional formats beyond - * an opaque/implementation-defined (under-the-hood) format; this function only returns - * sizes for the implementation-defined format.</p> - * - * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined - * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for - * that class and this method will return an empty array (but not {@code null}).</p> - * - * <p>If a well-defined format such as {@code NV21} is required, use - * {@link #getOutputSizes(int)} instead.</p> - * - * <p>The {@code klass} should be a supported output, that querying - * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p> - * - * @param klass - * a non-{@code null} {@link Class} object reference - * @return - * an array of supported sizes for implementation-defined formats, - * or {@code null} iff the {@code klass} is not a supported output - * - * @throws NullPointerException if {@code klass} was {@code null} - * - * @see #isOutputSupportedFor(Class) - */ - public <T> Size[] getOutputSizes(final Class<T> klass) { - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get a list of sizes compatible with the requested image {@code format}. - * - * <p>The {@code format} should be a supported format (one of the formats returned by - * {@link #getOutputFormats}).</p> - * - * @param format an image format from {@link ImageFormat} or {@link PixelFormat} - * @return - * an array of supported sizes, - * or {@code null} if the {@code format} is not a supported output - * - * @see ImageFormat - * @see PixelFormat - * @see #getOutputFormats - */ - public Size[] getOutputSizes(final int format) { - try { - checkArgumentFormatSupported(format, /*output*/true); - } catch (IllegalArgumentException e) { - return null; - } - - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} - * for the format/size combination (in nanoseconds). - * - * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p> - * <p>{@code size} should be one of the ones returned by - * {@link #getOutputSizes(int)}.</p> - * - * @param format an image format from {@link ImageFormat} or {@link PixelFormat} - * @param size an output-compatible size - * @return a minimum frame duration {@code >=} 0 in nanoseconds - * - * @throws IllegalArgumentException if {@code format} or {@code size} was not supported - * @throws NullPointerException if {@code size} was {@code null} - * - * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS - * @see CaptureRequest#SENSOR_FRAME_DURATION - * @see ImageFormat - * @see PixelFormat - */ - public long getOutputMinFrameDuration(final int format, final Size size) { - checkArgumentFormatSupported(format, /*output*/true); - - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} - * for the class/size combination (in nanoseconds). - * - * <p>This assumes a the {@code klass} is set up to use an implementation-defined format. - * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p> - * - * <p>{@code klass} should be one of the ones which is supported by - * {@link #isOutputSupportedFor(Class)}.</p> - * - * <p>{@code size} should be one of the ones returned by - * {@link #getOutputSizes(int)}.</p> - * - * @param klass - * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a - * non-empty array returned by {@link #getOutputSizes(Class)} - * @param size an output-compatible size - * @return a minimum frame duration {@code >=} 0 in nanoseconds - * - * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported - * @throws NullPointerException if {@code size} or {@code klass} was {@code null} - * - * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS - * @see CaptureRequest#SENSOR_FRAME_DURATION - * @see ImageFormat - * @see PixelFormat - */ - public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) { - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration} - * for the format/size combination (in nanoseconds). - * - * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p> - * <p>{@code size} should be one of the ones returned by - * {@link #getOutputSizes(int)}.</p> - * - * @param format an image format from {@link ImageFormat} or {@link PixelFormat} - * @param size an output-compatible size - * @return a stall duration {@code >=} 0 in nanoseconds - * - * @throws IllegalArgumentException if {@code format} or {@code size} was not supported - * @throws NullPointerException if {@code size} was {@code null} - * - * @see CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS - * @see ImageFormat - * @see PixelFormat - */ - public long getOutputStallDuration(final int format, final Size size) { - checkArgumentFormatSupported(format, /*output*/true); - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Get the {@link CameraCharacteristics#SCALER_AVAILABLE_STALL_DURATIONS stall duration} - * for the class/size combination (in nanoseconds). - * - * <p>This assumes a the {@code klass} is set up to use an implementation-defined format. - * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p> - * - * <p>{@code klass} should be one of the ones with a non-empty array returned by - * {@link #getOutputSizes(Class)}.</p> - * - * <p>{@code size} should be one of the ones returned by - * {@link #getOutputSizes(Class)}.</p> - * - * @param klass - * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a - * non-empty array returned by {@link #getOutputSizes(Class)} - * @param size an output-compatible size - * @return a minimum frame duration {@code >=} 0 in nanoseconds - * - * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported - * @throws NullPointerException if {@code size} or {@code klass} was {@code null} - * - * @see CameraCharacteristics#SCALER_AVAILABLE_MIN_FRAME_DURATIONS - * @see CaptureRequest#SENSOR_FRAME_DURATION - * @see ImageFormat - * @see PixelFormat - */ - public <T> long getOutputStallDuration(final Class<T> klass, final Size size) { - throw new UnsupportedOperationException("Not implemented yet"); - } - - /** - * Check if this {@link StreamConfigurationMap} is equal to another - * {@link StreamConfigurationMap}. - * - * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p> - * - * @return {@code true} if the objects were equal, {@code false} otherwise - */ - @Override - public boolean equals(final Object obj) { - if (obj == null) { - return false; - } - if (this == obj) { - return true; - } - if (obj instanceof StreamConfigurationMap) { - final StreamConfigurationMap other = (StreamConfigurationMap) obj; - // TODO: do we care about order? - return Arrays.equals(mConfigurations, other.mConfigurations) && - Arrays.equals(mDurations, other.mDurations); - } - return false; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - // TODO: do we care about order? - return HashCodeHelpers.hashCode(mConfigurations) ^ HashCodeHelpers.hashCode(mDurations); - } - - // Check that the argument is supported by #getOutputFormats or #getInputFormats - private int checkArgumentFormatSupported(int format, boolean output) { - checkArgumentFormat(format); - - int[] formats = output ? getOutputFormats() : getInputFormats(); - for (int i = 0; i < formats.length; ++i) { - if (format == formats[i]) { - return format; - } - } - - throw new IllegalArgumentException(String.format( - "format %x is not supported by this stream configuration map", format)); - } - - /** - * Ensures that the format is either user-defined or implementation defined. - * - * <p>Any invalid/undefined formats will raise an exception.</p> - * - * @param format image format - * @return the format - * - * @throws IllegalArgumentException if the format was invalid - */ - static int checkArgumentFormatInternal(int format) { - if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { - return format; - } - - return checkArgumentFormat(format); - } - - /** - * Ensures that the format is user-defined in either ImageFormat or PixelFormat. - * - * <p>Any invalid/undefined formats will raise an exception, including implementation-defined. - * </p> - * - * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p> - * - * @param format image format - * @return the format - * - * @throws IllegalArgumentException if the format was not user-defined - */ - static int checkArgumentFormat(int format) { - if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { - throw new IllegalArgumentException(String.format( - "format %x was not defined in either ImageFormat or PixelFormat", format)); - } - - return format; - } - - private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22; - - private final StreamConfiguration[] mConfigurations; - private final StreamConfigurationDuration[] mDurations; - -} diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java index 988f8f9..628d1c3 100644 --- a/core/java/android/hardware/camera2/impl/CameraDevice.java +++ b/core/java/android/hardware/camera2/impl/CameraDevice.java @@ -24,9 +24,9 @@ import android.hardware.camera2.CaptureResult; import android.hardware.camera2.CaptureResultExtras; import android.hardware.camera2.ICameraDeviceCallbacks; import android.hardware.camera2.ICameraDeviceUser; -import android.hardware.camera2.LongParcelable; import android.hardware.camera2.utils.CameraBinderDecorator; import android.hardware.camera2.utils.CameraRuntimeException; +import android.hardware.camera2.utils.LongParcelable; import android.os.Handler; import android.os.IBinder; import android.os.Looper; diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 9a06e97..d28f7bd 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -43,6 +43,9 @@ import android.hardware.camera2.marshal.impl.MarshalQueryableSizeF; import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration; import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration; import android.hardware.camera2.marshal.impl.MarshalQueryableString; +import android.hardware.camera2.params.StreamConfiguration; +import android.hardware.camera2.params.StreamConfigurationDuration; +import android.hardware.camera2.params.StreamConfigurationMap; import android.os.Parcelable; import android.os.Parcel; import android.util.Log; @@ -207,10 +210,8 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return (T) getFaces(); } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) { return (T) getFaceRectangles(); - } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) { - return (T) getAvailableStreamConfigurations(); - } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) { - return (T) getAvailableMinFrameDurations(); + } else if (key.equals(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)) { + return (T) getStreamConfigurationMap(); } // For other keys, get() falls back to getBase() @@ -231,50 +232,6 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return availableFormats; } - private int[] getAvailableStreamConfigurations() { - final int NUM_ELEMENTS_IN_CONFIG = 4; - int[] availableConfigs = - getBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); - if (availableConfigs != null) { - if (availableConfigs.length % NUM_ELEMENTS_IN_CONFIG != 0) { - Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple" - + " of " + NUM_ELEMENTS_IN_CONFIG); - return availableConfigs; - } - - for (int i = 0; i < availableConfigs.length; i += NUM_ELEMENTS_IN_CONFIG) { - // JPEG has different value between native and managed side, need override. - if (availableConfigs[i] == NATIVE_JPEG_FORMAT) { - availableConfigs[i] = ImageFormat.JPEG; - } - } - } - - return availableConfigs; - } - - private long[] getAvailableMinFrameDurations() { - final int NUM_ELEMENTS_IN_DURATION = 4; - long[] availableMinDurations = - getBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS); - if (availableMinDurations != null) { - if (availableMinDurations.length % NUM_ELEMENTS_IN_DURATION != 0) { - Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple" - + " of " + NUM_ELEMENTS_IN_DURATION); - return availableMinDurations; - } - - for (int i = 0; i < availableMinDurations.length; i += NUM_ELEMENTS_IN_DURATION) { - // JPEG has different value between native and managed side, need override. - if (availableMinDurations[i] == NATIVE_JPEG_FORMAT) { - availableMinDurations[i] = ImageFormat.JPEG; - } - } - } - - return availableMinDurations; - } - private Face[] getFaces() { final int FACE_LANDMARK_SIZE = 6; @@ -374,6 +331,17 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return fixedFaceRectangles; } + private StreamConfigurationMap getStreamConfigurationMap() { + StreamConfiguration[] configurations = getBase( + CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); + StreamConfigurationDuration[] minFrameDurations = getBase( + CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS); + StreamConfigurationDuration[] stallDurations = getBase( + CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS); + + return new StreamConfigurationMap(configurations, minFrameDurations, stallDurations); + } + private <T> void setBase(Key<T> key, T value) { int tag = key.getTag(); @@ -401,56 +369,12 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { return setAvailableFormats((int[]) value); } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) { return setFaceRectangles((Rect[]) value); - } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) { - return setAvailableStreamConfigurations((int[])value); - } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) { - return setAvailableMinFrameDurations((long[])value); } // For other keys, set() falls back to setBase(). return false; } - private boolean setAvailableStreamConfigurations(int[] value) { - final int NUM_ELEMENTS_IN_CONFIG = 4; - int[] availableConfigs = value; - if (value == null) { - // Let setBase() to handle the null value case. - return false; - } - - int[] newValues = new int[availableConfigs.length]; - for (int i = 0; i < availableConfigs.length; i++) { - newValues[i] = availableConfigs[i]; - if (i % NUM_ELEMENTS_IN_CONFIG == 0 && availableConfigs[i] == ImageFormat.JPEG) { - newValues[i] = NATIVE_JPEG_FORMAT; - } - } - - setBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS, newValues); - return true; - } - - private boolean setAvailableMinFrameDurations(long[] value) { - final int NUM_ELEMENTS_IN_DURATION = 4; - long[] availableDurations = value; - if (value == null) { - // Let setBase() to handle the null value case. - return false; - } - - long[] newValues = new long[availableDurations.length]; - for (int i = 0; i < availableDurations.length; i++) { - newValues[i] = availableDurations[i]; - if (i % NUM_ELEMENTS_IN_DURATION == 0 && availableDurations[i] == ImageFormat.JPEG) { - newValues[i] = NATIVE_JPEG_FORMAT; - } - } - - setBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS, newValues); - return true; - } - private boolean setAvailableFormats(int[] value) { int[] availableFormat = value; if (value == null) { diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java index 3025cb4..98a7ad7 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableReprocessFormatsMap.java @@ -15,9 +15,10 @@ */ package android.hardware.camera2.marshal.impl; -import android.hardware.camera2.ReprocessFormatsMap; import android.hardware.camera2.marshal.Marshaler; import android.hardware.camera2.marshal.MarshalQueryable; +import android.hardware.camera2.params.ReprocessFormatsMap; +import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.TypeReference; import static android.hardware.camera2.impl.CameraMetadataNative.*; @@ -50,12 +51,13 @@ public class MarshalQueryableReprocessFormatsMap * INPUT_FORMAT, OUTPUT_FORMAT_COUNT, [OUTPUT_0, OUTPUT_1, ..., OUTPUT_FORMAT_COUNT-1] * }; */ - int[] inputs = value.getInputs(); + int[] inputs = StreamConfigurationMap.imageFormatToInternal(value.getInputs()); for (int input : inputs) { // INPUT_FORMAT buffer.putInt(input); - int[] outputs = value.getOutputs(input); + int[] outputs = + StreamConfigurationMap.imageFormatToInternal(value.getOutputs(input)); // OUTPUT_FORMAT_COUNT buffer.putInt(outputs.length); diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java index 6a4e821..62ace31 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfiguration.java @@ -15,9 +15,9 @@ */ package android.hardware.camera2.marshal.impl; -import android.hardware.camera2.StreamConfiguration; import android.hardware.camera2.marshal.Marshaler; import android.hardware.camera2.marshal.MarshalQueryable; +import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.utils.TypeReference; import static android.hardware.camera2.impl.CameraMetadataNative.*; diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java index c3d564e..fd3dfac 100644 --- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableStreamConfigurationDuration.java @@ -15,9 +15,9 @@ */ package android.hardware.camera2.marshal.impl; -import android.hardware.camera2.StreamConfigurationDuration; import android.hardware.camera2.marshal.Marshaler; import android.hardware.camera2.marshal.MarshalQueryable; +import android.hardware.camera2.params.StreamConfigurationDuration; import android.hardware.camera2.utils.TypeReference; import static android.hardware.camera2.impl.CameraMetadataNative.*; diff --git a/core/java/android/hardware/camera2/ReprocessFormatsMap.java b/core/java/android/hardware/camera2/params/ReprocessFormatsMap.java index 894a499..d3f5bc3 100644 --- a/core/java/android/hardware/camera2/ReprocessFormatsMap.java +++ b/core/java/android/hardware/camera2/params/ReprocessFormatsMap.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package android.hardware.camera2; +package android.hardware.camera2.params; import static com.android.internal.util.Preconditions.*; +import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.utils.HashCodeHelpers; import java.util.Arrays; @@ -61,9 +62,12 @@ public final class ReprocessFormatsMap { * @throws IllegalArgumentException * if the data was poorly formatted * (missing output format length or too few output formats) + * or if any of the input/formats were not valid * @throws NullPointerException * if entry was null * + * @see StreamConfigurationMap#checkArgumentFormatInternal + * * @hide */ public ReprocessFormatsMap(final int[] entry) { @@ -72,26 +76,31 @@ public final class ReprocessFormatsMap { int numInputs = 0; int left = entry.length; for (int i = 0; i < entry.length; ) { - final int format = entry[i]; + int inputFormat = StreamConfigurationMap.checkArgumentFormatInternal(entry[i]); left--; i++; if (left < 1) { throw new IllegalArgumentException( - String.format("Input %x had no output format length listed", format)); + String.format("Input %x had no output format length listed", inputFormat)); } final int length = entry[i]; left--; i++; + for (int j = 0; j < length; ++j) { + int outputFormat = entry[i + j]; + StreamConfigurationMap.checkArgumentFormatInternal(outputFormat); + } + if (length > 0) { if (left < length) { throw new IllegalArgumentException( String.format( "Input %x had too few output formats listed (actual: %d, " + - "expected: %d)", format, left, length)); + "expected: %d)", inputFormat, left, length)); } i += length; @@ -131,7 +140,6 @@ public final class ReprocessFormatsMap { throw new AssertionError( String.format("Input %x had no output format length listed", format)); } - // TODO: check format is a valid input format final int length = mEntry[i]; left--; @@ -149,12 +157,10 @@ public final class ReprocessFormatsMap { left -= length; } - // TODO: check output format is a valid output format - inputs[j] = format; } - return inputs; + return StreamConfigurationMap.imageFormatToPublic(inputs); } /** @@ -204,7 +210,7 @@ public final class ReprocessFormatsMap { outputs[k] = mEntry[i + k]; } - return outputs; + return StreamConfigurationMap.imageFormatToPublic(outputs); } i += length; diff --git a/core/java/android/hardware/camera2/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java index a514034..1c6b6e9 100644 --- a/core/java/android/hardware/camera2/StreamConfiguration.java +++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java @@ -14,13 +14,16 @@ * limitations under the License. */ -package android.hardware.camera2; +package android.hardware.camera2.params; import static com.android.internal.util.Preconditions.*; -import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal; +import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormatInternal; import android.graphics.ImageFormat; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; import android.hardware.camera2.utils.HashCodeHelpers; +import android.graphics.PixelFormat; import android.util.Size; /** @@ -62,11 +65,12 @@ public final class StreamConfiguration { } /** - * Get the image {@code format} in this stream configuration. + * Get the internal image {@code format} in this stream configuration. * * @return an integer format * * @see ImageFormat + * @see PixelFormat */ public final int getFormat() { return mFormat; diff --git a/core/java/android/hardware/camera2/StreamConfigurationDuration.java b/core/java/android/hardware/camera2/params/StreamConfigurationDuration.java index 6a31156..217059d 100644 --- a/core/java/android/hardware/camera2/StreamConfigurationDuration.java +++ b/core/java/android/hardware/camera2/params/StreamConfigurationDuration.java @@ -14,13 +14,15 @@ * limitations under the License. */ -package android.hardware.camera2; +package android.hardware.camera2.params; import static com.android.internal.util.Preconditions.*; -import static android.hardware.camera2.StreamConfigurationMap.checkArgumentFormatInternal; +import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormatInternal; import android.graphics.ImageFormat; +import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.utils.HashCodeHelpers; +import android.graphics.PixelFormat; import android.util.Size; /** @@ -59,11 +61,12 @@ public final class StreamConfigurationDuration { } /** - * Get the image {@code format} in this stream configuration duration + * Get the internal image {@code format} in this stream configuration duration * * @return an integer format * * @see ImageFormat + * @see PixelFormat */ public final int getFormat() { return mFormat; diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java new file mode 100644 index 0000000..4cd6d15 --- /dev/null +++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java @@ -0,0 +1,949 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2.params; + +import android.graphics.ImageFormat; +import android.graphics.PixelFormat; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.utils.HashCodeHelpers; +import android.view.Surface; +import android.util.Log; +import android.util.Size; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Objects; + +import static com.android.internal.util.Preconditions.*; + +/** + * Immutable class to store the available stream + * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to be used + * when configuring streams with {@link CameraDevice#configureOutputs}. + * <!-- TODO: link to input stream configuration --> + * + * <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively + * for that format) that are supported by a camera device.</p> + * + * <p>This also contains the minimum frame durations and stall durations for each format/size + * combination that can be used to calculate effective frame rate when submitting multiple captures. + * </p> + * + * <p>An instance of this object is available from {@link CameraCharacteristics} using + * the {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP} key and the + * {@link CameraCharacteristics#get} method.</p> + * + * <pre><code>{@code + * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); + * StreamConfigurationMap configs = characteristics.get( + * CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + * }</code></pre> + * + * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP + * @see CameraDevice#configureOutputs + */ +public final class StreamConfigurationMap { + + private static final String TAG = "StreamConfigurationMap"; + /** + * Create a new {@link StreamConfigurationMap}. + * + * <p>The array parameters ownership is passed to this object after creation; do not + * write to them after this constructor is invoked.</p> + * + * @param configurations a non-{@code null} array of {@link StreamConfiguration} + * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * + * @throws NullPointerException if any of the arguments or subelements were {@code null} + * + * @hide + */ + public StreamConfigurationMap( + StreamConfiguration[] configurations, + StreamConfigurationDuration[] minFrameDurations, + StreamConfigurationDuration[] stallDurations) { + + mConfigurations = checkArrayElementsNotNull(configurations, "configurations"); + mMinFrameDurations = checkArrayElementsNotNull(minFrameDurations, "minFrameDurations"); + mStallDurations = checkArrayElementsNotNull(stallDurations, "stallDurations"); + + // For each format, track how many sizes there are available to configure + for (StreamConfiguration config : configurations) { + HashMap<Integer, Integer> map = config.isOutput() ? mOutputFormats : mInputFormats; + + Integer count = map.get(config.getFormat()); + + if (count == null) { + count = 0; + } + count = count + 1; + + map.put(config.getFormat(), count); + } + + if (!mOutputFormats.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) { + throw new AssertionError( + "At least one stream configuration for IMPLEMENTATION_DEFINED must exist"); + } + } + + /** + * Get the image {@code format} output formats in this stream configuration. + * + * <p>All image formats returned by this function will be defined in either {@link ImageFormat} + * or in {@link PixelFormat} (and there is no possibility of collision).</p> + * + * <p>Formats listed in this array are guaranteed to return true if queried with + * {@link #isOutputSupportedFor(int).</p> + * + * @return an array of integer format + * + * @see ImageFormat + * @see PixelFormat + */ + public final int[] getOutputFormats() { + return getPublicFormats(/*output*/true); + } + + /** + * Get the image {@code format} input formats in this stream configuration. + * + * <p>All image formats returned by this function will be defined in either {@link ImageFormat} + * or in {@link PixelFormat} (and there is no possibility of collision).</p> + * + * @return an array of integer format + * + * @see ImageFormat + * @see PixelFormat + * + * @hide + */ + public final int[] getInputFormats() { + return getPublicFormats(/*output*/false); + } + + /** + * Get the supported input sizes for this input format. + * + * <p>The format must have come from {@link #getInputFormats}; otherwise + * {@code null} is returned.</p> + * + * @param format a format from {@link #getInputFormats} + * @return a non-empty array of sizes, or {@code null} if the format was not available. + * + * @hide + */ + public Size[] getInputSizes(final int format) { + return getPublicFormatSizes(format, /*output*/false); + } + + /** + * Determine whether or not output streams can be + * {@link CameraDevice#configureOutputs configured} with a particular user-defined format. + * + * <p>This method determines that the output {@code format} is supported by the camera device; + * each output {@code surface} target may or may not itself support that {@code format}. + * Refer to the class which provides the surface for additional documentation.</p> + * + * <p>Formats for which this returns {@code true} are guaranteed to exist in the result + * returned by {@link #getOutputSizes}.</p> + * + * @param format an image format from either {@link ImageFormat} or {@link PixelFormat} + * @return + * {@code true} iff using a {@code surface} with this {@code format} will be + * supported with {@link CameraDevice#configureOutputs} + * + * @throws IllegalArgumentException + * if the image format was not a defined named constant + * from either {@link ImageFormat} or {@link PixelFormat} + * + * @see ImageFormat + * @see PixelFormat + * @see CameraDevice#configureOutputs + */ + public boolean isOutputSupportedFor(int format) { + checkArgumentFormat(format); + + format = imageFormatToInternal(format); + return getFormatsMap(/*output*/true).containsKey(format); + } + + /** + * Determine whether or not output streams can be configured with a particular class + * as a consumer. + * + * <p>The following list is generally usable for outputs: + * <ul> + * <li>{@link android.media.ImageReader} - + * Recommended for image processing or streaming to external resources (such as a file or + * network) + * <li>{@link android.media.MediaRecorder} - + * Recommended for recording video (simple to use) + * <li>{@link android.media.MediaCodec} - + * Recommended for recording video (more complicated to use, with more flexibility) + * <li>{@link android.renderscript.Allocation} - + * Recommended for image processing with {@link android.renderscript RenderScript} + * <li>{@link android.view.SurfaceHolder} - + * Recommended for low-power camera preview with {@link android.view.SurfaceView} + * <li>{@link android.graphics.SurfaceTexture} - + * Recommended for OpenGL-accelerated preview processing or compositing with + * {@link android.view.TextureView} + * </ul> + * </p> + * + * <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i> + * provide a producer endpoint that is suitable to be used with + * {@link CameraDevice#configureOutputs}.</p> + * + * <p>Since not all of the above classes support output of all format and size combinations, + * the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p> + * + * @param klass a non-{@code null} {@link Class} object reference + * @return {@code true} if this class is supported as an output, {@code false} otherwise + * + * @throws NullPointerException if {@code klass} was {@code null} + * + * @see CameraDevice#configureOutputs + * @see #isOutputSupportedFor(Surface) + */ + public static <T> boolean isOutputSupportedFor(Class<T> klass) { + checkNotNull(klass, "klass must not be null"); + + if (klass == android.media.ImageReader.class) { + return true; + } else if (klass == android.media.MediaRecorder.class) { + return true; + } else if (klass == android.media.MediaCodec.class) { + return true; + } else if (klass == android.renderscript.Allocation.class) { + return true; + } else if (klass == android.view.SurfaceHolder.class) { + return true; + } else if (klass == android.graphics.SurfaceTexture.class) { + return true; + } + + return false; + } + + /** + * Determine whether or not the {@code surface} in its current state is suitable to be + * {@link CameraDevice#configureOutputs configured} as an output. + * + * <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations + * of that {@code surface} are compatible. Some classes that provide the {@code surface} are + * compatible with the {@link CameraDevice} in general + * (see {@link #isOutputSupportedFor(Class)}, but it is the caller's responsibility to put the + * {@code surface} into a state that will be compatible with the {@link CameraDevice}.</p> + * + * <p>Reasons for a {@code surface} being specifically incompatible might be: + * <ul> + * <li>Using a format that's not listed by {@link #getOutputFormats} + * <li>Using a format/size combination that's not listed by {@link #getOutputSizes} + * <li>The {@code surface} itself is not in a state where it can service a new producer.</p> + * </li> + * </ul> + * + * This is not an exhaustive list; see the particular class's documentation for further + * possible reasons of incompatibility.</p> + * + * @param surface a non-{@code null} {@link Surface} object reference + * @return {@code true} if this is supported, {@code false} otherwise + * + * @throws NullPointerException if {@code surface} was {@code null} + * + * @see CameraDevice#configureOutputs + * @see #isOutputSupportedFor(Class) + */ + public boolean isOutputSupportedFor(Surface surface) { + checkNotNull(surface, "surface must not be null"); + + throw new UnsupportedOperationException("Not implemented yet"); + + // TODO: JNI function that checks the Surface's IGraphicBufferProducer state + } + + /** + * Get a list of sizes compatible with {@code klass} to use as an output. + * + * <p>Since some of the supported classes may support additional formats beyond + * an opaque/implementation-defined (under-the-hood) format; this function only returns + * sizes for the implementation-defined format.</p> + * + * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined + * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for + * that class and this method will return an empty array (but not {@code null}).</p> + * + * <p>If a well-defined format such as {@code NV21} is required, use + * {@link #getOutputSizes(int)} instead.</p> + * + * <p>The {@code klass} should be a supported output, that querying + * {@code #isOutputSupportedFor(Class)} should return {@code true}.</p> + * + * @param klass + * a non-{@code null} {@link Class} object reference + * @return + * an array of supported sizes for implementation-defined formats, + * or {@code null} iff the {@code klass} is not a supported output + * + * @throws NullPointerException if {@code klass} was {@code null} + * + * @see #isOutputSupportedFor(Class) + */ + public <T> Size[] getOutputSizes(Class<T> klass) { + if (isOutputSupportedFor(klass) == false) { + return null; + } + + return getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /*output*/true); + } + + /** + * Get a list of sizes compatible with the requested image {@code format}. + * + * <p>The {@code format} should be a supported format (one of the formats returned by + * {@link #getOutputFormats}).</p> + * + * @param format an image format from {@link ImageFormat} or {@link PixelFormat} + * @return + * an array of supported sizes, + * or {@code null} if the {@code format} is not a supported output + * + * @see ImageFormat + * @see PixelFormat + * @see #getOutputFormats + */ + public Size[] getOutputSizes(int format) { + return getPublicFormatSizes(format, /*output*/true); + } + + /** + * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} + * for the format/size combination (in nanoseconds). + * + * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p> + * <p>{@code size} should be one of the ones returned by + * {@link #getOutputSizes(int)}.</p> + * + * <p>This should correspond to the frame duration when only that stream is active, with all + * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}. + * </p> + * + * <p>When multiple streams are used in a request, the minimum frame duration will be + * {@code max(individual stream min durations)}.</p> + * + * <!-- + * TODO: uncomment after adding input stream support + * <p>The minimum frame duration of a stream (of a particular format, size) is the same + * regardless of whether the stream is input or output.</p> + * --> + * + * @param format an image format from {@link ImageFormat} or {@link PixelFormat} + * @param size an output-compatible size + * @return a minimum frame duration {@code >=} 0 in nanoseconds + * + * @throws IllegalArgumentException if {@code format} or {@code size} was not supported + * @throws NullPointerException if {@code size} was {@code null} + * + * @see CaptureRequest#SENSOR_FRAME_DURATION + * @see #getOutputStallDuration(int, Size) + * @see ImageFormat + * @see PixelFormat + */ + public long getOutputMinFrameDuration(int format, Size size) { + checkNotNull(size, "size must not be null"); + checkArgumentFormatSupported(format, /*output*/true); + + return getInternalFormatDuration(imageFormatToInternal(format), size, DURATION_MIN_FRAME); + } + + /** + * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} + * for the class/size combination (in nanoseconds). + * + * <p>This assumes a the {@code klass} is set up to use an implementation-defined format. + * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p> + * + * <p>{@code klass} should be one of the ones which is supported by + * {@link #isOutputSupportedFor(Class)}.</p> + * + * <p>{@code size} should be one of the ones returned by + * {@link #getOutputSizes(int)}.</p> + * + * <p>This should correspond to the frame duration when only that stream is active, with all + * processing (typically in {@code android.*.mode}) set to either {@code OFF} or {@code FAST}. + * </p> + * + * <p>When multiple streams are used in a request, the minimum frame duration will be + * {@code max(individual stream min durations)}.</p> + * + * <!-- + * TODO: uncomment after adding input stream support + * <p>The minimum frame duration of a stream (of a particular format, size) is the same + * regardless of whether the stream is input or output.</p> + * --> + * + * @param klass + * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a + * non-empty array returned by {@link #getOutputSizes(Class)} + * @param size an output-compatible size + * @return a minimum frame duration {@code >=} 0 in nanoseconds + * + * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported + * @throws NullPointerException if {@code size} or {@code klass} was {@code null} + * + * @see CaptureRequest#SENSOR_FRAME_DURATION + * @see ImageFormat + * @see PixelFormat + */ + public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) { + if (!isOutputSupportedFor(klass)) { + throw new IllegalArgumentException("klass was not supported"); + } + + return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, + size, DURATION_MIN_FRAME); + } + + /** + * Get the stall duration for the format/size combination (in nanoseconds). + * + * <p>{@code format} should be one of the ones returned by {@link #getOutputFormats()}.</p> + * <p>{@code size} should be one of the ones returned by + * {@link #getOutputSizes(int)}.</p> + * + * <p> + * A stall duration is how much extra time would get added to the normal minimum frame duration + * for a repeating request that has streams with non-zero stall. + * + * <p>For example, consider JPEG captures which have the following characteristics: + * + * <ul> + * <li>JPEG streams act like processed YUV streams in requests for which they are not included; + * in requests in which they are directly referenced, they act as JPEG streams. + * This is because supporting a JPEG stream requires the underlying YUV data to always be ready + * for use by a JPEG encoder, but the encoder will only be used (and impact frame duration) on + * requests that actually reference a JPEG stream. + * <li>The JPEG processor can run concurrently to the rest of the camera pipeline, but cannot + * process more than 1 capture at a time. + * </ul> + * + * <p>In other words, using a repeating YUV request would result in a steady frame rate + * (let's say it's 30 FPS). If a single JPEG request is submitted periodically, + * the frame rate will stay at 30 FPS (as long as we wait for the previous JPEG to return each + * time). If we try to submit a repeating YUV + JPEG request, then the frame rate will drop from + * 30 FPS.</p> + * + * <p>In general, submitting a new request with a non-0 stall time stream will <em>not</em> cause a + * frame rate drop unless there are still outstanding buffers for that stream from previous + * requests.</p> + * + * <p>Submitting a repeating request with streams (call this {@code S}) is the same as setting + * the minimum frame duration from the normal minimum frame duration corresponding to {@code S}, + * added with the maximum stall duration for {@code S}.</p> + * + * <p>If interleaving requests with and without a stall duration, a request will stall by the + * maximum of the remaining times for each can-stall stream with outstanding buffers.</p> + * + * <p>This means that a stalling request will not have an exposure start until the stall has + * completed.</p> + * + * <p>This should correspond to the stall duration when only that stream is active, with all + * processing (typically in {@code android.*.mode}) set to {@code FAST} or {@code OFF}. + * Setting any of the processing modes to {@code HIGH_QUALITY} effectively results in an + * indeterminate stall duration for all streams in a request (the regular stall calculation + * rules are ignored).</p> + * + * <p>The following formats may always have a stall duration: + * <ul> + * <li>{@link ImageFormat#JPEG JPEG} + * <li>{@link ImageFormat#RAW_SENSOR RAW16} + * </ul> + * </p> + * + * <p>The following formats will never have a stall duration: + * <ul> + * <li>{@link ImageFormat#YUV_420_888 YUV_420_888} + * <li>{@link #isOutputSupportedFor(Class) Implementation-Defined} + * </ul></p> + * + * <p> + * All other formats may or may not have an allowed stall duration on a per-capability basis; + * refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + * android.request.availableCapabilities} for more details.</p> + * </p> + * + * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} + * for more information about calculating the max frame rate (absent stalls).</p> + * + * @param format an image format from {@link ImageFormat} or {@link PixelFormat} + * @param size an output-compatible size + * @return a stall duration {@code >=} 0 in nanoseconds + * + * @throws IllegalArgumentException if {@code format} or {@code size} was not supported + * @throws NullPointerException if {@code size} was {@code null} + * + * @see CaptureRequest#SENSOR_FRAME_DURATION + * @see ImageFormat + * @see PixelFormat + */ + public long getOutputStallDuration(int format, Size size) { + checkArgumentFormatSupported(format, /*output*/true); + + return getInternalFormatDuration(imageFormatToInternal(format), + size, DURATION_STALL); + } + + /** + * Get the stall duration for the class/size combination (in nanoseconds). + * + * <p>This assumes a the {@code klass} is set up to use an implementation-defined format. + * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p> + * + * <p>{@code klass} should be one of the ones with a non-empty array returned by + * {@link #getOutputSizes(Class)}.</p> + * + * <p>{@code size} should be one of the ones returned by + * {@link #getOutputSizes(Class)}.</p> + * + * <p>See {@link #getOutputStallDuration(int, Size)} for a definition of a + * <em>stall duration</em>.</p> + * + * @param klass + * a class which is supported by {@link #isOutputSupportedFor(Class)} and has a + * non-empty array returned by {@link #getOutputSizes(Class)} + * @param size an output-compatible size + * @return a minimum frame duration {@code >=} 0 in nanoseconds + * + * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported + * @throws NullPointerException if {@code size} or {@code klass} was {@code null} + * + * @see CaptureRequest#SENSOR_FRAME_DURATION + * @see ImageFormat + * @see PixelFormat + */ + public <T> long getOutputStallDuration(final Class<T> klass, final Size size) { + if (!isOutputSupportedFor(klass)) { + throw new IllegalArgumentException("klass was not supported"); + } + + return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, + size, DURATION_STALL); + } + + /** + * Check if this {@link StreamConfigurationMap} is equal to another + * {@link StreamConfigurationMap}. + * + * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p> + * + * @return {@code true} if the objects were equal, {@code false} otherwise + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (obj instanceof StreamConfigurationMap) { + final StreamConfigurationMap other = (StreamConfigurationMap) obj; + // XX: do we care about order? + return Arrays.equals(mConfigurations, other.mConfigurations) && + Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) && + Arrays.equals(mStallDurations, other.mStallDurations); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + // XX: do we care about order? + return HashCodeHelpers.hashCode(mConfigurations, mMinFrameDurations, mStallDurations); + } + + // Check that the argument is supported by #getOutputFormats or #getInputFormats + private int checkArgumentFormatSupported(int format, boolean output) { + checkArgumentFormat(format); + + int[] formats = output ? getOutputFormats() : getInputFormats(); + for (int i = 0; i < formats.length; ++i) { + if (format == formats[i]) { + return format; + } + } + + throw new IllegalArgumentException(String.format( + "format %x is not supported by this stream configuration map", format)); + } + + /** + * Ensures that the format is either user-defined or implementation defined. + * + * <p>If a format has a different internal representation than the public representation, + * passing in the public representation here will fail.</p> + * + * <p>For example if trying to use {@link ImageFormat#JPEG}: + * it has a different public representation than the internal representation + * {@code HAL_PIXEL_FORMAT_BLOB}, this check will fail.</p> + * + * <p>Any invalid/undefined formats will raise an exception.</p> + * + * @param format image format + * @return the format + * + * @throws IllegalArgumentException if the format was invalid + */ + static int checkArgumentFormatInternal(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + case HAL_PIXEL_FORMAT_BLOB: + return format; + case ImageFormat.JPEG: + throw new IllegalArgumentException( + "ImageFormat.JPEG is an unknown internal format"); + default: + return checkArgumentFormat(format); + } + } + + /** + * Ensures that the format is publicly user-defined in either ImageFormat or PixelFormat. + * + * <p>If a format has a different public representation than the internal representation, + * passing in the internal representation here will fail.</p> + * + * <p>For example if trying to use {@code HAL_PIXEL_FORMAT_BLOB}: + * it has a different internal representation than the public representation + * {@link ImageFormat#JPEG}, this check will fail.</p> + * + * <p>Any invalid/undefined formats will raise an exception, including implementation-defined. + * </p> + * + * <p>Note that {@code @hide} and deprecated formats will not pass this check.</p> + * + * @param format image format + * @return the format + * + * @throws IllegalArgumentException if the format was not user-defined + */ + static int checkArgumentFormat(int format) { + // TODO: remove this hack , CTS shouldn't have been using internal constants + if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) { + Log.w(TAG, "RAW_OPAQUE is not yet a published format; allowing it anyway"); + return format; + } + + if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) { + throw new IllegalArgumentException(String.format( + "format 0x%x was not defined in either ImageFormat or PixelFormat", format)); + } + + return format; + } + + /** + * Convert a public-visible {@code ImageFormat} into an internal format + * compatible with {@code graphics.h}. + * + * <p>In particular these formats are converted: + * <ul> + * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.JPEG + * </ul> + * </p> + * + * <p>Passing in an implementation-defined format which has no public equivalent will fail; + * as will passing in a public format which has a different internal format equivalent. + * See {@link #checkArgumentFormat} for more details about a legal public format.</p> + * + * <p>All other formats are returned as-is, no further invalid check is performed.</p> + * + * <p>This function is the dual of {@link #imageFormatToInternal}.</p> + * + * @param format image format from {@link ImageFormat} or {@link PixelFormat} + * @return the converted image formats + * + * @throws IllegalArgumentException + * if {@code format} is {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} or + * {@link ImageFormat#JPEG} + * + * @see ImageFormat + * @see PixelFormat + * @see #checkArgumentFormat + */ + static int imageFormatToPublic(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_BLOB: + return ImageFormat.JPEG; + case ImageFormat.JPEG: + throw new IllegalArgumentException( + "ImageFormat.JPEG is an unknown internal format"); + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + throw new IllegalArgumentException( + "IMPLEMENTATION_DEFINED must not leak to public API"); + default: + return format; + } + } + + /** + * Convert image formats from internal to public formats (in-place). + * + * @param formats an array of image formats + * @return {@code formats} + * + * @see #imageFormatToPublic + */ + static int[] imageFormatToPublic(int[] formats) { + if (formats == null) { + return null; + } + + for (int i = 0; i < formats.length; ++i) { + formats[i] = imageFormatToPublic(formats[i]); + } + + return formats; + } + + /** + * Convert a public format compatible with {@code ImageFormat} to an internal format + * from {@code graphics.h}. + * + * <p>In particular these formats are converted: + * <ul> + * <li>ImageFormat.JPEG => HAL_PIXEL_FORMAT_BLOB + * </ul> + * </p> + * + * <p>Passing in an implementation-defined format here will fail (it's not a public format); + * as will passing in an internal format which has a different public format equivalent. + * See {@link #checkArgumentFormat} for more details about a legal public format.</p> + * + * <p>All other formats are returned as-is, no invalid check is performed.</p> + * + * <p>This function is the dual of {@link #imageFormatToPublic}.</p> + * + * @param format public image format from {@link ImageFormat} or {@link PixelFormat} + * @return the converted image formats + * + * @see ImageFormat + * @see PixelFormat + * + * @throws IllegalArgumentException + * if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} + */ + static int imageFormatToInternal(int format) { + switch (format) { + case ImageFormat.JPEG: + return HAL_PIXEL_FORMAT_BLOB; + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + throw new IllegalArgumentException( + "IMPLEMENTATION_DEFINED is not allowed via public API"); + default: + return format; + } + } + + /** + * Convert image formats from public to internal formats (in-place). + * + * @param formats an array of image formats + * @return {@code formats} + * + * @see #imageFormatToInternal + * + * @hide + */ + public static int[] imageFormatToInternal(int[] formats) { + if (formats == null) { + return null; + } + + for (int i = 0; i < formats.length; ++i) { + formats[i] = imageFormatToInternal(formats[i]); + } + + return formats; + } + + private Size[] getPublicFormatSizes(int format, boolean output) { + try { + checkArgumentFormatSupported(format, output); + } catch (IllegalArgumentException e) { + return null; + } + + format = imageFormatToInternal(format); + + return getInternalFormatSizes(format, output); + } + + private Size[] getInternalFormatSizes(int format, boolean output) { + HashMap<Integer, Integer> formatsMap = getFormatsMap(output); + + Integer sizesCount = formatsMap.get(format); + if (sizesCount == null) { + throw new IllegalArgumentException("format not available"); + } + + int len = sizesCount; + Size[] sizes = new Size[len]; + int sizeIndex = 0; + + for (StreamConfiguration config : mConfigurations) { + if (config.getFormat() == format && config.isOutput() == output) { + sizes[sizeIndex++] = config.getSize(); + } + } + + if (sizeIndex != len) { + throw new AssertionError( + "Too few sizes (expected " + len + ", actual " + sizeIndex + ")"); + } + + return sizes; + } + + /** Get the list of publically visible output formats; does not include IMPL_DEFINED */ + private int[] getPublicFormats(boolean output) { + int[] formats = new int[getPublicFormatCount(output)]; + + int i = 0; + + for (int format : getFormatsMap(output).keySet()) { + if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { + formats[i++] = format; + } + } + + if (formats.length != i) { + throw new AssertionError("Too few formats " + i + ", expected " + formats.length); + } + + return imageFormatToPublic(formats); + } + + /** Get the format -> size count map for either output or input formats */ + private HashMap<Integer, Integer> getFormatsMap(boolean output) { + return output ? mOutputFormats : mInputFormats; + } + + private long getInternalFormatDuration(int format, Size size, int duration) { + // assume format is already checked, since its internal + + if (!arrayContains(getInternalFormatSizes(format, /*output*/true), size)) { + throw new IllegalArgumentException("size was not supported"); + } + + StreamConfigurationDuration[] durations = getDurations(duration); + + for (StreamConfigurationDuration configurationDuration : durations) { + if (configurationDuration.getFormat() == format && + configurationDuration.getWidth() == size.getWidth() && + configurationDuration.getHeight() == size.getHeight()) { + return configurationDuration.getDuration(); + } + } + + return getDurationDefault(duration); + } + + /** + * Get the durations array for the kind of duration + * + * @see #DURATION_MIN_FRAME + * @see #DURATION_STALL + * */ + private StreamConfigurationDuration[] getDurations(int duration) { + switch (duration) { + case DURATION_MIN_FRAME: + return mMinFrameDurations; + case DURATION_STALL: + return mStallDurations; + default: + throw new IllegalArgumentException("duration was invalid"); + } + } + + private long getDurationDefault(int duration) { + switch (duration) { + case DURATION_MIN_FRAME: + throw new AssertionError("Minimum frame durations are required to be listed"); + case DURATION_STALL: + return 0L; // OK. A lack of a stall duration implies a 0 stall duration + default: + throw new IllegalArgumentException("duration was invalid"); + } + } + + /** Count the number of publicly-visible output formats */ + private int getPublicFormatCount(boolean output) { + HashMap<Integer, Integer> formatsMap = getFormatsMap(output); + + int size = formatsMap.size(); + if (formatsMap.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) { + size -= 1; + } + return size; + } + + private static <T> boolean arrayContains(T[] array, T element) { + if (array == null) { + return false; + } + + for (T el : array) { + if (Objects.equals(el, element)) { + return true; + } + } + + return false; + } + + // from system/core/include/system/graphics.h + private static final int HAL_PIXEL_FORMAT_BLOB = 0x21; + private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22; + private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24; + + /** + * @see #getDurations(int) + * @see #getDurationDefault(int) + */ + private static final int DURATION_MIN_FRAME = 0; + private static final int DURATION_STALL = 1; + + private final StreamConfiguration[] mConfigurations; + private final StreamConfigurationDuration[] mMinFrameDurations; + private final StreamConfigurationDuration[] mStallDurations; + + /** ImageFormat -> num output sizes mapping */ + private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mOutputFormats = + new HashMap<Integer, Integer>(); + /** ImageFormat -> num input sizes mapping */ + private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mInputFormats = + new HashMap<Integer, Integer>(); + +} diff --git a/core/java/android/hardware/camera2/LongParcelable.aidl b/core/java/android/hardware/camera2/utils/LongParcelable.aidl index 7d7e51b..98ad1b2 100644 --- a/core/java/android/hardware/camera2/LongParcelable.aidl +++ b/core/java/android/hardware/camera2/utils/LongParcelable.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.hardware.camera2; +package android.hardware.camera2.utils; /** @hide */ -parcelable LongParcelable;
\ No newline at end of file +parcelable LongParcelable; diff --git a/core/java/android/hardware/camera2/LongParcelable.java b/core/java/android/hardware/camera2/utils/LongParcelable.java index 97b0631..c89b339 100644 --- a/core/java/android/hardware/camera2/LongParcelable.java +++ b/core/java/android/hardware/camera2/utils/LongParcelable.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.hardware.camera2; +package android.hardware.camera2.utils; import android.os.Parcel; import android.os.Parcelable; diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index 062acaf..fe53a17 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -272,6 +272,7 @@ public class ImageFormat { case NV16: case YUY2: case YV12: + case JPEG: case NV21: case YUV_420_888: case RAW_SENSOR: diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java index b28733a..5ab586f 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java @@ -23,19 +23,21 @@ import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.ColorSpaceTransform; import android.hardware.camera2.Face; import android.hardware.camera2.MeteringRectangle; import android.hardware.camera2.Rational; -import android.hardware.camera2.ReprocessFormatsMap; import android.hardware.camera2.RggbChannelVector; import android.hardware.camera2.Size; -import android.hardware.camera2.StreamConfiguration; -import android.hardware.camera2.StreamConfigurationDuration; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.marshal.impl.MarshalQueryableEnum; +import android.hardware.camera2.params.ReprocessFormatsMap; +import android.hardware.camera2.params.StreamConfiguration; +import android.hardware.camera2.params.StreamConfigurationDuration; +import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.TypeReference; import static android.hardware.camera2.impl.CameraMetadataNative.*; @@ -72,6 +74,9 @@ public class CameraMetadataTest extends junit.framework.TestCase { static final int ANDROID_CONTROL_AE_ANTIBANDING_MODE = ANDROID_CONTROL_START; static final int ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION = ANDROID_CONTROL_START + 1; + // From graphics.h + private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22; + @Override public void setUp() { mMetadata = new CameraMetadataNative(); @@ -293,6 +298,28 @@ public class CameraMetadataTest extends junit.framework.TestCase { } } + private static <T, T2> void assertArrayContains(T needle, T2 array) { + if (!array.getClass().isArray()) { + throw new IllegalArgumentException("actual must be array"); + } + + int len = Array.getLength(array); + for (int i = 0; i < len; ++i) { + + Object actualElement = Array.get(array, i); + + if (needle.equals(actualElement)) { + return; + } + } + + fail(String.format( + "could not find element in array (needle %s). " + + "Array was: %s.", + needle, + formatArray(array, len))); + } + private <T> void checkKeyGetAndSet(String keyStr, TypeReference<T> typeToken, T expected, boolean reuse) { Key<T> key = new Key<T>(keyStr, typeToken); @@ -804,18 +831,48 @@ public class CameraMetadataTest extends junit.framework.TestCase { @SmallTest public void testReadWriteReprocessFormatsMap() { - final int RAW_OPAQUE = 0x24; + // final int RAW_OPAQUE = 0x24; // TODO: add RAW_OPAQUE to ImageFormat final int RAW16 = ImageFormat.RAW_SENSOR; final int YUV_420_888 = ImageFormat.YUV_420_888; final int BLOB = 0x21; + // TODO: also test HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED as an output int[] contents = new int[] { - RAW_OPAQUE, 3, RAW16, YUV_420_888, BLOB, + YUV_420_888, 3, YUV_420_888, ImageFormat.NV21, BLOB, RAW16, 2, YUV_420_888, BLOB, + }; // int32 x n - checkKeyMarshal("android.scaler.availableInputOutputFormatsMap", + Key<ReprocessFormatsMap> key = new Key<ReprocessFormatsMap>( + "android.scaler.availableInputOutputFormatsMap", ReprocessFormatsMap.class); + mMetadata.writeValues(key.getTag(), toByteArray(contents)); + + ReprocessFormatsMap map = mMetadata.get(key); + + /* + * Make sure the inputs/outputs were what we expected. + * - Use public image format constants here. + */ + + int[] expectedInputs = new int[] { + YUV_420_888, RAW16 + }; + assertArrayEquals(expectedInputs, map.getInputs()); + + int[] expectedYuvOutputs = new int[] { + YUV_420_888, ImageFormat.NV21, ImageFormat.JPEG, + }; + assertArrayEquals(expectedYuvOutputs, map.getOutputs(ImageFormat.YUV_420_888)); + + int[] expectedRaw16Outputs = new int[] { + YUV_420_888, ImageFormat.JPEG, + }; + assertArrayEquals(expectedRaw16Outputs, map.getOutputs(ImageFormat.RAW_SENSOR)); + + // Finally, do a round-trip check as a sanity + checkKeyMarshal( + "android.scaler.availableInputOutputFormatsMap", new ReprocessFormatsMap(contents), toByteArray(contents) ); @@ -889,68 +946,6 @@ public class CameraMetadataTest extends junit.framework.TestCase { expectedIntValues, availableFormatTag); // - // android.scaler.availableStreamConfigurations (int x n x 4 array) - // - final int OUTPUT = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT; - int[] availableStreamConfigs = new int[] { - 0x20, 3280, 2464, OUTPUT, // RAW16 - 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888 - 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888 - 0x100, 3264, 2448, OUTPUT, // ImageFormat.JPEG - 0x100, 3200, 2400, OUTPUT, // ImageFormat.JPEG - 0x100, 2592, 1944, OUTPUT, // ImageFormat.JPEG - 0x100, 2048, 1536, OUTPUT, // ImageFormat.JPEG - 0x100, 1920, 1080, OUTPUT // ImageFormat.JPEG - }; - int[] expectedAvailableStreamConfigs = new int[] { - 0x20, 3280, 2464, OUTPUT, // RAW16 - 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888 - 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888 - 0x21, 3264, 2448, OUTPUT, // BLOB - 0x21, 3200, 2400, OUTPUT, // BLOB - 0x21, 2592, 1944, OUTPUT, // BLOB - 0x21, 2048, 1536, OUTPUT, // BLOB - 0x21, 1920, 1080, OUTPUT // BLOB - }; - int availableStreamConfigTag = - CameraMetadataNative.getTag("android.scaler.availableStreamConfigurations"); - - Key<int[]> configKey = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS; - validateArrayMetadataReadWriteOverride(configKey, availableStreamConfigs, - expectedAvailableStreamConfigs, availableStreamConfigTag); - - // - // android.scaler.availableMinFrameDurations (int x n x 4 array) - - // - long[] availableMinDurations = new long[] { - 0x20, 3280, 2464, 33333336, // RAW16 - 0x23, 3264, 2448, 33333336, // YCbCr_420_888 - 0x23, 3200, 2400, 33333336, // YCbCr_420_888 - 0x100, 3264, 2448, 33333336, // ImageFormat.JPEG - 0x100, 3200, 2400, 33333336, // ImageFormat.JPEG - 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG - 0x100, 2048, 1536, 33333336, // ImageFormat.JPEG - 0x100, 1920, 1080, 33333336 // ImageFormat.JPEG - }; - long[] expectedAvailableMinDurations = new long[] { - 0x20, 3280, 2464, 33333336, // RAW16 - 0x23, 3264, 2448, 33333336, // YCbCr_420_888 - 0x23, 3200, 2400, 33333336, // YCbCr_420_888 - 0x21, 3264, 2448, 33333336, // BLOB - 0x21, 3200, 2400, 33333336, // BLOB - 0x21, 2592, 1944, 33333336, // BLOB - 0x21, 2048, 1536, 33333336, // BLOB - 0x21, 1920, 1080, 33333336 // BLOB - }; - int availableMinDurationsTag = - CameraMetadataNative.getTag("android.scaler.availableMinFrameDurations"); - - Key<long[]> durationKey = CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS; - validateArrayMetadataReadWriteOverride(durationKey, availableMinDurations, - expectedAvailableMinDurations, availableMinDurationsTag); - - // // android.statistics.faces (Face x n array) // int[] expectedFaceIds = new int[] {1, 2, 3, 4, 5}; @@ -1015,14 +1010,238 @@ public class CameraMetadataTest extends junit.framework.TestCase { } /** + * Set the raw native value of the available stream configurations; ensure that + * the read-out managed value is consistent with what we write in. + */ + @SmallTest + public void testOverrideStreamConfigurationMap() { + + /* + * First, write all the raw values: + * - availableStreamConfigurations + * - availableMinFrameDurations + * - availableStallDurations + * + * Then, read this out as a synthetic multi-key 'streamConfigurationMap' + * + * Finally, validate that the map was unmarshaled correctly + * and is converting the internal formats to public formats properly. + */ + + // + // android.scaler.availableStreamConfigurations (int x n x 4 array) + // + final int OUTPUT = 0; + final int INPUT = 1; + int[] rawAvailableStreamConfigs = new int[] { + 0x20, 3280, 2464, OUTPUT, // RAW16 + 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888 + 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888 + 0x21, 3264, 2448, OUTPUT, // BLOB + 0x21, 3200, 2400, OUTPUT, // BLOB + 0x21, 2592, 1944, OUTPUT, // BLOB + 0x21, 2048, 1536, OUTPUT, // BLOB + 0x21, 1920, 1080, OUTPUT, // BLOB + 0x22, 640, 480, OUTPUT, // IMPLEMENTATION_DEFINED + 0x20, 320, 240, INPUT, // RAW16 + }; + Key<StreamConfiguration[]> configKey = + CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS; + mMetadata.writeValues(configKey.getTag(), + toByteArray(rawAvailableStreamConfigs)); + + // + // android.scaler.availableMinFrameDurations (int x n x 4 array) + // + long[] expectedAvailableMinDurations = new long[] { + 0x20, 3280, 2464, 33333331, // RAW16 + 0x23, 3264, 2448, 33333332, // YCbCr_420_888 + 0x23, 3200, 2400, 33333333, // YCbCr_420_888 + 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG + 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG + 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG + 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG + 0x100, 1920, 1080, 33333338 // ImageFormat.JPEG + }; + long[] rawAvailableMinDurations = new long[] { + 0x20, 3280, 2464, 33333331, // RAW16 + 0x23, 3264, 2448, 33333332, // YCbCr_420_888 + 0x23, 3200, 2400, 33333333, // YCbCr_420_888 + 0x21, 3264, 2448, 33333334, // BLOB + 0x21, 3200, 2400, 33333335, // BLOB + 0x21, 2592, 1944, 33333336, // BLOB + 0x21, 2048, 1536, 33333337, // BLOB + 0x21, 1920, 1080, 33333338 // BLOB + }; + Key<StreamConfigurationDuration[]> durationKey = + CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS; + mMetadata.writeValues(durationKey.getTag(), + toByteArray(rawAvailableMinDurations)); + + // + // android.scaler.availableStallDurations (int x n x 4 array) + // + long[] expectedAvailableStallDurations = new long[] { + 0x20, 3280, 2464, 0, // RAW16 + 0x23, 3264, 2448, 0, // YCbCr_420_888 + 0x23, 3200, 2400, 0, // YCbCr_420_888 + 0x100, 3264, 2448, 33333334, // ImageFormat.JPEG + 0x100, 3200, 2400, 33333335, // ImageFormat.JPEG + 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG + 0x100, 2048, 1536, 33333337, // ImageFormat.JPEG + 0x100, 1920, 1080, 33333338 // ImageFormat.JPEG + }; + // Note: RAW16 and YUV_420_888 omitted intentionally; omitted values should default to 0 + long[] rawAvailableStallDurations = new long[] { + 0x21, 3264, 2448, 33333334, // BLOB + 0x21, 3200, 2400, 33333335, // BLOB + 0x21, 2592, 1944, 33333336, // BLOB + 0x21, 2048, 1536, 33333337, // BLOB + 0x21, 1920, 1080, 33333338 // BLOB + }; + Key<StreamConfigurationDuration[]> stallDurationKey = + CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS; + mMetadata.writeValues(stallDurationKey.getTag(), + toByteArray(rawAvailableStallDurations)); + + // + // android.scaler.streamConfigurationMap (synthetic as StreamConfigurationMap) + // + StreamConfigurationMap streamConfigMap = mMetadata.get( + CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + + // Inputs + checkStreamConfigurationMapByFormatSize( + streamConfigMap, ImageFormat.RAW_SENSOR, 320, 240, /*output*/false); + + // Outputs + checkStreamConfigurationMapByFormatSize( + streamConfigMap, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, 640, 480, /*output*/true); + checkStreamConfigurationMapByFormatSize( + streamConfigMap, ImageFormat.JPEG, 1920, 1080, /*output*/true); + checkStreamConfigurationMapByFormatSize( + streamConfigMap, ImageFormat.JPEG, 2048, 1536, /*output*/true); + checkStreamConfigurationMapByFormatSize( + streamConfigMap, ImageFormat.JPEG, 2592, 1944, /*output*/true); + checkStreamConfigurationMapByFormatSize( + streamConfigMap, ImageFormat.JPEG, 3200, 2400, /*output*/true); + checkStreamConfigurationMapByFormatSize( + streamConfigMap, ImageFormat.YUV_420_888, 3200, 2400, /*output*/true); + checkStreamConfigurationMapByFormatSize( + streamConfigMap, ImageFormat.YUV_420_888, 3264, 2448, /*output*/true); + checkStreamConfigurationMapByFormatSize( + streamConfigMap, ImageFormat.RAW_SENSOR, 3280, 2464, /*output*/true); + + // Min Frame Durations + + final int DURATION_TUPLE_SIZE = 4; + for (int i = 0; i < expectedAvailableMinDurations.length; i += DURATION_TUPLE_SIZE) { + checkStreamConfigurationMapDurationByFormatSize( + streamConfigMap, + (int)expectedAvailableMinDurations[i], + (int)expectedAvailableMinDurations[i+1], + (int)expectedAvailableMinDurations[i+2], + Duration.MinFrame, + expectedAvailableMinDurations[i+3]); + } + + // Stall Frame Durations + + for (int i = 0; i < expectedAvailableStallDurations.length; i += DURATION_TUPLE_SIZE) { + checkStreamConfigurationMapDurationByFormatSize( + streamConfigMap, + (int)expectedAvailableStallDurations[i], + (int)expectedAvailableStallDurations[i+1], + (int)expectedAvailableStallDurations[i+2], + Duration.Stall, + expectedAvailableStallDurations[i+3]); + } + } + + private static void checkStreamConfigurationMapByFormatSize(StreamConfigurationMap configMap, + int format, int width, int height, + boolean output) { + + /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */ + final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class; + + android.util.Size[] sizes; + int[] formats; + + if (output) { + if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { + sizes = configMap.getOutputSizes(IMPLEMENTATION_DEFINED_OUTPUT_CLASS); + // in this case the 'is output format supported' is vacuously true + formats = new int[] { HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED }; + } else { + sizes = configMap.getOutputSizes(format); + formats = configMap.getOutputFormats(); + assertTrue("Format must be supported by stream configuration map", + configMap.isOutputSupportedFor(format)); + } + } else { + // NOTE: No function to do input sizes from IMPL_DEFINED, so it would just fail for that + sizes = configMap.getInputSizes(format); + formats = configMap.getInputFormats(); + } + + android.util.Size expectedSize = new android.util.Size(width, height); + + assertArrayContains(format, formats); + assertArrayContains(expectedSize, sizes); + } + + private enum Duration { + MinFrame, + Stall + } + + private static void checkStreamConfigurationMapDurationByFormatSize( + StreamConfigurationMap configMap, + int format, int width, int height, Duration durationKind, long expectedDuration) { + + /** arbitrary class for which StreamConfigurationMap#isOutputSupportedFor(Class) is true */ + final Class<?> IMPLEMENTATION_DEFINED_OUTPUT_CLASS = SurfaceTexture.class; + + long actualDuration; + + android.util.Size size = new android.util.Size(width, height); + switch (durationKind) { + case MinFrame: + if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { + actualDuration = configMap.getOutputMinFrameDuration( + IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size); + } else { + actualDuration = configMap.getOutputMinFrameDuration(format, size); + } + + break; + case Stall: + if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { + actualDuration = configMap.getOutputStallDuration( + IMPLEMENTATION_DEFINED_OUTPUT_CLASS, size); + } else { + actualDuration = configMap.getOutputStallDuration(format, size); + } + + break; + default: + throw new AssertionError(); + } + + assertEquals("Expected " + durationKind + " to match actual value", expectedDuration, + actualDuration); + } + + /** * Validate metadata array tag read/write override. * * <p>Only support long and int array for now, can be easily extend to support other * primitive arrays.</p> */ - private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T writeValues, - T readValues, int tag) { - Class<?> type = writeValues.getClass(); + private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T expectedWriteValues, + T expectedReadValues, int tag) { + Class<?> type = expectedWriteValues.getClass(); if (!type.isArray()) { throw new IllegalArgumentException("This function expects an key with array type"); } else if (type != int[].class && type != long[].class) { @@ -1030,13 +1249,13 @@ public class CameraMetadataTest extends junit.framework.TestCase { } // Write - mMetadata.set(key, writeValues); + mMetadata.set(key, expectedWriteValues); byte[] readOutValues = mMetadata.readValues(tag); ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder()); - int readValuesLength = Array.getLength(readValues); + int readValuesLength = Array.getLength(expectedReadValues); int readValuesNumBytes = readValuesLength * 4; if (type == long[].class) { readValuesNumBytes = readValuesLength * 8; @@ -1045,9 +1264,9 @@ public class CameraMetadataTest extends junit.framework.TestCase { assertEquals(readValuesNumBytes, readOutValues.length); for (int i = 0; i < readValuesLength; ++i) { if (type == int[].class) { - assertEquals(Array.getInt(readValues, i), bf.getInt()); + assertEquals(Array.getInt(expectedReadValues, i), bf.getInt()); } else if (type == long[].class) { - assertEquals(Array.getLong(readValues, i), bf.getLong()); + assertEquals(Array.getLong(expectedReadValues, i), bf.getLong()); } } @@ -1057,16 +1276,16 @@ public class CameraMetadataTest extends junit.framework.TestCase { ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder()); for (int i = 0; i < readValuesLength; ++i) { if (type == int[].class) { - readOutValuesByteBuffer.putInt(Array.getInt(readValues, i)); + readOutValuesByteBuffer.putInt(Array.getInt(expectedReadValues, i)); } else if (type == long[].class) { - readOutValuesByteBuffer.putLong(Array.getLong(readValues, i)); + readOutValuesByteBuffer.putLong(Array.getLong(expectedReadValues, i)); } } mMetadata.writeValues(tag, readOutValuesAsByteArray); T result = mMetadata.get(key); assertNotNull(key.getName() + " result shouldn't be null", result); - assertArrayEquals(writeValues, result); + assertArrayEquals(expectedWriteValues, result); } // TODO: move somewhere else |