summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nick Deakin <deakin@google.com> 2023-02-13 20:28:12 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-02-13 20:28:12 +0000
commit34d28d124310ee328ec27be068ce3be6001ccb77 (patch)
tree526aa15e8e0d6d8687a50689fdd28f9a4bbf6ff8
parent8e8eb792bd30ebb42767869ef1fcace987a1a25c (diff)
parentd19e576fef9a1bd99a2118bb7edb6e2549ddde49 (diff)
Merge "jpegrecoverymap: Add min boost to metadata."
-rw-r--r--libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h28
-rw-r--r--libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h36
-rw-r--r--libs/jpegrecoverymap/recoverymap.cpp51
-rw-r--r--libs/jpegrecoverymap/recoverymapmath.cpp72
-rw-r--r--libs/jpegrecoverymap/tests/recoverymap_test.cpp150
-rw-r--r--libs/jpegrecoverymap/tests/recoverymapmath_test.cpp332
6 files changed, 463 insertions, 206 deletions
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
index aee6602aa4..1fd129b991 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h
@@ -88,6 +88,8 @@ struct jpegr_metadata {
uint32_t version;
// Max Content Boost for the map
float maxContentBoost;
+ // Min Content Boost for the map
+ float minContentBoost;
};
typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr;
@@ -219,16 +221,9 @@ public:
*/
status_t getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image,
jr_info_ptr jpegr_info);
-private:
- /*
- * This method is called in the encoding pipeline. It will encode the recovery map.
- *
- * @param uncompressed_recovery_map uncompressed recovery map
- * @param dest encoded recover map
- * @return NO_ERROR if encoding succeeds, error code if error occurs.
- */
- status_t compressRecoveryMap(jr_uncompressed_ptr uncompressed_recovery_map,
- jr_compressed_ptr dest);
+
+protected:
+ // Following functions protected instead of private for testing.
/*
* This method is called in the encoding pipeline. It will take the uncompressed 8-bit and
@@ -239,7 +234,7 @@ private:
* @param uncompressed_p010_image uncompressed HDR image in P010 color format
* @param hdr_tf transfer function of the HDR image
* @param dest recovery map; caller responsible for memory of data
- * @param metadata max_content_boost is filled in
+ * @param metadata minContentBoost and maxContentBoost are filled in
* @return NO_ERROR if calculation succeeds, error code if error occurs.
*/
status_t generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image,
@@ -265,6 +260,17 @@ private:
jr_metadata_ptr metadata,
jr_uncompressed_ptr dest);
+private:
+ /*
+ * This method is called in the encoding pipeline. It will encode the recovery map.
+ *
+ * @param uncompressed_recovery_map uncompressed recovery map
+ * @param dest encoded recover map
+ * @return NO_ERROR if encoding succeeds, error code if error occurs.
+ */
+ status_t compressRecoveryMap(jr_uncompressed_ptr uncompressed_recovery_map,
+ jr_compressed_ptr dest);
+
/*
* This methoud is called to separate primary image and recovery map image from JPEGR
*
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
index 0695bb74ac..6eed08afb4 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
@@ -118,11 +118,12 @@ inline Color operator/(const Color& lhs, const float rhs) {
constexpr size_t kRecoveryFactorPrecision = 10;
constexpr size_t kRecoveryFactorNumEntries = 1 << kRecoveryFactorPrecision;
struct RecoveryLUT {
- RecoveryLUT(float hdrRatio) {
- float increment = 2.0 / kRecoveryFactorNumEntries;
- float value = -1.0f;
- for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++, value += increment) {
- mRecoveryTable[idx] = pow(hdrRatio, value);
+ RecoveryLUT(jr_metadata_ptr metadata) {
+ 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);
}
}
@@ -130,10 +131,10 @@ struct RecoveryLUT {
}
float getRecoveryFactor(float recovery) {
- uint32_t value = static_cast<uint32_t>(((recovery + 1.0f) / 2.0f) * kRecoveryFactorNumEntries);
+ uint32_t idx = static_cast<uint32_t>(recovery * (kRecoveryFactorNumEntries - 1));
//TODO() : Remove once conversion modules have appropriate clamping in place
- value = CLIP3(value, 0, kRecoveryFactorNumEntries - 1);
- return mRecoveryTable[value];
+ idx = CLIP3(idx, 0, kRecoveryFactorNumEntries - 1);
+ return mRecoveryTable[idx];
}
private:
@@ -219,6 +220,9 @@ Color srgbInvOetf(Color e_gamma);
float srgbInvOetfLUT(float e_gamma);
Color srgbInvOetfLUT(Color e_gamma);
+constexpr size_t kSrgbInvOETFPrecision = 10;
+constexpr size_t kSrgbInvOETFNumEntries = 1 << kSrgbInvOETFPrecision;
+
////////////////////////////////////////////////////////////////////////////////
// Display-P3 transformations
@@ -260,6 +264,9 @@ Color hlgOetf(Color e);
float hlgOetfLUT(float e);
Color hlgOetfLUT(Color e);
+constexpr size_t kHlgOETFPrecision = 10;
+constexpr size_t kHlgOETFNumEntries = 1 << kHlgOETFPrecision;
+
/*
* Convert from HLG to scene luminance.
*
@@ -270,6 +277,9 @@ Color hlgInvOetf(Color e_gamma);
float hlgInvOetfLUT(float e_gamma);
Color hlgInvOetfLUT(Color e_gamma);
+constexpr size_t kHlgInvOETFPrecision = 10;
+constexpr size_t kHlgInvOETFNumEntries = 1 << kHlgInvOETFPrecision;
+
/*
* Convert from scene luminance to PQ.
*
@@ -280,6 +290,9 @@ Color pqOetf(Color e);
float pqOetfLUT(float e);
Color pqOetfLUT(Color e);
+constexpr size_t kPqOETFPrecision = 10;
+constexpr size_t kPqOETFNumEntries = 1 << kPqOETFPrecision;
+
/*
* Convert from PQ to scene luminance in nits.
*
@@ -290,6 +303,9 @@ Color pqInvOetf(Color e_gamma);
float pqInvOetfLUT(float e_gamma);
Color pqInvOetfLUT(Color e_gamma);
+constexpr size_t kPqInvOETFPrecision = 10;
+constexpr size_t kPqInvOETFNumEntries = 1 << kPqInvOETFPrecision;
+
////////////////////////////////////////////////////////////////////////////////
// Color space conversions
@@ -326,13 +342,13 @@ ColorTransformFn getHdrConversionFn(jpegr_color_gamut sdr_gamut, jpegr_color_gam
* Calculate the 8-bit unsigned integer recovery value for the given SDR and HDR
* luminances in linear space, and the hdr ratio to encode against.
*/
-uint8_t encodeRecovery(float y_sdr, float y_hdr, float hdr_ratio);
+uint8_t encodeRecovery(float y_sdr, float y_hdr, jr_metadata_ptr metadata);
/*
* Calculates the linear luminance in nits after applying the given recovery
* value, with the given hdr ratio, to the given sdr input in the range [0, 1].
*/
-Color applyRecovery(Color e, float recovery, float hdr_ratio);
+Color applyRecovery(Color e, float recovery, jr_metadata_ptr metadata);
Color applyRecoveryLUT(Color e, float recovery, RecoveryLUT& recoveryLUT);
/*
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
index 218c43017b..349223bb6b 100644
--- a/libs/jpegrecoverymap/recoverymap.cpp
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -573,19 +573,20 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4
}
std::mutex mutex;
- float hdr_y_nits_max = 0.0f;
- double hdr_y_nits_avg = 0.0f;
+ float max_gain = 0.0f;
+ float min_gain = 1.0f;
const int threads = std::clamp(GetCPUCoreCount(), 1, 4);
size_t rowStep = threads == 1 ? image_height : kJobSzInRows;
JobQueue jobQueue;
- std::function<void()> computeMetadata = [uncompressed_p010_image, hdrInvOetf,
- hdrGamutConversionFn, luminanceFn, hdr_white_nits,
- threads, &mutex, &hdr_y_nits_avg,
- &hdr_y_nits_max, &jobQueue]() -> void {
+ std::function<void()> computeMetadata = [uncompressed_p010_image, uncompressed_yuv_420_image,
+ hdrInvOetf, hdrGamutConversionFn, luminanceFn,
+ hdr_white_nits, threads, &mutex, &max_gain, &min_gain,
+ &jobQueue]() -> void {
size_t rowStart, rowEnd;
- float hdr_y_nits_max_th = 0.0f;
- double hdr_y_nits_avg_th = 0.0f;
+ float max_gain_th = 0.0f;
+ float min_gain_th = 1.0f;
+
while (jobQueue.dequeueJob(rowStart, rowEnd)) {
for (size_t y = rowStart; y < rowEnd; ++y) {
for (size_t x = 0; x < uncompressed_p010_image->width; ++x) {
@@ -595,16 +596,25 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4
hdr_rgb = hdrGamutConversionFn(hdr_rgb);
float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits;
- hdr_y_nits_avg_th += hdr_y_nits;
- if (hdr_y_nits > hdr_y_nits_max_th) {
- hdr_y_nits_max_th = hdr_y_nits;
- }
+ Color sdr_yuv_gamma =
+ getYuv420Pixel(uncompressed_yuv_420_image, x, y);
+ Color sdr_rgb_gamma = srgbYuvToRgb(sdr_yuv_gamma);
+#if USE_SRGB_INVOETF_LUT
+ Color sdr_rgb = srgbInvOetfLUT(sdr_rgb_gamma);
+#else
+ Color sdr_rgb = srgbInvOetf(sdr_rgb_gamma);
+#endif
+ float sdr_y_nits = luminanceFn(sdr_rgb) * kSdrWhiteNits;
+
+ float gain = hdr_y_nits / sdr_y_nits;
+ max_gain_th = std::max(max_gain_th, gain);
+ min_gain_th = std::min(min_gain_th, gain);
}
}
}
std::unique_lock<std::mutex> lock{mutex};
- hdr_y_nits_avg += hdr_y_nits_avg_th;
- hdr_y_nits_max = std::max(hdr_y_nits_max, hdr_y_nits_max_th);
+ max_gain = std::max(max_gain, max_gain_th);
+ min_gain = std::min(min_gain, min_gain_th);
};
std::function<void()> generateMap = [uncompressed_yuv_420_image, uncompressed_p010_image,
@@ -634,7 +644,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4
size_t pixel_idx = x + y * dest_map_stride;
reinterpret_cast<uint8_t*>(dest->data)[pixel_idx] =
- encodeRecovery(sdr_y_nits, hdr_y_nits, metadata->maxContentBoost);
+ encodeRecovery(sdr_y_nits, hdr_y_nits, metadata);
}
}
}
@@ -655,9 +665,9 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4
computeMetadata();
std::for_each(workers.begin(), workers.end(), [](std::thread& t) { t.join(); });
workers.clear();
- hdr_y_nits_avg /= image_width * image_height;
- metadata->maxContentBoost = hdr_y_nits_max / kSdrWhiteNits;
+ metadata->maxContentBoost = max_gain;
+ metadata->minContentBoost = min_gain;
// generate map
jobQueue.reset();
@@ -693,7 +703,7 @@ status_t RecoveryMap::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_
dest->width = uncompressed_yuv_420_image->width;
dest->height = uncompressed_yuv_420_image->height;
ShepardsIDW idwTable(kMapDimensionScaleFactor);
- RecoveryLUT recoveryLUT(metadata->maxContentBoost);
+ RecoveryLUT recoveryLUT(metadata);
JobQueue jobQueue;
std::function<void()> applyRecMap = [uncompressed_yuv_420_image, uncompressed_recovery_map,
@@ -729,13 +739,12 @@ status_t RecoveryMap::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_
if (map_scale_factor != floorf(map_scale_factor)) {
recovery = sampleMap(uncompressed_recovery_map, map_scale_factor, x, y);
} else {
- recovery = sampleMap(uncompressed_recovery_map, map_scale_factor, x, y,
- idwTable);
+ 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, hdr_ratio);
+ Color rgb_hdr = applyRecovery(rgb_sdr, recovery, metadata);
#endif
Color rgb_gamma_hdr = hdrOetf(rgb_hdr / metadata->maxContentBoost);
uint32_t rgba1010102 = colorToRgba1010102(rgb_gamma_hdr);
diff --git a/libs/jpegrecoverymap/recoverymapmath.cpp b/libs/jpegrecoverymap/recoverymapmath.cpp
index 4f21ac6372..9c89c8afd4 100644
--- a/libs/jpegrecoverymap/recoverymapmath.cpp
+++ b/libs/jpegrecoverymap/recoverymapmath.cpp
@@ -20,65 +20,46 @@
namespace android::recoverymap {
-constexpr size_t kPqOETFPrecision = 10;
-constexpr size_t kPqOETFNumEntries = 1 << kPqOETFPrecision;
-
static const std::vector<float> kPqOETF = [] {
std::vector<float> result;
- float increment = 1.0 / kPqOETFNumEntries;
- float value = 0.0f;
- for (int idx = 0; idx < kPqOETFNumEntries; idx++, value += increment) {
+ for (int idx = 0; idx < kPqOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kPqOETFNumEntries - 1);
result.push_back(pqOetf(value));
}
return result;
}();
-constexpr size_t kPqInvOETFPrecision = 10;
-constexpr size_t kPqInvOETFNumEntries = 1 << kPqInvOETFPrecision;
-
static const std::vector<float> kPqInvOETF = [] {
std::vector<float> result;
- float increment = 1.0 / kPqInvOETFNumEntries;
- float value = 0.0f;
- for (int idx = 0; idx < kPqInvOETFNumEntries; idx++, value += increment) {
+ for (int idx = 0; idx < kPqInvOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kPqInvOETFNumEntries - 1);
result.push_back(pqInvOetf(value));
}
return result;
}();
-constexpr size_t kHlgOETFPrecision = 10;
-constexpr size_t kHlgOETFNumEntries = 1 << kHlgOETFPrecision;
-
static const std::vector<float> kHlgOETF = [] {
std::vector<float> result;
- float increment = 1.0 / kHlgOETFNumEntries;
- float value = 0.0f;
- for (int idx = 0; idx < kHlgOETFNumEntries; idx++, value += increment) {
+ for (int idx = 0; idx < kHlgOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kHlgOETFNumEntries - 1);
result.push_back(hlgOetf(value));
}
return result;
}();
-constexpr size_t kHlgInvOETFPrecision = 10;
-constexpr size_t kHlgInvOETFNumEntries = 1 << kHlgInvOETFPrecision;
-
static const std::vector<float> kHlgInvOETF = [] {
std::vector<float> result;
- float increment = 1.0 / kHlgInvOETFNumEntries;
- float value = 0.0f;
- for (int idx = 0; idx < kHlgInvOETFNumEntries; idx++, value += increment) {
+ for (int idx = 0; idx < kHlgInvOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kHlgInvOETFNumEntries - 1);
result.push_back(hlgInvOetf(value));
}
return result;
}();
-constexpr size_t kSRGBInvOETFPrecision = 10;
-constexpr size_t kSRGBInvOETFNumEntries = 1 << kSRGBInvOETFPrecision;
-static const std::vector<float> kSRGBInvOETF = [] {
+static const std::vector<float> kSrgbInvOETF = [] {
std::vector<float> result;
- float increment = 1.0 / kSRGBInvOETFNumEntries;
- float value = 0.0f;
- for (int idx = 0; idx < kSRGBInvOETFNumEntries; idx++, value += increment) {
+ for (int idx = 0; idx < kSrgbInvOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kSrgbInvOETFNumEntries - 1);
result.push_back(srgbInvOetf(value));
}
return result;
@@ -182,10 +163,10 @@ Color srgbInvOetf(Color e_gamma) {
// See IEC 61966-2-1, Equations F.5 and F.6.
float srgbInvOetfLUT(float e_gamma) {
- uint32_t value = static_cast<uint32_t>(e_gamma * kSRGBInvOETFNumEntries);
+ uint32_t value = static_cast<uint32_t>(e_gamma * kSrgbInvOETFNumEntries);
//TODO() : Remove once conversion modules have appropriate clamping in place
- value = CLIP3(value, 0, kSRGBInvOETFNumEntries - 1);
- return kSRGBInvOETF[value];
+ value = CLIP3(value, 0, kSrgbInvOETFNumEntries - 1);
+ return kSrgbInvOETF[value];
}
Color srgbInvOetfLUT(Color e_gamma) {
@@ -461,21 +442,24 @@ ColorTransformFn getHdrConversionFn(jpegr_color_gamut sdr_gamut, jpegr_color_gam
////////////////////////////////////////////////////////////////////////////////
// Recovery map calculations
-
-uint8_t encodeRecovery(float y_sdr, float y_hdr, float hdr_ratio) {
+uint8_t encodeRecovery(float y_sdr, float y_hdr, jr_metadata_ptr metadata) {
float gain = 1.0f;
if (y_sdr > 0.0f) {
gain = y_hdr / y_sdr;
}
- if (gain < (1.0f / hdr_ratio)) gain = 1.0f / hdr_ratio;
- if (gain > hdr_ratio) gain = hdr_ratio;
+ if (gain < metadata->minContentBoost) gain = metadata->minContentBoost;
+ if (gain > metadata->maxContentBoost) gain = metadata->maxContentBoost;
- return static_cast<uint8_t>(log2(gain) / log2(hdr_ratio) * 127.5f + 127.5f);
+ return static_cast<uint8_t>((log2(gain) - log2(metadata->minContentBoost))
+ / (log2(metadata->maxContentBoost) - log2(metadata->minContentBoost))
+ * 255.0f);
}
-Color applyRecovery(Color e, float recovery, float hdr_ratio) {
- float recoveryFactor = pow(hdr_ratio, recovery);
+Color applyRecovery(Color e, float recovery, jr_metadata_ptr metadata) {
+ float logBoost = log2(metadata->minContentBoost) * (1.0f - recovery)
+ + log2(metadata->maxContentBoost) * recovery;
+ float recoveryFactor = exp2(logBoost);
return e * recoveryFactor;
}
@@ -550,7 +534,7 @@ static size_t clamp(const size_t& val, const size_t& low, const size_t& high) {
}
static float mapUintToFloat(uint8_t map_uint) {
- return (static_cast<float>(map_uint) - 127.5f) / 127.5f;
+ return static_cast<float>(map_uint) / 255.0f;
}
static float pythDistance(float x_diff, float y_diff) {
@@ -558,9 +542,9 @@ static float pythDistance(float x_diff, float y_diff) {
}
// TODO: If map_scale_factor is guaranteed to be an integer, then remove the following.
-float sampleMap(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y) {
- float x_map = static_cast<float>(x) / static_cast<float>(map_scale_factor);
- float y_map = static_cast<float>(y) / static_cast<float>(map_scale_factor);
+float sampleMap(jr_uncompressed_ptr map, float map_scale_factor, size_t x, size_t y) {
+ float x_map = static_cast<float>(x) / map_scale_factor;
+ float y_map = static_cast<float>(y) / map_scale_factor;
size_t x_lower = static_cast<size_t>(floor(x_map));
size_t x_upper = x_lower + 1;
diff --git a/libs/jpegrecoverymap/tests/recoverymap_test.cpp b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
index 3e9a76d47a..1b73d94057 100644
--- a/libs/jpegrecoverymap/tests/recoverymap_test.cpp
+++ b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
@@ -20,6 +20,7 @@
#include <fcntl.h>
#include <fstream>
#include <gtest/gtest.h>
+#include <sys/time.h>
#include <utils/Log.h>
#define RAW_P010_IMAGE "/sdcard/Documents/raw_p010_image.p010"
@@ -35,27 +36,24 @@
namespace android::recoverymap {
-class RecoveryMapTest : public testing::Test {
-public:
- RecoveryMapTest();
- ~RecoveryMapTest();
-protected:
- virtual void SetUp();
- virtual void TearDown();
-
- struct jpegr_uncompressed_struct mRawP010Image;
- struct jpegr_uncompressed_struct mRawYuv420Image;
- struct jpegr_compressed_struct mJpegImage;
+struct Timer {
+ struct timeval StartingTime;
+ struct timeval EndingTime;
+ struct timeval ElapsedMicroseconds;
};
-RecoveryMapTest::RecoveryMapTest() {}
-RecoveryMapTest::~RecoveryMapTest() {}
+void timerStart(Timer *t) {
+ gettimeofday(&t->StartingTime, nullptr);
+}
-void RecoveryMapTest::SetUp() {}
-void RecoveryMapTest::TearDown() {
- free(mRawP010Image.data);
- free(mRawYuv420Image.data);
- free(mJpegImage.data);
+void timerStop(Timer *t) {
+ gettimeofday(&t->EndingTime, nullptr);
+}
+
+int64_t elapsedTime(Timer *t) {
+ t->ElapsedMicroseconds.tv_sec = t->EndingTime.tv_sec - t->StartingTime.tv_sec;
+ t->ElapsedMicroseconds.tv_usec = t->EndingTime.tv_usec - t->StartingTime.tv_usec;
+ return t->ElapsedMicroseconds.tv_sec * 1000000 + t->ElapsedMicroseconds.tv_usec;
}
static size_t getFileSize(int fd) {
@@ -89,6 +87,80 @@ static bool loadFile(const char filename[], void*& result, int* fileLength) {
return true;
}
+class RecoveryMapTest : public testing::Test {
+public:
+ RecoveryMapTest();
+ ~RecoveryMapTest();
+
+protected:
+ virtual void SetUp();
+ virtual void TearDown();
+
+ struct jpegr_uncompressed_struct mRawP010Image;
+ struct jpegr_uncompressed_struct mRawYuv420Image;
+ struct jpegr_compressed_struct mJpegImage;
+};
+
+RecoveryMapTest::RecoveryMapTest() {}
+RecoveryMapTest::~RecoveryMapTest() {}
+
+void RecoveryMapTest::SetUp() {}
+void RecoveryMapTest::TearDown() {
+ free(mRawP010Image.data);
+ free(mRawYuv420Image.data);
+ free(mJpegImage.data);
+}
+
+class RecoveryMapBenchmark : public RecoveryMap {
+public:
+ void BenchmarkGenerateRecoveryMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr p010Image,
+ jr_metadata_ptr metadata, jr_uncompressed_ptr map);
+ void BenchmarkApplyRecoveryMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr map,
+ jr_metadata_ptr metadata, jr_uncompressed_ptr dest);
+private:
+ const int kProfileCount = 10;
+};
+
+void RecoveryMapBenchmark::BenchmarkGenerateRecoveryMap(jr_uncompressed_ptr yuv420Image,
+ jr_uncompressed_ptr p010Image,
+ jr_metadata_ptr metadata,
+ jr_uncompressed_ptr map) {
+ ASSERT_EQ(yuv420Image->width, p010Image->width);
+ ASSERT_EQ(yuv420Image->height, p010Image->height);
+
+ Timer genRecMapTime;
+
+ timerStart(&genRecMapTime);
+ for (auto i = 0; i < kProfileCount; i++) {
+ ASSERT_EQ(OK, generateRecoveryMap(
+ yuv420Image, p010Image, jpegr_transfer_function::JPEGR_TF_HLG, metadata, map));
+ if (i != kProfileCount - 1) delete[] static_cast<uint8_t *>(map->data);
+ }
+ timerStop(&genRecMapTime);
+
+ ALOGE("Generate Recovery Map:- Res = %i x %i, time = %f ms",
+ yuv420Image->width, yuv420Image->height,
+ elapsedTime(&genRecMapTime) / (kProfileCount * 1000.f));
+
+}
+
+void RecoveryMapBenchmark::BenchmarkApplyRecoveryMap(jr_uncompressed_ptr yuv420Image,
+ jr_uncompressed_ptr map,
+ jr_metadata_ptr metadata,
+ jr_uncompressed_ptr dest) {
+ Timer applyRecMapTime;
+
+ timerStart(&applyRecMapTime);
+ for (auto i = 0; i < kProfileCount; i++) {
+ ASSERT_EQ(OK, applyRecoveryMap(yuv420Image, map, metadata, dest));
+ }
+ timerStop(&applyRecMapTime);
+
+ ALOGE("Apply Recovery Map:- Res = %i x %i, time = %f ms",
+ yuv420Image->width, yuv420Image->height,
+ elapsedTime(&applyRecMapTime) / (kProfileCount * 1000.f));
+}
+
TEST_F(RecoveryMapTest, build) {
// Force all of the recovery map lib to be linked by calling all public functions.
RecoveryMap recovery_map;
@@ -382,4 +454,46 @@ TEST_F(RecoveryMapTest, encodeFromJpegThenDecode) {
free(decodedJpegR.data);
}
+TEST_F(RecoveryMapTest, ProfileRecoveryMapFuncs) {
+ const size_t kWidth = TEST_IMAGE_WIDTH;
+ const size_t kHeight = TEST_IMAGE_HEIGHT;
+
+ // Load input files.
+ if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
+ FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
+ }
+ mRawP010Image.width = kWidth;
+ mRawP010Image.height = kHeight;
+ mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
+
+ if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
+ FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
+ }
+ mRawYuv420Image.width = kWidth;
+ mRawYuv420Image.height = kHeight;
+ mRawYuv420Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
+
+ RecoveryMapBenchmark benchmark;
+
+ jpegr_metadata metadata = { .version = 1,
+ .maxContentBoost = 8.0f,
+ .minContentBoost = 1.0f / 8.0f };
+
+ jpegr_uncompressed_struct map = { .data = NULL,
+ .width = 0,
+ .height = 0,
+ .colorGamut = JPEGR_COLORGAMUT_UNSPECIFIED };
+
+ benchmark.BenchmarkGenerateRecoveryMap(&mRawYuv420Image, &mRawP010Image, &metadata, &map);
+
+ const int dstSize = mRawYuv420Image.width * mRawYuv420Image.height * 4;
+ auto bufferDst = std::make_unique<uint8_t[]>(dstSize);
+ jpegr_uncompressed_struct dest = { .data = bufferDst.get(),
+ .width = 0,
+ .height = 0,
+ .colorGamut = JPEGR_COLORGAMUT_UNSPECIFIED };
+
+ benchmark.BenchmarkApplyRecoveryMap(&mRawYuv420Image, &map, &metadata, &dest);
+}
+
} // namespace android::recoverymap
diff --git a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
index 2eec95f01b..80a9596e3c 100644
--- a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
+++ b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
@@ -42,7 +42,7 @@ public:
}
float Map(uint8_t e) {
- return (static_cast<float>(e) - 127.5f) / 127.5f;
+ return static_cast<float>(e) / 255.0f;
}
Color ColorMin(Color e1, Color e2) {
@@ -88,10 +88,10 @@ public:
return luminance_scaled * scale_factor;
}
- Color Recover(Color yuv_gamma, float recovery, float max_content_boost) {
+ Color Recover(Color yuv_gamma, float recovery, jr_metadata_ptr metadata) {
Color rgb_gamma = srgbYuvToRgb(yuv_gamma);
Color rgb = srgbInvOetf(rgb_gamma);
- return applyRecovery(rgb, recovery, max_content_boost);
+ return applyRecovery(rgb, recovery, metadata);
}
jpegr_uncompressed_struct Yuv420Image() {
@@ -518,59 +518,95 @@ TEST_F(RecoveryMapMathTest, PqInvOetf) {
}
TEST_F(RecoveryMapMathTest, PqInvOetfLUT) {
- float increment = 1.0 / 1024.0;
- float value = 0.0f;
- for (int idx = 0; idx < 1024; idx++, value += increment) {
+ for (int idx = 0; idx < kPqInvOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kPqInvOETFNumEntries - 1);
EXPECT_FLOAT_EQ(pqInvOetf(value), pqInvOetfLUT(value));
}
}
TEST_F(RecoveryMapMathTest, HlgInvOetfLUT) {
- float increment = 1.0 / 1024.0;
- float value = 0.0f;
- for (int idx = 0; idx < 1024; idx++, value += increment) {
+ for (int idx = 0; idx < kHlgInvOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kHlgInvOETFNumEntries - 1);
EXPECT_FLOAT_EQ(hlgInvOetf(value), hlgInvOetfLUT(value));
}
}
TEST_F(RecoveryMapMathTest, pqOetfLUT) {
- float increment = 1.0 / 1024.0;
- float value = 0.0f;
- for (int idx = 0; idx < 1024; idx++, value += increment) {
+ for (int idx = 0; idx < kPqOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kPqOETFNumEntries - 1);
EXPECT_FLOAT_EQ(pqOetf(value), pqOetfLUT(value));
}
}
TEST_F(RecoveryMapMathTest, hlgOetfLUT) {
- float increment = 1.0 / 1024.0;
- float value = 0.0f;
- for (int idx = 0; idx < 1024; idx++, value += increment) {
+ for (int idx = 0; idx < kHlgOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kHlgOETFNumEntries - 1);
EXPECT_FLOAT_EQ(hlgOetf(value), hlgOetfLUT(value));
}
}
TEST_F(RecoveryMapMathTest, srgbInvOetfLUT) {
- float increment = 1.0 / 1024.0;
- float value = 0.0f;
- for (int idx = 0; idx < 1024; idx++, value += increment) {
+ for (int idx = 0; idx < kSrgbInvOETFNumEntries; idx++) {
+ float value = static_cast<float>(idx) / static_cast<float>(kSrgbInvOETFNumEntries - 1);
EXPECT_FLOAT_EQ(srgbInvOetf(value), srgbInvOetfLUT(value));
}
}
TEST_F(RecoveryMapMathTest, applyRecoveryLUT) {
- float increment = 2.0 / kRecoveryFactorNumEntries;
- for (float hdrRatio = 1.0f; hdrRatio <= 10.0f; hdrRatio += 1.0f) {
- RecoveryLUT recoveryLUT(hdrRatio);
- for (float value = -1.0f; value <= -1.0f; value += increment) {
- EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, hdrRatio),
+ for (int boost = 1; boost <= 10; boost++) {
+ jpegr_metadata metadata = { .maxContentBoost = static_cast<float>(boost),
+ .minContentBoost = 1.0f / static_cast<float>(boost) };
+ RecoveryLUT recoveryLUT(&metadata);
+ 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),
applyRecoveryLUT(RgbBlack(), value, recoveryLUT));
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), value, hdrRatio),
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), value, &metadata),
applyRecoveryLUT(RgbWhite(), value, recoveryLUT));
- EXPECT_RGB_NEAR(applyRecovery(RgbRed(), value, hdrRatio),
+ EXPECT_RGB_NEAR(applyRecovery(RgbRed(), value, &metadata),
applyRecoveryLUT(RgbRed(), value, recoveryLUT));
- EXPECT_RGB_NEAR(applyRecovery(RgbGreen(), value, hdrRatio),
+ EXPECT_RGB_NEAR(applyRecovery(RgbGreen(), value, &metadata),
applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
- EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, hdrRatio),
+ EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ }
+ }
+
+ for (int boost = 1; boost <= 10; boost++) {
+ jpegr_metadata metadata = { .maxContentBoost = static_cast<float>(boost),
+ .minContentBoost = 1.0f };
+ RecoveryLUT recoveryLUT(&metadata);
+ 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),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), value, &metadata),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbRed(), value, &metadata),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbGreen(), value, &metadata),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ }
+ }
+
+ for (int boost = 1; boost <= 10; boost++) {
+ jpegr_metadata metadata = { .maxContentBoost = static_cast<float>(boost),
+ .minContentBoost = 1.0f / pow(static_cast<float>(boost),
+ 1.0f / 3.0f) };
+ RecoveryLUT recoveryLUT(&metadata);
+ 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),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), value, &metadata),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbRed(), value, &metadata),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbGreen(), value, &metadata),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, &metadata),
applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
}
}
@@ -623,60 +659,121 @@ TEST_F(RecoveryMapMathTest, ColorConversionLookup) {
}
TEST_F(RecoveryMapMathTest, EncodeRecovery) {
- EXPECT_EQ(encodeRecovery(0.0f, 0.0f, 4.0f), 127);
- EXPECT_EQ(encodeRecovery(0.0f, 1.0f, 4.0f), 127);
- EXPECT_EQ(encodeRecovery(1.0f, 0.0f, 4.0f), 0);
- EXPECT_EQ(encodeRecovery(0.5f, 0.0f, 4.0f), 0);
-
- EXPECT_EQ(encodeRecovery(1.0f, 1.0f, 4.0f), 127);
- EXPECT_EQ(encodeRecovery(1.0f, 4.0f, 4.0f), 255);
- EXPECT_EQ(encodeRecovery(1.0f, 5.0f, 4.0f), 255);
- EXPECT_EQ(encodeRecovery(4.0f, 1.0f, 4.0f), 0);
- EXPECT_EQ(encodeRecovery(4.0f, 0.5f, 4.0f), 0);
- EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 4.0f), 191);
- EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 4.0f), 63);
-
- EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 2.0f), 255);
- EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 2.0f), 0);
- EXPECT_EQ(encodeRecovery(1.0f, 1.41421f, 2.0f), 191);
- EXPECT_EQ(encodeRecovery(1.41421f, 1.0f, 2.0f), 63);
-
- EXPECT_EQ(encodeRecovery(1.0f, 8.0f, 8.0f), 255);
- EXPECT_EQ(encodeRecovery(8.0f, 1.0f, 8.0f), 0);
- EXPECT_EQ(encodeRecovery(1.0f, 2.82843f, 8.0f), 191);
- EXPECT_EQ(encodeRecovery(2.82843f, 1.0f, 8.0f), 63);
+ jpegr_metadata metadata = { .maxContentBoost = 4.0f,
+ .minContentBoost = 1.0f / 4.0f };
+
+ EXPECT_EQ(encodeRecovery(0.0f, 0.0f, &metadata), 127);
+ EXPECT_EQ(encodeRecovery(0.0f, 1.0f, &metadata), 127);
+ EXPECT_EQ(encodeRecovery(1.0f, 0.0f, &metadata), 0);
+ EXPECT_EQ(encodeRecovery(0.5f, 0.0f, &metadata), 0);
+
+ EXPECT_EQ(encodeRecovery(1.0f, 1.0f, &metadata), 127);
+ EXPECT_EQ(encodeRecovery(1.0f, 4.0f, &metadata), 255);
+ EXPECT_EQ(encodeRecovery(1.0f, 5.0f, &metadata), 255);
+ EXPECT_EQ(encodeRecovery(4.0f, 1.0f, &metadata), 0);
+ EXPECT_EQ(encodeRecovery(4.0f, 0.5f, &metadata), 0);
+ EXPECT_EQ(encodeRecovery(1.0f, 2.0f, &metadata), 191);
+ EXPECT_EQ(encodeRecovery(2.0f, 1.0f, &metadata), 63);
+
+ metadata.maxContentBoost = 2.0f;
+ metadata.minContentBoost = 1.0f / 2.0f;
+
+ EXPECT_EQ(encodeRecovery(1.0f, 2.0f, &metadata), 255);
+ EXPECT_EQ(encodeRecovery(2.0f, 1.0f, &metadata), 0);
+ EXPECT_EQ(encodeRecovery(1.0f, 1.41421f, &metadata), 191);
+ EXPECT_EQ(encodeRecovery(1.41421f, 1.0f, &metadata), 63);
+
+ metadata.maxContentBoost = 8.0f;
+ metadata.minContentBoost = 1.0f / 8.0f;
+
+ EXPECT_EQ(encodeRecovery(1.0f, 8.0f, &metadata), 255);
+ EXPECT_EQ(encodeRecovery(8.0f, 1.0f, &metadata), 0);
+ EXPECT_EQ(encodeRecovery(1.0f, 2.82843f, &metadata), 191);
+ EXPECT_EQ(encodeRecovery(2.82843f, 1.0f, &metadata), 63);
+
+ metadata.maxContentBoost = 8.0f;
+ metadata.minContentBoost = 1.0f;
+
+ EXPECT_EQ(encodeRecovery(0.0f, 0.0f, &metadata), 0);
+ EXPECT_EQ(encodeRecovery(1.0f, 0.0f, &metadata), 0);
+
+ EXPECT_EQ(encodeRecovery(1.0f, 1.0f, &metadata), 0);
+ EXPECT_EQ(encodeRecovery(1.0f, 8.0f, &metadata), 255);
+ EXPECT_EQ(encodeRecovery(1.0f, 4.0f, &metadata), 170);
+ EXPECT_EQ(encodeRecovery(1.0f, 2.0f, &metadata), 85);
+
+ metadata.maxContentBoost = 8.0f;
+ metadata.minContentBoost = 0.5f;
+
+ EXPECT_EQ(encodeRecovery(0.0f, 0.0f, &metadata), 63);
+ EXPECT_EQ(encodeRecovery(1.0f, 0.0f, &metadata), 0);
+
+ EXPECT_EQ(encodeRecovery(1.0f, 1.0f, &metadata), 63);
+ EXPECT_EQ(encodeRecovery(1.0f, 8.0f, &metadata), 255);
+ EXPECT_EQ(encodeRecovery(1.0f, 4.0f, &metadata), 191);
+ EXPECT_EQ(encodeRecovery(1.0f, 2.0f, &metadata), 127);
+ EXPECT_EQ(encodeRecovery(1.0f, 0.7071f, &metadata), 31);
+ EXPECT_EQ(encodeRecovery(1.0f, 0.5f, &metadata), 0);
}
TEST_F(RecoveryMapMathTest, ApplyRecovery) {
- EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), -1.0f, 4.0f), RgbBlack());
- EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, 4.0f), RgbBlack());
- EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 1.0f, 4.0f), RgbBlack());
-
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 4.0f), RgbWhite() / 4.0f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 4.0f), RgbWhite() / 2.0f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 4.0f), RgbWhite());
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 4.0f), RgbWhite() * 2.0f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 4.0f), RgbWhite() * 4.0f);
-
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 2.0f), RgbWhite() / 2.0f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 2.0f), RgbWhite() / 1.41421f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 2.0f), RgbWhite());
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 2.0f), RgbWhite() * 1.41421f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 2.0f), RgbWhite() * 2.0f);
-
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 8.0f), RgbWhite() / 8.0f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 8.0f), RgbWhite() / 2.82843f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 8.0f), RgbWhite());
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 8.0f), RgbWhite() * 2.82843f);
- EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 8.0f), RgbWhite() * 8.0f);
+ jpegr_metadata metadata = { .maxContentBoost = 4.0f,
+ .minContentBoost = 1.0f / 4.0f };
+
+ EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, &metadata), RgbBlack());
+ EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.5f, &metadata), RgbBlack());
+ EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 1.0f, &metadata), RgbBlack());
+
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, &metadata), RgbWhite() / 4.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.25f, &metadata), RgbWhite() / 2.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, &metadata), RgbWhite());
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.75f, &metadata), RgbWhite() * 2.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, &metadata), RgbWhite() * 4.0f);
+
+ metadata.maxContentBoost = 2.0f;
+ metadata.minContentBoost = 1.0f / 2.0f;
+
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, &metadata), RgbWhite() / 2.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.25f, &metadata), RgbWhite() / 1.41421f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, &metadata), RgbWhite());
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.75f, &metadata), RgbWhite() * 1.41421f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, &metadata), RgbWhite() * 2.0f);
+
+ metadata.maxContentBoost = 8.0f;
+ metadata.minContentBoost = 1.0f / 8.0f;
+
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, &metadata), RgbWhite() / 8.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.25f, &metadata), RgbWhite() / 2.82843f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, &metadata), RgbWhite());
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.75f, &metadata), RgbWhite() * 2.82843f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, &metadata), RgbWhite() * 8.0f);
+
+ metadata.maxContentBoost = 8.0f;
+ metadata.minContentBoost = 1.0f;
+
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, &metadata), RgbWhite());
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f / 3.0f, &metadata), RgbWhite() * 2.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 2.0f / 3.0f, &metadata), RgbWhite() * 4.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, &metadata), RgbWhite() * 8.0f);
+
+ metadata.maxContentBoost = 8.0f;
+ metadata.minContentBoost = 0.5f;
+
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, &metadata), RgbWhite() / 2.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.25f, &metadata), RgbWhite());
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, &metadata), RgbWhite() * 2.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.75f, &metadata), RgbWhite() * 4.0f);
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, &metadata), RgbWhite() * 8.0f);
Color e = {{{ 0.0f, 0.5f, 1.0f }}};
-
- EXPECT_RGB_NEAR(applyRecovery(e, -1.0f, 4.0f), e / 4.0f);
- EXPECT_RGB_NEAR(applyRecovery(e, -0.5f, 4.0f), e / 2.0f);
- EXPECT_RGB_NEAR(applyRecovery(e, 0.0f, 4.0f), e);
- EXPECT_RGB_NEAR(applyRecovery(e, 0.5f, 4.0f), e * 2.0f);
- EXPECT_RGB_NEAR(applyRecovery(e, 1.0f, 4.0f), e * 4.0f);
+ metadata.maxContentBoost = 4.0f;
+ metadata.minContentBoost = 1.0f / 4.0f;
+
+ EXPECT_RGB_NEAR(applyRecovery(e, 0.0f, &metadata), e / 4.0f);
+ EXPECT_RGB_NEAR(applyRecovery(e, 0.25f, &metadata), e / 2.0f);
+ 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);
}
TEST_F(RecoveryMapMathTest, GetYuv420Pixel) {
@@ -785,8 +882,10 @@ TEST_F(RecoveryMapMathTest, SampleMap) {
// Instead of reimplementing the sampling algorithm, confirm that the
// sample output is within the range of the min and max of the nearest
// points.
- EXPECT_THAT(sampleMap(&image, kMapScaleFactor, x, y, idwTable),
+ EXPECT_THAT(sampleMap(&image, kMapScaleFactor, x, y),
testing::AllOf(testing::Ge(min), testing::Le(max)));
+ EXPECT_EQ(sampleMap(&image, kMapScaleFactor, x, y, idwTable),
+ sampleMap(&image, kMapScaleFactor, x, y));
}
}
}
@@ -882,60 +981,89 @@ TEST_F(RecoveryMapMathTest, GenerateMapLuminancePq) {
}
TEST_F(RecoveryMapMathTest, ApplyMap) {
- EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, 8.0f),
+ jpegr_metadata metadata = { .maxContentBoost = 8.0f,
+ .minContentBoost = 1.0f / 8.0f };
+
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, &metadata),
RgbWhite() * 8.0f);
- EXPECT_RGB_EQ(Recover(YuvBlack(), 1.0f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvBlack(), 1.0f, &metadata),
RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 1.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 1.0f, &metadata),
RgbRed() * 8.0f);
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 1.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 1.0f, &metadata),
RgbGreen() * 8.0f);
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 1.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 1.0f, &metadata),
RgbBlue() * 8.0f);
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.75f, &metadata),
RgbWhite() * sqrt(8.0f));
- EXPECT_RGB_EQ(Recover(YuvBlack(), 0.5f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvBlack(), 0.75f, &metadata),
RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.5f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.75f, &metadata),
RgbRed() * sqrt(8.0f));
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.5f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.75f, &metadata),
RgbGreen() * sqrt(8.0f));
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.5f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.75f, &metadata),
RgbBlue() * sqrt(8.0f));
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, &metadata),
RgbWhite());
- EXPECT_RGB_EQ(Recover(YuvBlack(), 0.0f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvBlack(), 0.5f, &metadata),
RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.5f, &metadata),
RgbRed());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.5f, &metadata),
RgbGreen());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.5f, &metadata),
RgbBlue());
- EXPECT_RGB_EQ(Recover(YuvWhite(), -0.5f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.25f, &metadata),
RgbWhite() / sqrt(8.0f));
- EXPECT_RGB_EQ(Recover(YuvBlack(), -0.5f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvBlack(), 0.25f, &metadata),
RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -0.5f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.25f, &metadata),
RgbRed() / sqrt(8.0f));
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -0.5f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.25f, &metadata),
RgbGreen() / sqrt(8.0f));
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -0.5f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.25f, &metadata),
RgbBlue() / sqrt(8.0f));
- EXPECT_RGB_EQ(Recover(YuvWhite(), -1.0f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, &metadata),
RgbWhite() / 8.0f);
- EXPECT_RGB_EQ(Recover(YuvBlack(), -1.0f, 8.0f),
+ EXPECT_RGB_EQ(Recover(YuvBlack(), 0.0f, &metadata),
RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -1.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.0f, &metadata),
RgbRed() / 8.0f);
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -1.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.0f, &metadata),
RgbGreen() / 8.0f);
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -1.0f, 8.0f),
+ EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.0f, &metadata),
RgbBlue() / 8.0f);
+
+ metadata.maxContentBoost = 8.0f;
+ metadata.minContentBoost = 1.0f;
+
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, &metadata),
+ RgbWhite() * 8.0f);
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 2.0f / 3.0f, &metadata),
+ RgbWhite() * 4.0f);
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f / 3.0f, &metadata),
+ RgbWhite() * 2.0f);
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, &metadata),
+ RgbWhite());
+
+ metadata.maxContentBoost = 8.0f;
+ metadata.minContentBoost = 0.5f;;
+
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, &metadata),
+ RgbWhite() * 8.0f);
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.75, &metadata),
+ RgbWhite() * 4.0f);
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, &metadata),
+ RgbWhite() * 2.0f);
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.25f, &metadata),
+ RgbWhite());
+ EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, &metadata),
+ RgbWhite() / 2.0f);
}
} // namespace android::recoverymap