Skip to content

Commit

Permalink
configure hdr display max brightness
Browse files Browse the repository at this point in the history
If the input color transfer is linear, there is no proper peak
brightness configuration. Also hlg is not absolute standard allowing
room for different peak brightness levels. This change addresses this.

Test: ./ultrahdr_unit_test
  • Loading branch information
ram-mohan committed Aug 30, 2024
1 parent 3250b81 commit f323a26
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 63 deletions.
59 changes: 36 additions & 23 deletions examples/ultrahdr_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,21 +245,19 @@ 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, uhdr_enc_preset_t encPreset = UHDR_USAGE_REALTIME,
float minContentBoost = FLT_MIN, float maxContentBoost = FLT_MAX)
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, float minContentBoost = FLT_MIN,
float maxContentBoost = FLT_MAX, float maxDispBrightness = -1.0f)
: mHdrIntentRawFile(hdrIntentRawFile),
mSdrIntentRawFile(sdrIntentRawFile),
mSdrIntentCompressedFile(sdrIntentCompressedFile),
Expand Down Expand Up @@ -287,6 +285,7 @@ class UltraHdrAppInput {
mEncPreset(encPreset),
mMinContentBoost(minContentBoost),
mMaxContentBoost(maxContentBoost),
mMaxDispBrightness(maxDispBrightness),
mMode(0){};

UltraHdrAppInput(const char* gainmapMetadataCfgFile, const char* uhdrFile, const char* outputFile,
Expand Down Expand Up @@ -319,6 +318,7 @@ class UltraHdrAppInput {
mEncPreset(UHDR_USAGE_REALTIME),
mMinContentBoost(FLT_MIN),
mMaxContentBoost(FLT_MAX),
mMaxDispBrightness(-1.0f),
mMode(1){};

~UltraHdrAppInput() {
Expand Down Expand Up @@ -401,6 +401,7 @@ class UltraHdrAppInput {
const uhdr_enc_preset_t mEncPreset;
const float mMinContentBoost;
const float mMaxContentBoost;
const float mMaxDispBrightness;
const int mMode;

uhdr_raw_image_t mRawP010Image{};
Expand Down Expand Up @@ -701,6 +702,9 @@ bool UltraHdrAppInput::encode() {
if (mMinContentBoost != FLT_MIN || mMaxContentBoost != FLT_MAX) {
RET_IF_ERR(uhdr_enc_set_min_max_content_boost(handle, mMinContentBoost, mMaxContentBoost))
}
if (mMaxDispBrightness != -1.0f) {
RET_IF_ERR(uhdr_enc_set_max_display_brightness(handle, mMaxDispBrightness))
}
if (mEnableGLES) {
RET_IF_ERR(uhdr_enable_gpu_acceleration(handle, mEnableGLES))
}
Expand Down Expand Up @@ -1373,6 +1377,11 @@ static void usage(const char* name) {
" -k min content boost recommendation, must be in linear scale, optional \n");
fprintf(stderr,
" -K max content boost recommendation, must be in linear scale, optional \n");
fprintf(stderr,
" -L set maximum hdr display brightness in nits. \n"
" required if the input color transfer is linear. \n"
" optional if the input color transfer is HLG or PQ. \n"
" any real number in range [203, 10000]. \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 @@ -1460,7 +1469,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:D:k:K:";
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:k:K:L:";
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 @@ -1484,6 +1493,7 @@ int main(int argc, char* argv[]) {
uhdr_enc_preset_t enc_preset = UHDR_USAGE_REALTIME;
float min_content_boost = FLT_MIN;
float max_content_boost = FLT_MAX;
float max_disp_brightness = -1.0f;
int ch;
while ((ch = getopt_s(argc, argv, opt_string)) != -1) {
switch (ch) {
Expand Down Expand Up @@ -1578,6 +1588,9 @@ int main(int argc, char* argv[]) {
case 'K':
max_content_boost = atof(optarg_s);
break;
case 'L':
max_disp_brightness = atof(optarg_s);
break;
default:
usage(argv[0]);
return -1;
Expand All @@ -1600,13 +1613,13 @@ int main(int argc, char* argv[]) {
std::cerr << "did not receive raw resources for encoding." << std::endl;
return -1;
}
UltraHdrAppInput appInput(hdr_intent_raw_file, sdr_intent_raw_file, sdr_intent_compressed_file,
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, enc_preset, min_content_boost, max_content_boost);
UltraHdrAppInput appInput(
hdr_intent_raw_file, sdr_intent_raw_file, sdr_intent_compressed_file,
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, enc_preset,
min_content_boost, max_content_boost, max_disp_brightness);
if (!appInput.encode()) return -1;
if (compute_psnr == 1) {
if (!appInput.decode()) return -1;
Expand Down
5 changes: 0 additions & 5 deletions lib/include/ultrahdr/gainmapmath.h
Original file line number Diff line number Diff line change
Expand Up @@ -490,11 +490,6 @@ PutPixelFn putPixelFn(uhdr_img_fmt_t format);
*/
bool isPixelFormatRgb(uhdr_img_fmt_t format);

/*
* Get max display mastering luminance in nits
*/
float getMaxDisplayMasteringLuminance(uhdr_color_transfer_t transfer);

/*
* Convert between YUV encodings, according to ITU-R BT.709-6, ITU-R BT.601-7, and ITU-R BT.2100-2.
*
Expand Down
12 changes: 11 additions & 1 deletion lib/include/ultrahdr/jpegr.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class JpegR {
int mapCompressQuality = kMapCompressQualityDefault,
bool useMultiChannelGainMap = kUseMultiChannelGainMapDefault,
float gamma = kGainMapGammaDefault, uhdr_enc_preset_t preset = UHDR_USAGE_REALTIME,
float minContentBoost = FLT_MIN, float maxContentBoost = FLT_MAX);
float minContentBoost = FLT_MIN, float maxContentBoost = FLT_MAX,
float maxDispBrightness = -1.0f);

/*!\brief Encode API-0.
*
Expand Down Expand Up @@ -547,6 +548,14 @@ class JpegR {
uhdr_error_info_t convertYuv(uhdr_raw_image_t* image, uhdr_color_gamut_t src_encoding,
uhdr_color_gamut_t dst_encoding);

/*!\brief Get max display brightness in nits
*
* \param[in] transfer intent's color transfer characteristics
*
* \return max display brightness in nits
*/
float getMasteringDisplayMaxLuminance(uhdr_color_transfer_t transfer);

/*
* This method will check the validity of the input arguments.
*
Expand Down Expand Up @@ -593,6 +602,7 @@ class JpegR {
uhdr_enc_preset_t mEncPreset; // encoding speed preset
float mMinContentBoost; // min content boost recommendation
float mMaxContentBoost; // max content boost recommendation
float mMaxDispBrightness; // mastering display max luminance in nits
};

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 @@ -355,6 +355,7 @@ struct uhdr_encoder_private : uhdr_codec_private {
uhdr_enc_preset_t m_enc_preset;
float m_min_content_boost;
float m_max_content_boost;
float m_max_disp_brightness;

// internal data
std::unique_ptr<ultrahdr::uhdr_compressed_image_ext_t> m_compressed_output_buffer;
Expand Down
17 changes: 0 additions & 17 deletions lib/src/gainmapmath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -512,23 +512,6 @@ bool isPixelFormatRgb(uhdr_img_fmt_t format) {
format == UHDR_IMG_FMT_32bppRGBA1010102;
}

float getMaxDisplayMasteringLuminance(uhdr_color_transfer_t transfer) {
switch (transfer) {
case UHDR_CT_LINEAR:
// TODO: configure MDML correctly for linear tf
return kHlgMaxNits;
case UHDR_CT_HLG:
return kHlgMaxNits;
case UHDR_CT_PQ:
return kPqMaxNits;
case UHDR_CT_SRGB:
return kSdrWhiteNits;
case UHDR_CT_UNSPECIFIED:
return -1.0f;
}
return -1.0f;
}

// All of these conversions are derived from the respective input YUV->RGB conversion followed by
// the RGB->YUV for the receiving encoding. They are consistent with the RGB<->YUV functions in
// gainmapmath.cpp, given that we use BT.709 encoding for sRGB and BT.601 encoding for Display-P3,
Expand Down
9 changes: 5 additions & 4 deletions lib/src/gpu/applygainmap_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,13 @@ static const std::string applyGainMapShader = R"__SHADER__(
uniform float logMinBoost;
uniform float logMaxBoost;
uniform float weight;
uniform float displayBoost;
uniform float hdrCapacityMax;
float applyGainMapSample(const float channel, float gain) {
gain = pow(gain, 1.0f / gamma);
float logBoost = logMinBoost * (1.0f - gain) + logMaxBoost * gain;
logBoost = exp2(logBoost * weight);
return channel * logBoost / displayBoost;
return channel * logBoost / hdrCapacityMax;
}
vec3 applyGain(const vec3 color, const vec3 gain) {
Expand Down Expand Up @@ -302,15 +302,16 @@ uhdr_error_info_t applyGainMapGLES(uhdr_raw_image_t* sdr_intent, uhdr_raw_image_
GLint logMinBoostLocation = glGetUniformLocation(shaderProgram, "logMinBoost");
GLint logMaxBoostLocation = glGetUniformLocation(shaderProgram, "logMaxBoost");
GLint weightLocation = glGetUniformLocation(shaderProgram, "weight");
GLint displayBoostLocation = glGetUniformLocation(shaderProgram, "displayBoost");
GLint hdrCapacityMaxLocation = glGetUniformLocation(shaderProgram, "hdrCapacityMax");

glUniform1i(pWidthLocation, sdr_intent->w);
glUniform1i(pHeightLocation, sdr_intent->h);
glUniform1f(gammaLocation, gainmap_metadata->gamma);
glUniform1f(logMinBoostLocation, log2(gainmap_metadata->min_content_boost));
glUniform1f(logMaxBoostLocation, log2(gainmap_metadata->max_content_boost));
glUniform1f(weightLocation, display_boost / gainmap_metadata->hdr_capacity_max);
glUniform1f(displayBoostLocation, display_boost);
glUniform1f(hdrCapacityMaxLocation, output_ct == UHDR_CT_PQ ? (kSdrWhiteNits / kPqMaxNits)
: gainmap_metadata->hdr_capacity_max);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, yuvTexture);
Expand Down
Loading

0 comments on commit f323a26

Please sign in to comment.