DNG: Write out additional fields.
Bug: 15112503
Change-Id: Ib06d9a5e70e6e3d5063a95a7109538ef64f03334
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 7b686e7..33100bf 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -31,6 +31,8 @@
#include <utils/RefBase.h>
#include <cutils/properties.h>
+#include <string.h>
+
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
@@ -175,7 +177,7 @@
}
static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr,
- jobject resultsPtr) {
+ jobject resultsPtr, jstring formattedCaptureTime) {
ALOGV("%s:", __FUNCTION__);
CameraMetadata characteristics;
CameraMetadata results;
@@ -205,7 +207,6 @@
OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
// TODO: Greensplit.
- // TODO: UniqueCameraModel
// TODO: Add remaining non-essential tags
{
// Set orientation
@@ -352,6 +353,176 @@
}
{
+ // image description
+ uint8_t imageDescription = '\0'; // empty
+ BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription, TIFF_IFD_0),
+ env, TAG_IMAGEDESCRIPTION);
+ }
+
+ {
+ // make
+ char manufacturer[PROPERTY_VALUE_MAX];
+
+ // Use "" to represent unknown make as suggested in TIFF/EP spec.
+ property_get("ro.product.manufacturer", manufacturer, "");
+ uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1;
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_MAKE, count, reinterpret_cast<uint8_t*>(manufacturer),
+ TIFF_IFD_0), env, TAG_MAKE);
+ }
+
+ {
+ // model
+ char model[PROPERTY_VALUE_MAX];
+
+ // Use "" to represent unknown model as suggested in TIFF/EP spec.
+ property_get("ro.product.model", model, "");
+ uint32_t count = static_cast<uint32_t>(strlen(model)) + 1;
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_MODEL, count, reinterpret_cast<uint8_t*>(model),
+ TIFF_IFD_0), env, TAG_MODEL);
+ }
+
+ {
+ // x resolution
+ uint32_t xres[] = { 72, 1 }; // default 72 ppi
+ BAIL_IF_INVALID(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
+ env, TAG_XRESOLUTION);
+
+ // y resolution
+ uint32_t yres[] = { 72, 1 }; // default 72 ppi
+ BAIL_IF_INVALID(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
+ env, TAG_YRESOLUTION);
+
+ uint16_t unit = 2; // inches
+ BAIL_IF_INVALID(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
+ env, TAG_RESOLUTIONUNIT);
+ }
+
+ {
+ // software
+ char software[PROPERTY_VALUE_MAX];
+ property_get("ro.build.fingerprint", software, "");
+ uint32_t count = static_cast<uint32_t>(strlen(software)) + 1;
+ BAIL_IF_INVALID(writer->addEntry(TAG_SOFTWARE, count, reinterpret_cast<uint8_t*>(software),
+ TIFF_IFD_0), env, TAG_SOFTWARE);
+ }
+
+ {
+ // datetime
+ const size_t DATETIME_COUNT = 20;
+ const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, NULL);
+
+ size_t len = strlen(captureTime) + 1;
+ if (len != DATETIME_COUNT) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Timestamp string length is not required 20 characters");
+ return;
+ }
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_DATETIME, DATETIME_COUNT,
+ reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0), env, TAG_DATETIMEORIGINAL);
+
+ // datetime original
+ BAIL_IF_INVALID(writer->addEntry(TAG_DATETIMEORIGINAL, DATETIME_COUNT,
+ reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0), env, TAG_DATETIMEORIGINAL);
+ env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
+ }
+
+ {
+ // TIFF/EP standard id
+ uint8_t standardId[] = { 1, 0, 0, 0 };
+ BAIL_IF_INVALID(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId,
+ TIFF_IFD_0), env, TAG_TIFFEPSTANDARDID);
+ }
+
+ {
+ // copyright
+ uint8_t copyright = '\0'; // empty
+ BAIL_IF_INVALID(writer->addEntry(TAG_COPYRIGHT, 1, ©right,
+ TIFF_IFD_0), env, TAG_COPYRIGHT);
+ }
+
+ {
+ // exposure time
+ camera_metadata_entry entry =
+ results.find(ANDROID_SENSOR_EXPOSURE_TIME);
+ BAIL_IF_EMPTY(entry, env, TAG_EXPOSURETIME);
+
+ int64_t exposureTime = *(entry.data.i64);
+
+ if (exposureTime < 0) {
+ // Should be unreachable
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Negative exposure time in metadata");
+ return;
+ }
+
+ // Ensure exposure time doesn't overflow (for exposures > 4s)
+ uint32_t denominator = 1000000000;
+ while (exposureTime > UINT32_MAX) {
+ exposureTime >>= 1;
+ denominator >>= 1;
+ if (denominator == 0) {
+ // Should be unreachable
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Exposure time too long");
+ return;
+ }
+ }
+
+ uint32_t exposure[] = { static_cast<uint32_t>(exposureTime), denominator };
+ BAIL_IF_INVALID(writer->addEntry(TAG_EXPOSURETIME, 1, exposure,
+ TIFF_IFD_0), env, TAG_EXPOSURETIME);
+
+ }
+
+ {
+ // ISO speed ratings
+ camera_metadata_entry entry =
+ results.find(ANDROID_SENSOR_SENSITIVITY);
+ BAIL_IF_EMPTY(entry, env, TAG_ISOSPEEDRATINGS);
+
+ int32_t tempIso = *(entry.data.i32);
+ if (tempIso < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Negative ISO value");
+ return;
+ }
+
+ if (tempIso > UINT16_MAX) {
+ ALOGW("%s: ISO value overflows UINT16_MAX, clamping to max", __FUNCTION__);
+ tempIso = UINT16_MAX;
+ }
+
+ uint16_t iso = static_cast<uint16_t>(tempIso);
+ BAIL_IF_INVALID(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso,
+ TIFF_IFD_0), env, TAG_ISOSPEEDRATINGS);
+ }
+
+ {
+ // focal length
+ camera_metadata_entry entry =
+ results.find(ANDROID_LENS_FOCAL_LENGTH);
+ BAIL_IF_EMPTY(entry, env, TAG_FOCALLENGTH);
+
+ uint32_t focalLength[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
+ BAIL_IF_INVALID(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength,
+ TIFF_IFD_0), env, TAG_FOCALLENGTH);
+ }
+
+ {
+ // f number
+ camera_metadata_entry entry =
+ results.find(ANDROID_LENS_APERTURE);
+ BAIL_IF_EMPTY(entry, env, TAG_FNUMBER);
+
+ uint32_t fnum[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
+ BAIL_IF_INVALID(writer->addEntry(TAG_FNUMBER, 1, fnum,
+ TIFF_IFD_0), env, TAG_FNUMBER);
+ }
+
+ {
// Set DNG version information
uint8_t version[4] = {1, 4, 0, 0};
BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
@@ -751,7 +922,8 @@
static JNINativeMethod gDngCreatorMethods[] = {
{"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit},
{"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
- "Landroid/hardware/camera2/impl/CameraMetadataNative;)V", (void*) DngCreator_init},
+ "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V",
+ (void*) DngCreator_init},
{"nativeDestroy", "()V", (void*) DngCreator_destroy},
{"nativeSetOrientation", "(I)V", (void*) DngCreator_nativeSetOrientation},
{"nativeSetThumbnailBitmap","(Landroid/graphics/Bitmap;)V",