Merge "DngCreator : Add support for maximum resolution mode captures for ultra high resolution sensors." into sc-dev am: 0c9840906a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14454327

Change-Id: I6fa81712517856d8db0157279a8ffcf169f61ec6
This commit is contained in:
Jayant Chowdhary
2021-05-21 17:11:38 +00:00
committed by Automerger Merge Worker

View File

@@ -83,6 +83,22 @@ using android::base::GetProperty;
return nullptr; \ return nullptr; \
} }
#define BAIL_IF_EMPTY_RET_BOOL(entry, jnienv, tagId, writer) \
if ((entry).count == 0) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
"Missing metadata fields for tag %s (%x)", \
(writer)->getTagName(tagId), (tagId)); \
return false; \
}
#define BAIL_IF_EMPTY_RET_STATUS(entry, jnienv, tagId, writer) \
if ((entry).count == 0) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
"Missing metadata fields for tag %s (%x)", \
(writer)->getTagName(tagId), (tagId)); \
return BAD_VALUE; \
}
#define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \ #define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \
if (expr) { \ if (expr) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
@@ -764,15 +780,76 @@ uint32_t DirectStripSource::getIfd() const {
// End of DirectStripSource // End of DirectStripSource
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Get the appropriate tag corresponding to default / maximum resolution mode.
static int32_t getAppropriateModeTag(int32_t tag, bool maximumResolution) {
if (!maximumResolution) {
return tag;
}
switch (tag) {
case ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE:
return ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION;
case ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE:
return ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION;
case ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE:
return ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION;
default:
ALOGE("%s: Tag %d doesn't have sensor info related maximum resolution counterpart",
__FUNCTION__, tag);
return -1;
}
}
static bool isMaximumResolutionModeImage(const CameraMetadata& characteristics, uint32_t imageWidth,
uint32_t imageHeight, const sp<TiffWriter> writer,
JNIEnv* env) {
// If this isn't an ultra-high resolution sensor, return false;
camera_metadata_ro_entry capabilitiesEntry =
characteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
size_t capsCount = capabilitiesEntry.count;
const uint8_t* caps = capabilitiesEntry.data.u8;
if (std::find(caps, caps + capsCount,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) ==
caps + capsCount) {
// not an ultra-high resolution sensor, cannot have a maximum resolution
// mode image.
return false;
}
// If the image width and height are either the maximum resolution
// pre-correction active array size or the maximum resolution pixel array
// size, this image is a maximum resolution RAW_SENSOR image.
// Check dimensions
camera_metadata_ro_entry entry = characteristics.find(
ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION);
BAIL_IF_EMPTY_RET_BOOL(entry, env, TAG_IMAGEWIDTH, writer);
uint32_t preWidth = static_cast<uint32_t>(entry.data.i32[2]);
uint32_t preHeight = static_cast<uint32_t>(entry.data.i32[3]);
camera_metadata_ro_entry pixelArrayEntry =
characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION);
BAIL_IF_EMPTY_RET_BOOL(pixelArrayEntry, env, TAG_IMAGEWIDTH, writer);
uint32_t pixWidth = static_cast<uint32_t>(pixelArrayEntry.data.i32[0]);
uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]);
return (imageWidth == preWidth && imageHeight == preHeight) ||
(imageWidth == pixWidth && imageHeight == pixHeight);
}
/** /**
* Calculate the default crop relative to the "active area" of the image sensor (this active area * Calculate the default crop relative to the "active area" of the image sensor (this active area
* will always be the pre-correction active area rectangle), and set this. * will always be the pre-correction active area rectangle), and set this.
*/ */
static status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics, static status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics,
sp<TiffWriter> writer) { sp<TiffWriter> writer, bool maximumResolutionMode) {
camera_metadata_ro_entry entry = characteristics.find(
camera_metadata_ro_entry entry = getAppropriateModeTag(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); maximumResolutionMode));
BAIL_IF_EMPTY_RET_STATUS(entry, env, TAG_IMAGEWIDTH, writer);
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
@@ -811,11 +888,18 @@ static bool validateDngHeader(JNIEnv* env, sp<TiffWriter> writer,
"Image height %d is invalid", height); "Image height %d is invalid", height);
return false; return false;
} }
bool isMaximumResolutionMode =
isMaximumResolutionModeImage(characteristics, static_cast<uint32_t>(width),
static_cast<uint32_t>(height), writer, env);
camera_metadata_ro_entry preCorrectionEntry = camera_metadata_ro_entry preCorrectionEntry = characteristics.find(
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); getAppropriateModeTag(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
camera_metadata_ro_entry pixelArrayEntry = isMaximumResolutionMode));
characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE); BAIL_IF_EMPTY_RET_BOOL(preCorrectionEntry, env, TAG_IMAGEWIDTH, writer);
camera_metadata_ro_entry pixelArrayEntry = characteristics.find(
getAppropriateModeTag(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, isMaximumResolutionMode));
BAIL_IF_EMPTY_RET_BOOL(pixelArrayEntry, env, TAG_IMAGEWIDTH, writer);
int pWidth = static_cast<int>(pixelArrayEntry.data.i32[0]); int pWidth = static_cast<int>(pixelArrayEntry.data.i32[0]);
int pHeight = static_cast<int>(pixelArrayEntry.data.i32[1]); int pHeight = static_cast<int>(pixelArrayEntry.data.i32[1]);
@@ -1236,10 +1320,13 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
uint32_t preHeight = 0; uint32_t preHeight = 0;
uint8_t colorFilter = 0; uint8_t colorFilter = 0;
bool isBayer = true; bool isBayer = true;
bool isMaximumResolutionMode =
isMaximumResolutionModeImage(characteristics, imageWidth, imageHeight, writer, env);
{ {
// Check dimensions // Check dimensions
camera_metadata_entry entry = camera_metadata_entry entry = characteristics.find(
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); getAppropriateModeTag(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
isMaximumResolutionMode));
BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer); BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer);
preXMin = static_cast<uint32_t>(entry.data.i32[0]); preXMin = static_cast<uint32_t>(entry.data.i32[0]);
preYMin = static_cast<uint32_t>(entry.data.i32[1]); preYMin = static_cast<uint32_t>(entry.data.i32[1]);
@@ -1247,7 +1334,10 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
preHeight = static_cast<uint32_t>(entry.data.i32[3]); preHeight = static_cast<uint32_t>(entry.data.i32[3]);
camera_metadata_entry pixelArrayEntry = camera_metadata_entry pixelArrayEntry =
characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE); characteristics.find(getAppropriateModeTag(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
isMaximumResolutionMode));
BAIL_IF_EMPTY_RET_NULL_SP(pixelArrayEntry, env, TAG_IMAGEWIDTH, writer);
uint32_t pixWidth = static_cast<uint32_t>(pixelArrayEntry.data.i32[0]); uint32_t pixWidth = static_cast<uint32_t>(pixelArrayEntry.data.i32[0]);
uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]); uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]);
@@ -1773,11 +1863,12 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
{ {
// Set dimensions // Set dimensions
if (calculateAndSetCrop(env, characteristics, writer) != OK) { if (calculateAndSetCrop(env, characteristics, writer, isMaximumResolutionMode) != OK) {
return nullptr; return nullptr;
} }
camera_metadata_entry entry = camera_metadata_entry entry = characteristics.find(
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); getAppropriateModeTag(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
isMaximumResolutionMode));
BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ACTIVEAREA, writer); BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ACTIVEAREA, writer);
uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
@@ -1872,8 +1963,9 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
camera_metadata_entry entry2 = results.find(ANDROID_STATISTICS_LENS_SHADING_MAP); camera_metadata_entry entry2 = results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
camera_metadata_entry entry = camera_metadata_entry entry = characteristics.find(
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); getAppropriateModeTag(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
isMaximumResolutionMode));
BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer); BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer);
uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
@@ -1899,7 +1991,12 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
// Hot pixel map is specific to bayer camera per DNG spec. // Hot pixel map is specific to bayer camera per DNG spec.
if (isBayer) { if (isBayer) {
// Set up bad pixel correction list // Set up bad pixel correction list
camera_metadata_entry entry3 = characteristics.find(ANDROID_STATISTICS_HOT_PIXEL_MAP); // We first check the capture result. If the hot pixel map is not
// available, as a fallback, try the static characteristics.
camera_metadata_entry entry3 = results.find(ANDROID_STATISTICS_HOT_PIXEL_MAP);
if (entry3.count == 0) {
entry3 = characteristics.find(ANDROID_STATISTICS_HOT_PIXEL_MAP);
}
if ((entry3.count % 2) != 0) { if ((entry3.count % 2) != 0) {
ALOGE("%s: Hot pixel map contains odd number of values, cannot map to pairs!", ALOGE("%s: Hot pixel map contains odd number of values, cannot map to pairs!",
@@ -1908,7 +2005,8 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
return nullptr; return nullptr;
} }
// Adjust the bad pixel coordinates to be relative to the origin of the active area DNG tag // Adjust the bad pixel coordinates to be relative to the origin of the active area
// DNG tag
std::vector<uint32_t> v; std::vector<uint32_t> v;
for (size_t i = 0; i < entry3.count; i += 2) { for (size_t i = 0; i < entry3.count; i += 2) {
int32_t x = entry3.data.i32[i]; int32_t x = entry3.data.i32[i];
@@ -1962,6 +2060,8 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
std::array<float, 6> distortion = {1.f, 0.f, 0.f, 0.f, 0.f, 0.f}; std::array<float, 6> distortion = {1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
bool gotDistortion = false; bool gotDistortion = false;
// The capture result would have the correct intrinsic calibration
// regardless of the sensor pixel mode.
camera_metadata_entry entry4 = camera_metadata_entry entry4 =
results.find(ANDROID_LENS_INTRINSIC_CALIBRATION); results.find(ANDROID_LENS_INTRINSIC_CALIBRATION);