diff options
-rw-r--r-- | core/java/android/hardware/camera2/impl/CameraMetadataNative.java | 92 | ||||
-rw-r--r-- | media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java | 136 |
2 files changed, 209 insertions, 19 deletions
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 0d4a4cb..c5e5753 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -461,6 +461,10 @@ 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(); } // For other keys, get() falls back to getBase() @@ -481,6 +485,50 @@ 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; @@ -607,12 +655,56 @@ 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/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java index 26498ca..edfa36a 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java @@ -552,29 +552,72 @@ public class CameraMetadataTest extends junit.framework.TestCase { }; int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats"); - // Write - mMetadata.set(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, availableFormats); + Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS; - byte[] availableFormatValues = mMetadata.readValues(availableFormatTag); + validateArrayMetadataReadWriteOverride(formatKey, availableFormats, + expectedIntValues, availableFormatTag); - ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder()); + // + // 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"); - assertEquals(expectedIntValues.length * 4, availableFormatValues.length); - for (int i = 0; i < expectedIntValues.length; ++i) { - assertEquals(expectedIntValues[i], bf.getInt()); - } - // Read - byte[] availableFormatsAsByteArray = new byte[expectedIntValues.length * 4]; - ByteBuffer availableFormatsByteBuffer = - ByteBuffer.wrap(availableFormatsAsByteArray).order(ByteOrder.nativeOrder()); - for (int value : expectedIntValues) { - availableFormatsByteBuffer.putInt(value); - } - mMetadata.writeValues(availableFormatTag, availableFormatsAsByteArray); + Key<int[]> configKey = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS; + validateArrayMetadataReadWriteOverride(configKey, availableStreamConfigs, + expectedAvailableStreamConfigs, availableStreamConfigTag); - int[] resultFormats = mMetadata.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS); - assertNotNull("result available formats shouldn't be null", resultFormats); - assertArrayEquals(availableFormats, resultFormats); + // + // 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) @@ -639,4 +682,59 @@ public class CameraMetadataTest extends junit.framework.TestCase { } } + + /** + * 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<T> type = key.getType(); + if (!type.isArray()) { + throw new IllegalArgumentException("This function expects an key with array type"); + } else if (type != int[].class && type != long[].class) { + throw new IllegalArgumentException("This function expects long or int array values"); + } + + // Write + mMetadata.set(key, writeValues); + + byte[] readOutValues = mMetadata.readValues(tag); + + ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder()); + + int readValuesLength = Array.getLength(readValues); + int readValuesNumBytes = readValuesLength * 4; + if (type == long[].class) { + readValuesNumBytes = readValuesLength * 8; + } + + assertEquals(readValuesNumBytes, readOutValues.length); + for (int i = 0; i < readValuesLength; ++i) { + if (type == int[].class) { + assertEquals(Array.getInt(readValues, i), bf.getInt()); + } else if (type == long[].class) { + assertEquals(Array.getLong(readValues, i), bf.getLong()); + } + } + + // Read + byte[] readOutValuesAsByteArray = new byte[readValuesNumBytes]; + ByteBuffer readOutValuesByteBuffer = + ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder()); + for (int i = 0; i < readValuesLength; ++i) { + if (type == int[].class) { + readOutValuesByteBuffer.putInt(Array.getInt(readValues, i)); + } else if (type == long[].class) { + readOutValuesByteBuffer.putLong(Array.getLong(readValues, i)); + } + } + mMetadata.writeValues(tag, readOutValuesAsByteArray); + + T result = mMetadata.get(key); + assertNotNull(key.getName() + " result shouldn't be null", result); + assertArrayEquals(writeValues, result); + } } |