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

This commit is contained in:
Jayant Chowdhary
2021-05-21 17:06:41 +00:00
committed by Android (Google) Code Review

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,15 +1334,18 @@ 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]);
if (!((imageWidth == preWidth && imageHeight == preHeight) || if (!((imageWidth == preWidth && imageHeight == preHeight) ||
(imageWidth == pixWidth && imageHeight == pixHeight))) { (imageWidth == pixWidth && imageHeight == pixHeight))) {
jniThrowException(env, "java/lang/AssertionError", jniThrowException(env, "java/lang/AssertionError",
"Height and width of image buffer did not match height and width of" "Height and width of image buffer did not match height and width of"
"either the preCorrectionActiveArraySize or the pixelArraySize."); " either the preCorrectionActiveArraySize or the pixelArraySize.");
return nullptr; return nullptr;
} }
@@ -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);