Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34d28d12 authored by Nick Deakin's avatar Nick Deakin Committed by Android (Google) Code Review
Browse files

Merge "jpegrecoverymap: Add min boost to metadata."

parents 8e8eb792 d19e576f
Loading
Loading
Loading
Loading
+17 −11
Original line number Diff line number Diff line
@@ -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
     *
+26 −10
Original line number Diff line number Diff line
@@ -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);

/*
+30 −21
Original line number Diff line number Diff line
@@ -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);
+28 −44
Original line number Diff line number Diff line
@@ -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;
+132 −18
Original line number Diff line number Diff line
@@ -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
Loading