Skip to content

Commit

Permalink
Allow for larger excursions of min, max content boost
Browse files Browse the repository at this point in the history
Current implementation clips min/max content boost to a smaller range.
Allow for larger excursions for better hdr intent representation.

This is not enabled by default and is enabled in best quality encoding
preset.

Test: ./ultrahdr_app <options> -D 1
Test: ./ultrahdr_unit_test
  • Loading branch information
ram-mohan authored and DichenZhang1 committed Aug 19, 2024
1 parent 4ef6913 commit 04788ce
Show file tree
Hide file tree
Showing 10 changed files with 449 additions and 192 deletions.
42 changes: 28 additions & 14 deletions examples/ultrahdr_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,17 +244,20 @@ static bool writeFile(const char* filename, uhdr_raw_image_t* img) {

class UltraHdrAppInput {
public:
UltraHdrAppInput(
const char* hdrIntentRawFile, const char* sdrIntentRawFile,
const char* sdrIntentCompressedFile, const char* gainmapCompressedFile,
const char* gainmapMetadataCfgFile, const char* exifFile, const char* outputFile,
size_t width, size_t height, uhdr_img_fmt_t hdrCf = UHDR_IMG_FMT_32bppRGBA1010102,
uhdr_img_fmt_t sdrCf = UHDR_IMG_FMT_32bppRGBA8888,
uhdr_color_gamut_t hdrCg = UHDR_CG_DISPLAY_P3, uhdr_color_gamut_t sdrCg = UHDR_CG_BT_709,
uhdr_color_transfer_t hdrTf = UHDR_CT_HLG, int quality = 95,
uhdr_color_transfer_t oTf = UHDR_CT_HLG, uhdr_img_fmt_t oFmt = UHDR_IMG_FMT_32bppRGBA1010102,
bool isHdrCrFull = false, int gainmapScaleFactor = 4, int gainmapQuality = 85,
bool enableMultiChannelGainMap = false, float gamma = 1.0f, bool enableGLES = false)
UltraHdrAppInput(const char* hdrIntentRawFile, const char* sdrIntentRawFile,
const char* sdrIntentCompressedFile, const char* gainmapCompressedFile,
const char* gainmapMetadataCfgFile, const char* exifFile, const char* outputFile,
size_t width, size_t height,
uhdr_img_fmt_t hdrCf = UHDR_IMG_FMT_32bppRGBA1010102,
uhdr_img_fmt_t sdrCf = UHDR_IMG_FMT_32bppRGBA8888,
uhdr_color_gamut_t hdrCg = UHDR_CG_DISPLAY_P3,
uhdr_color_gamut_t sdrCg = UHDR_CG_BT_709,
uhdr_color_transfer_t hdrTf = UHDR_CT_HLG, int quality = 95,
uhdr_color_transfer_t oTf = UHDR_CT_HLG,
uhdr_img_fmt_t oFmt = UHDR_IMG_FMT_32bppRGBA1010102, bool isHdrCrFull = false,
int gainmapScaleFactor = 4, int gainmapQuality = 85,
bool enableMultiChannelGainMap = false, float gamma = 1.0f,
bool enableGLES = false, uhdr_enc_preset_t encPreset = UHDR_USAGE_REALTIME)
: mHdrIntentRawFile(hdrIntentRawFile),
mSdrIntentRawFile(sdrIntentRawFile),
mSdrIntentCompressedFile(sdrIntentCompressedFile),
Expand All @@ -279,6 +282,7 @@ class UltraHdrAppInput {
mUseMultiChannelGainMap(enableMultiChannelGainMap),
mGamma(gamma),
mEnableGLES(enableGLES),
mEncPreset(encPreset),
mMode(0){};

UltraHdrAppInput(const char* gainmapMetadataCfgFile, const char* uhdrFile, const char* outputFile,
Expand Down Expand Up @@ -308,6 +312,7 @@ class UltraHdrAppInput {
mUseMultiChannelGainMap(false),
mGamma(1.0f),
mEnableGLES(enableGLES),
mEncPreset(UHDR_USAGE_REALTIME),
mMode(1){};

~UltraHdrAppInput() {
Expand Down Expand Up @@ -387,6 +392,7 @@ class UltraHdrAppInput {
const bool mUseMultiChannelGainMap;
const float mGamma;
const bool mEnableGLES;
const uhdr_enc_preset_t mEncPreset;
const int mMode;

uhdr_raw_image_t mRawP010Image{};
Expand Down Expand Up @@ -683,6 +689,7 @@ bool UltraHdrAppInput::encode() {
RET_IF_ERR(uhdr_enc_set_using_multi_channel_gainmap(handle, mUseMultiChannelGainMap))
RET_IF_ERR(uhdr_enc_set_gainmap_scale_factor(handle, mMapDimensionScaleFactor))
RET_IF_ERR(uhdr_enc_set_gainmap_gamma(handle, mGamma))
RET_IF_ERR(uhdr_enc_set_preset(handle, mEncPreset))
if (mEnableGLES) {
RET_IF_ERR(uhdr_enable_gpu_acceleration(handle, mEnableGLES))
}
Expand Down Expand Up @@ -1348,6 +1355,9 @@ static void usage(const char* name) {
"real number (1.0 : default)].\n");
fprintf(stderr,
" -M select multi channel gain map, optional. [0:disable (default), 1:enable]. \n");
fprintf(
stderr,
" -D select encoding preset, optional. [0:real time (default), 1:best quality]. \n");
fprintf(stderr, " -x binary input resource containing exif data to insert, optional. \n");
fprintf(stderr, "\n## decoder options : \n");
fprintf(stderr, " -j ultra hdr compressed input resource, required. \n");
Expand Down Expand Up @@ -1425,7 +1435,7 @@ static void usage(const char* name) {
fprintf(stderr, "\n## encode at high quality :\n");
fprintf(stderr,
" ultrahdr_app -m 0 -p hdr_intent.raw -y sdr_intent.raw -w 640 -h 480 -c <select> -C "
"<select> -t <select> -s 1 -M 1 -Q 98 -q 98\n");
"<select> -t <select> -s 1 -M 1 -Q 98 -q 98 -D 1\n");

fprintf(stderr, "\n## decode api :\n");
fprintf(stderr, " ultrahdr_app -m 1 -j cosmat_1920x1080_hdr.jpg \n");
Expand All @@ -1435,7 +1445,7 @@ static void usage(const char* name) {
}

int main(int argc, char* argv[]) {
char opt_string[] = "p:y:i:g:f:w:h:C:c:t:q:o:O:m:j:e:a:b:z:R:s:M:Q:G:x:u:";
char opt_string[] = "p:y:i:g:f:w:h:C:c:t:q:o:O:m:j:e:a:b:z:R:s:M:Q:G:x:u:D:";
char *hdr_intent_raw_file = nullptr, *sdr_intent_raw_file = nullptr, *uhdr_file = nullptr,
*sdr_intent_compressed_file = nullptr, *gainmap_compressed_file = nullptr,
*gainmap_metadata_cfg_file = nullptr, *output_file = nullptr, *exif_file = nullptr;
Expand All @@ -1456,6 +1466,7 @@ int main(int argc, char* argv[]) {
int compute_psnr = 0;
float gamma = 1.0f;
bool enable_gles = false;
uhdr_enc_preset_t enc_preset = UHDR_USAGE_REALTIME;
int ch;
while ((ch = getopt_s(argc, argv, opt_string)) != -1) {
switch (ch) {
Expand Down Expand Up @@ -1541,6 +1552,9 @@ int main(int argc, char* argv[]) {
case 'u':
enable_gles = atoi(optarg_s) == 1 ? true : false;
break;
case 'D':
enc_preset = static_cast<uhdr_enc_preset_t>(atoi(optarg_s));
break;
default:
usage(argv[0]);
return -1;
Expand Down Expand Up @@ -1568,7 +1582,7 @@ int main(int argc, char* argv[]) {
gainmap_compressed_file, gainmap_metadata_cfg_file, exif_file,
output_file ? output_file : "out.jpeg", width, height, hdr_cf, sdr_cf, hdr_cg, sdr_cg,
hdr_tf, quality, out_tf, out_cf, use_full_range_color_hdr, gainmap_scale_factor,
gainmap_compression_quality, use_multi_channel_gainmap, gamma, enable_gles);
gainmap_compression_quality, use_multi_channel_gainmap, gamma, enable_gles, enc_preset);
if (!appInput.encode()) return -1;
if (compute_psnr == 1) {
if (!appInput.decode()) return -1;
Expand Down
4 changes: 4 additions & 0 deletions fuzzer/ultrahdr_enc_fuzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ void UltraHdrEncFuzzer::process() {
// gainmap scale factor
auto gm_scale_factor = mFdp.ConsumeIntegralInRange<int>(1, 128);

// encoding speed preset
auto enc_preset = static_cast<uhdr_enc_preset_t>(mFdp.ConsumeIntegralInRange<int>(0, 1));

std::unique_ptr<uint32_t[]> bufferHdr = nullptr;
std::unique_ptr<uint16_t[]> bufferYHdr = nullptr;
std::unique_ptr<uint16_t[]> bufferUVHdr = nullptr;
Expand Down Expand Up @@ -265,6 +268,7 @@ void UltraHdrEncFuzzer::process() {
ON_ERR(uhdr_enc_set_quality(enc_handle, gainmap_quality, UHDR_GAIN_MAP_IMG))
ON_ERR(uhdr_enc_set_gainmap_scale_factor(enc_handle, gm_scale_factor))
ON_ERR(uhdr_enc_set_using_multi_channel_gainmap(enc_handle, multi_channel_gainmap))
ON_ERR(uhdr_enc_set_preset(enc_handle, enc_preset))

uhdr_error_info_t status = {UHDR_CODEC_OK, 0, ""};
if (muxSwitch == 0 || muxSwitch == 1) { // api 0 or api 1
Expand Down
18 changes: 4 additions & 14 deletions lib/include/ultrahdr/gainmapmath.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ struct GainLUT {

GainLUT(uhdr_gainmap_metadata_ext_t* metadata, float displayBoost) {
this->mGammaInv = 1.0f / metadata->gamma;
float boostFactor = displayBoost > 0 ? displayBoost / metadata->max_content_boost : 1.0f;
float boostFactor = displayBoost > 0 ? displayBoost / metadata->hdr_capacity_max : 1.0f;
for (int32_t idx = 0; idx < kGainFactorNumEntries; idx++) {
float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
float logBoost = log2(metadata->min_content_boost) * (1.0f - value) +
Expand Down Expand Up @@ -540,23 +540,17 @@ void transformYuv444(uhdr_raw_image_t* image, const std::array<float, 9>& coeffs

/*
* Calculate the 8-bit unsigned integer gain value for the given SDR and HDR
* luminances in linear space, and the hdr ratio to encode against.
*
* Note: since this library always uses gamma of 1.0, offsetSdr of 0.0, and
* offsetHdr of 0.0, this function doesn't handle different metadata values for
* these fields.
* luminances in linear space and gainmap metadata fields.
*/
uint8_t encodeGain(float y_sdr, float y_hdr, uhdr_gainmap_metadata_ext_t* metadata);
uint8_t encodeGain(float y_sdr, float y_hdr, uhdr_gainmap_metadata_ext_t* metadata,
float log2MinContentBoost, float log2MaxContentBoost);
float computeGain(float sdr, float hdr);
uint8_t affineMapGain(float gainlog2, float mingainlog2, float maxgainlog2, float gamma);

/*
* Calculates the linear luminance in nits after applying the given gain
* value, with the given hdr ratio, to the given sdr input in the range [0, 1].
*
* Note: similar to encodeGain(), this function only supports gamma 1.0,
* offsetSdr 0.0, offsetHdr 0.0, hdrCapacityMin 1.0, and hdrCapacityMax equal to
* gainMapMax, as this library encodes.
*/
Color applyGain(Color e, float gain, uhdr_gainmap_metadata_ext_t* metadata);
Color applyGain(Color e, float gain, uhdr_gainmap_metadata_ext_t* metadata, float displayBoost);
Expand All @@ -565,10 +559,6 @@ Color applyGainLUT(Color e, float gain, GainLUT& gainLUT);
/*
* Apply gain in R, G and B channels, with the given hdr ratio, to the given sdr input
* in the range [0, 1].
*
* Note: similar to encodeGain(), this function only supports gamma 1.0,
* offsetSdr 0.0, offsetHdr 0.0, hdrCapacityMin 1.0, and hdrCapacityMax equal to
* gainMapMax, as this library encodes.
*/
Color applyGain(Color e, Color gain, uhdr_gainmap_metadata_ext_t* metadata);
Color applyGain(Color e, Color gain, uhdr_gainmap_metadata_ext_t* metadata, float displayBoost);
Expand Down
3 changes: 2 additions & 1 deletion lib/include/ultrahdr/jpegr.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class JpegR {
size_t mapDimensionScaleFactor = kMapDimensionScaleFactorDefault,
int mapCompressQuality = kMapCompressQualityDefault,
bool useMultiChannelGainMap = kUseMultiChannelGainMapDefault,
float gamma = kGainMapGammaDefault);
float gamma = kGainMapGammaDefault, uhdr_enc_preset_t preset = UHDR_USAGE_REALTIME);

/*!\brief Encode API-0.
*
Expand Down Expand Up @@ -571,6 +571,7 @@ class JpegR {
int mMapCompressQuality; // gain map quality factor
bool mUseMultiChannelGainMap; // enable multichannel gain map
float mGamma; // gain map gamma parameter
uhdr_enc_preset_t mEncPreset; // encoding speed preset
};

struct GlobalTonemapOutputs {
Expand Down
1 change: 1 addition & 0 deletions lib/include/ultrahdr/ultrahdrcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ struct uhdr_encoder_private : uhdr_codec_private {
int m_gainmap_scale_factor;
bool m_use_multi_channel_gainmap;
float m_gamma;
uhdr_enc_preset_t m_enc_preset;

// internal data
std::unique_ptr<ultrahdr::uhdr_compressed_image_ext_t> m_compressed_output_buffer;
Expand Down
26 changes: 21 additions & 5 deletions lib/src/gainmapmath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ SamplePixelFn getSamplePixelFn(uhdr_img_fmt_t format) {
float getMaxDisplayMasteringLuminance(uhdr_color_transfer_t transfer) {
switch (transfer) {
case UHDR_CT_LINEAR:
// TODO: configure maxCLL correctly for linear tf
// TODO: configure MDML correctly for linear tf
return kHlgMaxNits;
case UHDR_CT_HLG:
return kHlgMaxNits;
Expand Down Expand Up @@ -647,6 +647,22 @@ uint8_t encodeGain(float y_sdr, float y_hdr, uhdr_gainmap_metadata_ext_t* metada
return static_cast<uint8_t>(gain_normalized_gamma * 255.0f);
}

float computeGain(float sdr, float hdr) {
if (sdr == 0.0f) return 0.0f; // for sdr black return no gain
if (hdr == 0.0f) { // for hdr black, return a gain large enough to attenuate the sdr pel
float offset = (1.0f / 64);
return log2(offset / (offset + sdr));
}
return log2(hdr / sdr);
}

uint8_t affineMapGain(float gainlog2, float mingainlog2, float maxgainlog2, float gamma) {
float mappedVal = (gainlog2 - mingainlog2) / (maxgainlog2 - mingainlog2);
if (gamma != 1.0f) mappedVal = pow(mappedVal, gamma);
mappedVal *= 255;
return CLIP3(mappedVal + 0.5f, 0, 255);
}

Color applyGain(Color e, float gain, uhdr_gainmap_metadata_ext_t* metadata) {
gain = pow(gain, 1.0f / metadata->gamma);
float logBoost =
Expand All @@ -659,7 +675,7 @@ Color applyGain(Color e, float gain, uhdr_gainmap_metadata_ext_t* metadata, floa
gain = pow(gain, 1.0f / metadata->gamma);
float logBoost =
log2(metadata->min_content_boost) * (1.0f - gain) + log2(metadata->max_content_boost) * gain;
float gainFactor = exp2(logBoost * displayBoost / metadata->max_content_boost);
float gainFactor = exp2(logBoost * displayBoost / metadata->hdr_capacity_max);
return e * gainFactor;
}

Expand Down Expand Up @@ -694,9 +710,9 @@ Color applyGain(Color e, Color gain, uhdr_gainmap_metadata_ext_t* metadata, floa
log2(metadata->max_content_boost) * gain.g;
float logBoostB = log2(metadata->min_content_boost) * (1.0f - gain.b) +
log2(metadata->max_content_boost) * gain.b;
float gainFactorR = exp2(logBoostR * displayBoost / metadata->max_content_boost);
float gainFactorG = exp2(logBoostG * displayBoost / metadata->max_content_boost);
float gainFactorB = exp2(logBoostB * displayBoost / metadata->max_content_boost);
float gainFactorR = exp2(logBoostR * displayBoost / metadata->hdr_capacity_max);
float gainFactorG = exp2(logBoostG * displayBoost / metadata->hdr_capacity_max);
float gainFactorB = exp2(logBoostB * displayBoost / metadata->hdr_capacity_max);
return {{{e.r * gainFactorR, e.g * gainFactorG, e.b * gainFactorB}}};
}

Expand Down
Loading

0 comments on commit 04788ce

Please sign in to comment.