JPEG/R: Add display_boost parameter to decode API
Bug: 264715926
Test: jpegr_test
Change-Id: Ifef71a8aee532d603fd20417e32314243c8b4673
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
index e2023a6..1ab1dd7 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h
@@ -206,13 +206,14 @@
*
* @param compressed_jpegr_image compressed JPEGR image.
* @param dest destination of the uncompressed JPEGR image.
+ * @param max_display_boost (optional) the maximum available boost supported by a display
* @param exif destination of the decoded EXIF metadata. The default value is NULL where the
decoder will do nothing about it. If configured not NULL the decoder will write
EXIF data into this structure. The format is defined in {@code jpegr_exif_struct}
* @param output_format flag for setting output color format. Its value configures the output
color format. The default value is {@code JPEGR_OUTPUT_HDR_LINEAR}.
----------------------------------------------------------------------
- | output_format | decoded color format to be written |
+ | output_format | decoded color format to be written |
----------------------------------------------------------------------
| JPEGR_OUTPUT_SDR | RGBA_8888 |
----------------------------------------------------------------------
@@ -234,6 +235,7 @@
*/
status_t decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
jr_uncompressed_ptr dest,
+ float max_display_boost = -1.0f,
jr_exif_ptr exif = nullptr,
jpegr_output_format output_format = JPEGR_OUTPUT_HDR_LINEAR,
jr_uncompressed_ptr recovery_map = nullptr,
@@ -281,6 +283,7 @@
* @param output_format flag for setting output color format. if set to
* {@code JPEGR_OUTPUT_SDR}, decoder will only decode the primary image
* which is SDR. Default value is JPEGR_OUTPUT_HDR_LINEAR.
+ * @param max_display_boost the maximum available boost supported by a display
* @param dest reconstructed HDR image
* @return NO_ERROR if calculation succeeds, error code if error occurs.
*/
@@ -288,6 +291,7 @@
jr_uncompressed_ptr uncompressed_recovery_map,
jr_metadata_ptr metadata,
jpegr_output_format output_format,
+ float max_display_boost,
jr_uncompressed_ptr dest);
private:
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
index 8b5318f..67d2a6a 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
@@ -135,6 +135,16 @@
}
}
+ RecoveryLUT(jr_metadata_ptr metadata, float displayBoost) {
+ float boostFactor = displayBoost > 0 ? displayBoost / metadata->maxContentBoost : 1.0f;
+ for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
+ float logBoost = log2(metadata->minContentBoost) * (1.0f - value)
+ + log2(metadata->maxContentBoost) * value;
+ mRecoveryTable[idx] = exp2(logBoost * boostFactor);
+ }
+ }
+
~RecoveryLUT() {
}
@@ -357,6 +367,7 @@
* value, with the given hdr ratio, to the given sdr input in the range [0, 1].
*/
Color applyRecovery(Color e, float recovery, jr_metadata_ptr metadata);
+Color applyRecovery(Color e, float recovery, jr_metadata_ptr metadata, float displayBoost);
Color applyRecoveryLUT(Color e, float recovery, RecoveryLUT& recoveryLUT);
/*
diff --git a/libs/jpegrecoverymap/jpegr.cpp b/libs/jpegrecoverymap/jpegr.cpp
index e197bf0..e395d51 100644
--- a/libs/jpegrecoverymap/jpegr.cpp
+++ b/libs/jpegrecoverymap/jpegr.cpp
@@ -330,6 +330,7 @@
/* Decode API */
status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
jr_uncompressed_ptr dest,
+ float max_display_boost,
jr_exif_ptr exif,
jpegr_output_format output_format,
jr_uncompressed_ptr recovery_map,
@@ -431,7 +432,7 @@
uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight();
JPEGR_CHECK(applyRecoveryMap(&uncompressed_yuv_420_image, &map, &jr_metadata, output_format,
- dest));
+ max_display_boost, dest));
return NO_ERROR;
}
@@ -667,6 +668,7 @@
jr_uncompressed_ptr uncompressed_recovery_map,
jr_metadata_ptr metadata,
jpegr_output_format output_format,
+ float max_display_boost,
jr_uncompressed_ptr dest) {
if (uncompressed_yuv_420_image == nullptr
|| uncompressed_recovery_map == nullptr
@@ -678,13 +680,15 @@
dest->width = uncompressed_yuv_420_image->width;
dest->height = uncompressed_yuv_420_image->height;
ShepardsIDW idwTable(kMapDimensionScaleFactor);
- RecoveryLUT recoveryLUT(metadata);
+ float display_boost = max_display_boost > 0 ?
+ std::min(max_display_boost, metadata->maxContentBoost)
+ : metadata->maxContentBoost;
+ RecoveryLUT recoveryLUT(metadata, display_boost);
JobQueue jobQueue;
std::function<void()> applyRecMap = [uncompressed_yuv_420_image, uncompressed_recovery_map,
metadata, dest, &jobQueue, &idwTable, output_format,
- &recoveryLUT]() -> void {
- const float hdr_ratio = metadata->maxContentBoost;
+ &recoveryLUT, display_boost]() -> void {
size_t width = uncompressed_yuv_420_image->width;
size_t height = uncompressed_yuv_420_image->height;
@@ -710,12 +714,13 @@
} else {
recovery = sampleMap(uncompressed_recovery_map, map_scale_factor, x, y, idwTable);
}
+
#if USE_APPLY_RECOVERY_LUT
Color rgb_hdr = applyRecoveryLUT(rgb_sdr, recovery, recoveryLUT);
#else
- Color rgb_hdr = applyRecovery(rgb_sdr, recovery, metadata);
+ Color rgb_hdr = applyRecovery(rgb_sdr, recovery, metadata, display_boost);
#endif
- rgb_hdr = rgb_hdr / metadata->maxContentBoost;
+ rgb_hdr = rgb_hdr / display_boost;
size_t pixel_idx = x + y * width;
switch (output_format) {
diff --git a/libs/jpegrecoverymap/recoverymapmath.cpp b/libs/jpegrecoverymap/recoverymapmath.cpp
index 20c32ed..2cffde3 100644
--- a/libs/jpegrecoverymap/recoverymapmath.cpp
+++ b/libs/jpegrecoverymap/recoverymapmath.cpp
@@ -463,6 +463,13 @@
return e * recoveryFactor;
}
+Color applyRecovery(Color e, float recovery, jr_metadata_ptr metadata, float displayBoost) {
+ float logBoost = log2(metadata->minContentBoost) * (1.0f - recovery)
+ + log2(metadata->maxContentBoost) * recovery;
+ float recoveryFactor = exp2(logBoost * displayBoost / metadata->maxContentBoost);
+ return e * recoveryFactor;
+}
+
Color applyRecoveryLUT(Color e, float recovery, RecoveryLUT& recoveryLUT) {
float recoveryFactor = recoveryLUT.getRecoveryFactor(recovery);
return e * recoveryFactor;
diff --git a/libs/jpegrecoverymap/tests/jpegr_test.cpp b/libs/jpegrecoverymap/tests/jpegr_test.cpp
index be4b972..df90f53 100644
--- a/libs/jpegrecoverymap/tests/jpegr_test.cpp
+++ b/libs/jpegrecoverymap/tests/jpegr_test.cpp
@@ -152,7 +152,8 @@
timerStart(&applyRecMapTime);
for (auto i = 0; i < kProfileCount; i++) {
- ASSERT_EQ(OK, applyRecoveryMap(yuv420Image, map, metadata, JPEGR_OUTPUT_HDR_HLG, dest));
+ ASSERT_EQ(OK, applyRecoveryMap(yuv420Image, map, metadata, JPEGR_OUTPUT_HDR_HLG,
+ metadata->maxContentBoost /* displayBoost */, dest));
}
timerStop(&applyRecMapTime);
@@ -170,7 +171,7 @@
jpegRCodec.encodeJPEGR(nullptr, nullptr, nullptr, static_cast<jpegr_transfer_function>(0),
nullptr);
jpegRCodec.encodeJPEGR(nullptr, nullptr, static_cast<jpegr_transfer_function>(0), nullptr);
- jpegRCodec.decodeJPEGR(nullptr, nullptr, nullptr);
+ jpegRCodec.decodeJPEGR(nullptr, nullptr);
}
TEST_F(JpegRTest, writeXmpThenRead) {
diff --git a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
index cf6a034..5ef79e9 100644
--- a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
+++ b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
@@ -557,6 +557,7 @@
jpegr_metadata_struct metadata = { .maxContentBoost = static_cast<float>(boost),
.minContentBoost = 1.0f / static_cast<float>(boost) };
RecoveryLUT recoveryLUT(&metadata);
+ RecoveryLUT recoveryLUTWithBoost(&metadata, metadata.maxContentBoost);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, &metadata),
@@ -569,6 +570,16 @@
applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlack(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbWhite(), value, recoveryLUT),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbRed(), value, recoveryLUT),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbGreen(), value, recoveryLUT),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlue(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUTWithBoost));
}
}
@@ -576,6 +587,7 @@
jpegr_metadata_struct metadata = { .maxContentBoost = static_cast<float>(boost),
.minContentBoost = 1.0f };
RecoveryLUT recoveryLUT(&metadata);
+ RecoveryLUT recoveryLUTWithBoost(&metadata, metadata.maxContentBoost);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, &metadata),
@@ -588,6 +600,16 @@
applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlack(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbWhite(), value, recoveryLUT),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbRed(), value, recoveryLUT),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbGreen(), value, recoveryLUT),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlue(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUTWithBoost));
}
}
@@ -596,6 +618,7 @@
.minContentBoost = 1.0f / pow(static_cast<float>(boost),
1.0f / 3.0f) };
RecoveryLUT recoveryLUT(&metadata);
+ RecoveryLUT recoveryLUTWithBoost(&metadata, metadata.maxContentBoost);
for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kRecoveryFactorNumEntries - 1);
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, &metadata),
@@ -608,6 +631,16 @@
applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlack(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbWhite(), value, recoveryLUT),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbRed(), value, recoveryLUT),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbGreen(), value, recoveryLUT),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUTWithBoost));
+ EXPECT_RGB_EQ(applyRecoveryLUT(RgbBlue(), value, recoveryLUT),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUTWithBoost));
}
}
}
@@ -719,6 +752,7 @@
TEST_F(RecoveryMapMathTest, ApplyRecovery) {
jpegr_metadata_struct metadata = { .maxContentBoost = 4.0f,
.minContentBoost = 1.0f / 4.0f };
+ float displayBoost = metadata.maxContentBoost;
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, &metadata), RgbBlack());
EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.5f, &metadata), RgbBlack());
@@ -774,6 +808,19 @@
EXPECT_RGB_NEAR(applyRecovery(e, 0.5f, &metadata), e);
EXPECT_RGB_NEAR(applyRecovery(e, 0.75f, &metadata), e * 2.0f);
EXPECT_RGB_NEAR(applyRecovery(e, 1.0f, &metadata), e * 4.0f);
+
+ EXPECT_RGB_EQ(applyRecovery(RgbBlack(), 1.0f, &metadata),
+ applyRecovery(RgbBlack(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(RgbWhite(), 1.0f, &metadata),
+ applyRecovery(RgbWhite(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(RgbRed(), 1.0f, &metadata),
+ applyRecovery(RgbRed(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(RgbGreen(), 1.0f, &metadata),
+ applyRecovery(RgbGreen(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(RgbBlue(), 1.0f, &metadata),
+ applyRecovery(RgbBlue(), 1.0f, &metadata, displayBoost));
+ EXPECT_RGB_EQ(applyRecovery(e, 1.0f, &metadata),
+ applyRecovery(e, 1.0f, &metadata, displayBoost));
}
TEST_F(RecoveryMapMathTest, GetYuv420Pixel) {