diff options
author | Ruben Brunk <rubenbrunk@google.com> | 2014-08-26 06:55:25 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-08-26 06:55:26 +0000 |
commit | 6d388af85379f4d534002118caa9ba4f7812e049 (patch) | |
tree | e362c2368d678501d6d481b52cfbe7b4dbb981ce /core/jni | |
parent | ed25dda8ba5b1be9bd050939deca82bf6506a09b (diff) | |
parent | d70132c373eee01b4e0a35250bd4246672e7a02e (diff) | |
download | frameworks_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.cpp | 194 |
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__); |