diff options
| author | 2016-03-02 15:52:08 -0800 | |
|---|---|---|
| committer | 2016-03-04 11:22:15 -0800 | |
| commit | 8069b1f252d6a1e1c469dfc733bdd0db5d69574f (patch) | |
| tree | e7373bb6d0cce7f6abbb3dd796969082ce0352d7 | |
| parent | 1ca7c808447737fb38330a013dae5ab21deea9b9 (diff) | |
DngCreator: Improve BlackLevel, fix thumbnail metadata
- Use new dynamic black level result key when available
- Write rational black level instead of integral value
- Fix incorrect thumbnail BitsPerSample metadata
- Fix incorrect date/time format string
- Fix unknown orientation
Test: dng_validate for captured DNGs is clean
Bug: 27452979
Bug: 25862995
Change-Id: I87b73f7a4f4ecc3cf6498c7db16df68dd0b0b43a
| -rw-r--r-- | core/java/android/hardware/camera2/DngCreator.java | 10 | ||||
| -rw-r--r-- | core/jni/android_hardware_camera2_DngCreator.cpp | 44 |
2 files changed, 43 insertions, 11 deletions
diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java index 57a080b9346b..9478dc002d6c 100644 --- a/core/java/android/hardware/camera2/DngCreator.java +++ b/core/java/android/hardware/camera2/DngCreator.java @@ -137,6 +137,11 @@ public final class DngCreator implements AutoCloseable { throw new IllegalArgumentException("Orientation " + orientation + " is not a valid EXIF orientation value"); } + // ExifInterface and TIFF/EP spec differ on definition of + // "Unknown" orientation; other values map directly + if (orientation == ExifInterface.ORIENTATION_UNDEFINED) { + orientation = TAG_ORIENTATION_UNKNOWN; + } nativeSetOrientation(orientation); return this; } @@ -443,7 +448,7 @@ public final class DngCreator implements AutoCloseable { private static final String GPS_LONG_REF_WEST = "W"; private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd"; - private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd kk:mm:ss"; + private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss"; private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR); private static final DateFormat sDateTimeStampFormat = new SimpleDateFormat(TIFF_DATETIME_FORMAT); @@ -458,6 +463,9 @@ public final class DngCreator implements AutoCloseable { private static final int DEFAULT_PIXEL_STRIDE = 2; // bytes per sample private static final int BYTES_PER_RGB_PIX = 3; // byts per pixel + // TIFF tag values needed to map between public API and TIFF spec + private static final int TAG_ORIENTATION_UNKNOWN = 9; + /** * Offset, rowStride, and pixelStride are given in bytes. Height and width are given in pixels. */ diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index cb0abb6bfaa8..c6baf1c645bf 100644 --- a/core/jni/android_hardware_camera2_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -80,6 +80,13 @@ using namespace img_utils; return nullptr; \ } +#define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \ + if (expr) { \ + jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ + "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ + return nullptr; \ + } + #define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext" @@ -195,8 +202,8 @@ private: NativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) : mCharacteristics(std::make_shared<CameraMetadata>(characteristics)), mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0), - mThumbnailHeight(0), mOrientation(0), mThumbnailSet(false), mGpsSet(false), - mDescriptionSet(false), mCaptureTimeSet(false) {} + mThumbnailHeight(0), mOrientation(TAG_ORIENTATION_UNKNOWN), mThumbnailSet(false), + mGpsSet(false), mDescriptionSet(false), mCaptureTimeSet(false) {} NativeContext::~NativeContext() {} @@ -1096,7 +1103,7 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image { // Set orientation - uint16_t orientation = 1; // Normal + uint16_t orientation = TAG_ORIENTATION_NORMAL; BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env, TAG_ORIENTATION, writer); } @@ -1138,12 +1145,27 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image } { - // Set blacklevel tags + // Set blacklevel tags, using dynamic black level if available camera_metadata_entry entry = - characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN); - BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BLACKLEVEL, writer); - const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32); - BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, + results.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL); + uint32_t blackLevelRational[8] = {0}; + if (entry.count != 0) { + BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer); + for (size_t i = 0; i < entry.count; i++) { + blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.f[i] * 100); + blackLevelRational[i * 2 + 1] = 100; + } + } else { + // Fall back to static black level which is guaranteed + entry = characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN); + BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer); + for (size_t i = 0; i < entry.count; i++) { + blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.i32[i]); + blackLevelRational[i * 2 + 1] = 1; + } + + } + BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, 4, blackLevelRational, TIFF_IFD_0), env, TAG_BLACKLEVEL, writer); uint16_t repeatDim[2] = {2, 2}; @@ -1913,8 +1935,10 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image { // Set bits per sample - uint16_t bits = BITS_PER_RGB_SAMPLE; - BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), + uint16_t bits[SAMPLES_PER_RGB_PIXEL]; + for (int i = 0; i < SAMPLES_PER_RGB_PIXEL; i++) bits[i] = BITS_PER_RGB_SAMPLE; + BAIL_IF_INVALID_RET_NULL_SP( + writer->addEntry(TAG_BITSPERSAMPLE, SAMPLES_PER_RGB_PIXEL, bits, TIFF_IFD_0), env, TAG_BITSPERSAMPLE, writer); } |