Loading core/java/android/hardware/camera2/DngCreator.java +33 −2 Original line number Diff line number Diff line Loading @@ -22,12 +22,16 @@ import android.hardware.camera2.impl.CameraMetadataNative; import android.location.Location; import android.media.ExifInterface; import android.media.Image; import android.os.SystemClock; import android.util.Size; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.TimeZone; /** * The {@link DngCreator} class provides functions to write raw pixel data as a DNG file. Loading Loading @@ -55,6 +59,7 @@ import java.nio.ByteBuffer; */ public final class DngCreator implements AutoCloseable { private static final String TAG = "DngCreator"; /** * Create a new DNG object. * Loading @@ -75,7 +80,25 @@ public final class DngCreator implements AutoCloseable { if (characteristics == null || metadata == null) { throw new NullPointerException("Null argument to DngCreator constructor"); } nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy()); // Find current time long currentTime = System.currentTimeMillis(); // Find boot time long bootTimeMillis = currentTime - SystemClock.elapsedRealtime(); // Find capture time (nanos since boot) Long timestamp = metadata.get(CaptureResult.SENSOR_TIMESTAMP); long captureTime = currentTime; if (timestamp != null) { captureTime = timestamp / 1000000 + bootTimeMillis; } // Format for metadata String formattedCaptureTime = sDateTimeStampFormat.format(captureTime); nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy(), formattedCaptureTime); } /** Loading Loading @@ -329,6 +352,13 @@ public final class DngCreator implements AutoCloseable { } } private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd kk:mm:ss"; private static final DateFormat sDateTimeStampFormat = new SimpleDateFormat(TIFF_DATETIME_FORMAT); static { sDateTimeStampFormat.setTimeZone(TimeZone.getDefault()); } /** * This field is used by native code, do not access or modify. */ Loading @@ -337,7 +367,8 @@ public final class DngCreator implements AutoCloseable { private static native void nativeClassInit(); private synchronized native void nativeInit(CameraMetadataNative nativeCharacteristics, CameraMetadataNative nativeResult); CameraMetadataNative nativeResult, String captureTime); private synchronized native void nativeDestroy(); Loading core/jni/android_hardware_camera2_DngCreator.cpp +175 −3 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -175,7 +177,7 @@ static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) { } static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr, jobject resultsPtr) { jobject resultsPtr, jstring formattedCaptureTime) { ALOGV("%s:", __FUNCTION__); CameraMetadata characteristics; CameraMetadata results; Loading Loading @@ -205,7 +207,6 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB; // TODO: Greensplit. // TODO: UniqueCameraModel // TODO: Add remaining non-essential tags { // Set orientation Loading Loading @@ -351,6 +352,176 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt env, TAG_CFALAYOUT); } { // 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}; Loading Loading @@ -751,7 +922,8 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject 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", Loading Loading
core/java/android/hardware/camera2/DngCreator.java +33 −2 Original line number Diff line number Diff line Loading @@ -22,12 +22,16 @@ import android.hardware.camera2.impl.CameraMetadataNative; import android.location.Location; import android.media.ExifInterface; import android.media.Image; import android.os.SystemClock; import android.util.Size; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.TimeZone; /** * The {@link DngCreator} class provides functions to write raw pixel data as a DNG file. Loading Loading @@ -55,6 +59,7 @@ import java.nio.ByteBuffer; */ public final class DngCreator implements AutoCloseable { private static final String TAG = "DngCreator"; /** * Create a new DNG object. * Loading @@ -75,7 +80,25 @@ public final class DngCreator implements AutoCloseable { if (characteristics == null || metadata == null) { throw new NullPointerException("Null argument to DngCreator constructor"); } nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy()); // Find current time long currentTime = System.currentTimeMillis(); // Find boot time long bootTimeMillis = currentTime - SystemClock.elapsedRealtime(); // Find capture time (nanos since boot) Long timestamp = metadata.get(CaptureResult.SENSOR_TIMESTAMP); long captureTime = currentTime; if (timestamp != null) { captureTime = timestamp / 1000000 + bootTimeMillis; } // Format for metadata String formattedCaptureTime = sDateTimeStampFormat.format(captureTime); nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy(), formattedCaptureTime); } /** Loading Loading @@ -329,6 +352,13 @@ public final class DngCreator implements AutoCloseable { } } private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd kk:mm:ss"; private static final DateFormat sDateTimeStampFormat = new SimpleDateFormat(TIFF_DATETIME_FORMAT); static { sDateTimeStampFormat.setTimeZone(TimeZone.getDefault()); } /** * This field is used by native code, do not access or modify. */ Loading @@ -337,7 +367,8 @@ public final class DngCreator implements AutoCloseable { private static native void nativeClassInit(); private synchronized native void nativeInit(CameraMetadataNative nativeCharacteristics, CameraMetadataNative nativeResult); CameraMetadataNative nativeResult, String captureTime); private synchronized native void nativeDestroy(); Loading
core/jni/android_hardware_camera2_DngCreator.cpp +175 −3 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -175,7 +177,7 @@ static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) { } static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr, jobject resultsPtr) { jobject resultsPtr, jstring formattedCaptureTime) { ALOGV("%s:", __FUNCTION__); CameraMetadata characteristics; CameraMetadata results; Loading Loading @@ -205,7 +207,6 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB; // TODO: Greensplit. // TODO: UniqueCameraModel // TODO: Add remaining non-essential tags { // Set orientation Loading Loading @@ -351,6 +352,176 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt env, TAG_CFALAYOUT); } { // 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}; Loading Loading @@ -751,7 +922,8 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject 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", Loading