summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
authorRuben Brunk <rubenbrunk@google.com>2014-08-26 06:55:25 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-08-26 06:55:26 +0000
commit6d388af85379f4d534002118caa9ba4f7812e049 (patch)
treee362c2368d678501d6d481b52cfbe7b4dbb981ce /core/jni
parented25dda8ba5b1be9bd050939deca82bf6506a09b (diff)
parentd70132c373eee01b4e0a35250bd4246672e7a02e (diff)
downloadframeworks_base-6d388af85379f4d534002118caa9ba4f7812e049.zip
frameworks_base-6d388af85379f4d534002118caa9ba4f7812e049.tar.gz
frameworks_base-6d388af85379f4d534002118caa9ba4f7812e049.tar.bz2
Merge "camera2: Fix number of DNG NoiseProfile coeffs." into lmp-dev
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/android_hardware_camera2_DngCreator.cpp194
1 files changed, 153 insertions, 41 deletions
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index a728455..31c7b9f 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -653,6 +653,119 @@ static status_t moveEntries(TiffWriter* writer, uint32_t ifdFrom, uint32_t ifdTo
return OK;
}
+/**
+ * Write CFA pattern for given CFA enum into cfaOut. cfaOut must have length >= 4.
+ * Returns OK on success, or a negative error code if the CFA enum was invalid.
+ */
+static status_t convertCFA(uint8_t cfaEnum, /*out*/uint8_t* cfaOut) {
+ camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
+ static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
+ cfaEnum);
+ switch(cfa) {
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
+ cfaOut[0] = 0;
+ cfaOut[1] = 1;
+ cfaOut[2] = 1;
+ cfaOut[3] = 2;
+ break;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
+ cfaOut[0] = 1;
+ cfaOut[1] = 0;
+ cfaOut[2] = 2;
+ cfaOut[3] = 1;
+ break;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
+ cfaOut[0] = 1;
+ cfaOut[1] = 2;
+ cfaOut[2] = 0;
+ cfaOut[3] = 1;
+ break;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
+ cfaOut[0] = 2;
+ cfaOut[1] = 1;
+ cfaOut[2] = 1;
+ cfaOut[3] = 0;
+ break;
+ }
+ default: {
+ return BAD_VALUE;
+ }
+ }
+ return OK;
+}
+
+/**
+ * Convert the CFA layout enum to an OpcodeListBuilder::CfaLayout enum, defaults to
+ * RGGB for an unknown enum.
+ */
+static OpcodeListBuilder::CfaLayout convertCFAEnumToOpcodeLayout(uint8_t cfaEnum) {
+ camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
+ static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
+ cfaEnum);
+ switch(cfa) {
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
+ return OpcodeListBuilder::CFA_RGGB;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
+ return OpcodeListBuilder::CFA_GRBG;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
+ return OpcodeListBuilder::CFA_GBRG;
+ }
+ case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
+ return OpcodeListBuilder::CFA_BGGR;
+ }
+ default: {
+ return OpcodeListBuilder::CFA_RGGB;
+ }
+ }
+}
+
+/**
+ * For each color plane, find the corresponding noise profile coefficients given in the
+ * per-channel noise profile. If multiple channels in the CFA correspond to a color in the color
+ * plane, this method takes the pair of noise profile coefficients with the higher S coefficient.
+ *
+ * perChannelNoiseProfile - numChannels * 2 noise profile coefficients.
+ * cfa - numChannels color channels corresponding to each of the per-channel noise profile
+ * coefficients.
+ * numChannels - the number of noise profile coefficient pairs and color channels given in
+ * the perChannelNoiseProfile and cfa arguments, respectively.
+ * planeColors - the color planes in the noise profile output.
+ * numPlanes - the number of planes in planeColors and pairs of coefficients in noiseProfile.
+ * noiseProfile - 2 * numPlanes doubles containing numPlanes pairs of noise profile coefficients.
+ *
+ * returns OK, or a negative error code on failure.
+ */
+static status_t generateNoiseProfile(const double* perChannelNoiseProfile, uint8_t* cfa,
+ size_t numChannels, const uint8_t* planeColors, size_t numPlanes,
+ /*out*/double* noiseProfile) {
+
+ for (size_t p = 0; p < numPlanes; ++p) {
+ size_t S = p * 2;
+ size_t O = p * 2 + 1;
+
+ noiseProfile[S] = 0;
+ noiseProfile[O] = 0;
+ bool uninitialized = true;
+ for (size_t c = 0; c < numChannels; ++c) {
+ if (cfa[c] == planeColors[p] && perChannelNoiseProfile[c * 2] > noiseProfile[S]) {
+ noiseProfile[S] = perChannelNoiseProfile[c * 2];
+ noiseProfile[O] = perChannelNoiseProfile[c * 2 + 1];
+ uninitialized = false;
+ }
+ }
+ if (uninitialized) {
+ ALOGE("%s: No valid NoiseProfile coefficients for color plane %u", __FUNCTION__, p);
+ return BAD_VALUE;
+ }
+ }
+ return OK;
+}
+
// ----------------------------------------------------------------------------
extern "C" {
@@ -745,6 +858,8 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
uint32_t imageHeight = 0;
OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
+ uint8_t cfaPlaneColor[3] = {0, 1, 2};
+ uint8_t cfaEnum = -1;
// TODO: Greensplit.
// TODO: Add remaining non-essential tags
@@ -841,49 +956,23 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN, writer);
- camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
- static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
- entry.data.u8[0]);
- switch(cfa) {
- case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
- uint8_t cfa[4] = {0, 1, 1, 2};
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
- env, TAG_CFAPATTERN, writer);
- opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
- break;
- }
- case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
- uint8_t cfa[4] = {1, 0, 2, 1};
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
- env, TAG_CFAPATTERN, writer);
- opcodeCfaLayout = OpcodeListBuilder::CFA_GRBG;
- break;
- }
- case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
- uint8_t cfa[4] = {1, 2, 0, 1};
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
- env, TAG_CFAPATTERN, writer);
- opcodeCfaLayout = OpcodeListBuilder::CFA_GBRG;
- break;
- }
- case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
- uint8_t cfa[4] = {2, 1, 1, 0};
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
- env, TAG_CFAPATTERN, writer);
- opcodeCfaLayout = OpcodeListBuilder::CFA_BGGR;
- break;
- }
- default: {
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "Invalid metadata for tag %d", TAG_CFAPATTERN);
- return;
- }
+
+ const int cfaLength = 4;
+ cfaEnum = entry.data.u8[0];
+ uint8_t cfa[cfaLength];
+ if ((err = convertCFA(cfaEnum, /*out*/cfa)) != OK) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Invalid metadata for tag %d", TAG_CFAPATTERN);
}
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0), env,
+ TAG_CFAPATTERN, writer);
+
+ opcodeCfaLayout = convertCFAEnumToOpcodeLayout(cfaEnum);
}
{
// Set CFA plane color
- uint8_t cfaPlaneColor[3] = {0, 1, 2};
BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
env, TAG_CFAPLANECOLOR, writer);
}
@@ -1298,10 +1387,33 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
camera_metadata_entry entry =
results.find(ANDROID_SENSOR_NOISE_PROFILE);
+ const status_t numPlaneColors = 3;
+ const status_t numCfaChannels = 4;
+
+ uint8_t cfaOut[numCfaChannels];
+ if ((err = convertCFA(cfaEnum, /*out*/cfaOut)) != OK) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Invalid CFA from camera characteristics");
+ return;
+ }
+
+ double noiseProfile[numPlaneColors * 2];
+
if (entry.count > 0) {
- BAIL_IF_INVALID(writer->addEntry(TAG_NOISEPROFILE, entry.count,
- entry.data.d, TIFF_IFD_0), env,
- TAG_NOISEPROFILE, writer);
+ if (entry.count != numCfaChannels * 2) {
+ ALOGW("%s: Invalid entry count %u for noise profile returned in characteristics,"
+ " no noise profile tag written...", __FUNCTION__, entry.count);
+ } else {
+ if ((err = generateNoiseProfile(entry.data.d, cfaOut, numCfaChannels,
+ cfaPlaneColor, numPlaneColors, /*out*/ noiseProfile)) == OK) {
+
+ BAIL_IF_INVALID(writer->addEntry(TAG_NOISEPROFILE, numPlaneColors * 2,
+ noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE, writer);
+ } else {
+ ALOGW("%s: Error converting coefficients for noise profile, no noise profile"
+ " tag written...", __FUNCTION__);
+ }
+ }
} else {
ALOGW("%s: No noise profile found in result metadata. Image quality may be reduced.",
__FUNCTION__);