1 /* 2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ULTRAHDR_JPEGR_H 18 #define ULTRAHDR_JPEGR_H 19 20 #include <array> 21 #include <cfloat> 22 23 #include "ultrahdr/ultrahdr.h" 24 #include "ultrahdr/jpegdecoderhelper.h" 25 #include "ultrahdr/jpegencoderhelper.h" 26 27 namespace ultrahdr { 28 29 // The current JPEGR version that we encode to 30 static const char* const kJpegrVersion = kGainMapVersion; 31 32 // Map is quarter res / sixteenth size 33 static const size_t kMapDimensionScaleFactor = 4; 34 35 // Gain Map width is (image_width / kMapDimensionScaleFactor). If we were to 36 // compress 420 GainMap in jpeg, then we need at least 2 samples. For Grayscale 37 // 1 sample is sufficient. We are using 2 here anyways 38 static const int kMinWidth = 2 * kMapDimensionScaleFactor; 39 static const int kMinHeight = 2 * kMapDimensionScaleFactor; 40 41 /* 42 * Holds information of jpeg image 43 */ 44 struct jpeg_info_struct { 45 std::vector<uint8_t> imgData = std::vector<uint8_t>(0); 46 std::vector<uint8_t> iccData = std::vector<uint8_t>(0); 47 std::vector<uint8_t> exifData = std::vector<uint8_t>(0); 48 std::vector<uint8_t> xmpData = std::vector<uint8_t>(0); 49 size_t width; 50 size_t height; 51 }; 52 53 /* 54 * Holds information of jpegr image 55 */ 56 struct jpegr_info_struct { 57 size_t width; // copy of primary image width (for easier access) 58 size_t height; // copy of primary image height (for easier access) 59 jpeg_info_struct* primaryImgInfo = nullptr; 60 jpeg_info_struct* gainmapImgInfo = nullptr; 61 }; 62 63 /* 64 * Holds information for uncompressed image or gain map. 65 */ 66 struct jpegr_uncompressed_struct { 67 // Pointer to the data location. 68 void* data; 69 // Width of the gain map or the luma plane of the image in pixels. 70 size_t width; 71 // Height of the gain map or the luma plane of the image in pixels. 72 size_t height; 73 // Color gamut. 74 ultrahdr_color_gamut colorGamut; 75 76 // Values below are optional 77 // Pointer to chroma data, if it's NULL, chroma plane is considered to be immediately 78 // after the luma plane. 79 void* chroma_data = nullptr; 80 // Stride of Y plane in number of pixels. 0 indicates the member is uninitialized. If 81 // non-zero this value must be larger than or equal to luma width. If stride is 82 // uninitialized then it is assumed to be equal to luma width. 83 size_t luma_stride = 0; 84 // Stride of UV plane in number of pixels. 85 // 1. If this handle points to P010 image then this value must be larger than 86 // or equal to luma width. 87 // 2. If this handle points to 420 image then this value must be larger than 88 // or equal to (luma width / 2). 89 // NOTE: if chroma_data is nullptr, chroma_stride is irrelevant. Just as the way, 90 // chroma_data is derived from luma ptr, chroma stride is derived from luma stride. 91 size_t chroma_stride = 0; 92 // Pixel format. 93 uhdr_img_fmt_t pixelFormat = UHDR_IMG_FMT_UNSPECIFIED; 94 }; 95 96 /* 97 * Holds information for compressed image or gain map. 98 */ 99 struct jpegr_compressed_struct { 100 // Pointer to the data location. 101 void* data; 102 // Used data length in bytes. 103 int length; 104 // Maximum available data length in bytes. 105 int maxLength; 106 // Color gamut. 107 ultrahdr_color_gamut colorGamut; 108 }; 109 110 /* 111 * Holds information for EXIF metadata. 112 */ 113 struct jpegr_exif_struct { 114 // Pointer to the data location. 115 void* data; 116 // Data length; 117 size_t length; 118 }; 119 120 typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr; 121 typedef struct jpegr_compressed_struct* jr_compressed_ptr; 122 typedef struct jpegr_exif_struct* jr_exif_ptr; 123 typedef struct jpeg_info_struct* j_info_ptr; 124 typedef struct jpegr_info_struct* jr_info_ptr; 125 126 class JpegR { 127 public: 128 /* 129 * Experimental only 130 * 131 * Encode API-0 132 * Compress JPEGR image from 10-bit HDR YUV. 133 * 134 * Tonemap the HDR input to a SDR image, generate gain map from the HDR and SDR images, 135 * compress SDR YUV to 8-bit JPEG and append the gain map to the end of the compressed 136 * JPEG. 137 * @param p010_image_ptr uncompressed HDR image in P010 color format 138 * @param hdr_tf transfer function of the HDR image 139 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 140 * represents the maximum available size of the destination buffer, and it must be 141 * set before calling this method. If the encoded JPEGR size exceeds 142 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 143 * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is 144 * the highest quality 145 * @param exif pointer to the exif metadata. 146 * @return NO_ERROR if encoding succeeds, error code if error occurs. 147 */ 148 status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfer_function hdr_tf, 149 jr_compressed_ptr dest, int quality, jr_exif_ptr exif); 150 151 /* 152 * Encode API-1 153 * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV. 154 * 155 * Generate gain map from the HDR and SDR inputs, compress SDR YUV to 8-bit JPEG and append 156 * the gain map to the end of the compressed JPEG. HDR and SDR inputs must be the same 157 * resolution. SDR input is assumed to use the sRGB transfer function. 158 * @param p010_image_ptr uncompressed HDR image in P010 color format 159 * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format 160 * @param hdr_tf transfer function of the HDR image 161 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 162 * represents the maximum available size of the desitination buffer, and it must be 163 * set before calling this method. If the encoded JPEGR size exceeds 164 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 165 * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is 166 * the highest quality 167 * @param exif pointer to the exif metadata. 168 * @return NO_ERROR if encoding succeeds, error code if error occurs. 169 */ 170 status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_uncompressed_ptr yuv420_image_ptr, 171 ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest, int quality, 172 jr_exif_ptr exif); 173 174 /* 175 * Encode API-2 176 * Compress JPEGR image from 10-bit HDR YUV, 8-bit SDR YUV and compressed 8-bit JPEG. 177 * 178 * This method requires HAL Hardware JPEG encoder. 179 * 180 * Generate gain map from the HDR and SDR inputs, append the gain map to the end of the 181 * compressed JPEG. Adds an ICC profile if one isn't present in the input JPEG image. HDR and 182 * SDR inputs must be the same resolution and color space. SDR image is assumed to use the sRGB 183 * transfer function. 184 * @param p010_image_ptr uncompressed HDR image in P010 color format 185 * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format 186 * @param yuv420jpg_image_ptr SDR image compressed in jpeg format 187 * @param hdr_tf transfer function of the HDR image 188 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 189 * represents the maximum available size of the desitination buffer, and it must be 190 * set before calling this method. If the encoded JPEGR size exceeds 191 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 192 * @return NO_ERROR if encoding succeeds, error code if error occurs. 193 */ 194 status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_uncompressed_ptr yuv420_image_ptr, 195 jr_compressed_ptr yuv420jpg_image_ptr, ultrahdr_transfer_function hdr_tf, 196 jr_compressed_ptr dest); 197 198 /* 199 * Encode API-3 200 * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV. 201 * 202 * This method requires HAL Hardware JPEG encoder. 203 * 204 * Decode the compressed 8-bit JPEG image to YUV SDR, generate gain map from the HDR input 205 * and the decoded SDR result, append the gain map to the end of the compressed JPEG. Adds an 206 * ICC profile if one isn't present in the input JPEG image. HDR and SDR inputs must be the same 207 * resolution. JPEG image is assumed to use the sRGB transfer function. 208 * @param p010_image_ptr uncompressed HDR image in P010 color format 209 * @param yuv420jpg_image_ptr SDR image compressed in jpeg format 210 * @param hdr_tf transfer function of the HDR image 211 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 212 * represents the maximum available size of the desitination buffer, and it must be 213 * set before calling this method. If the encoded JPEGR size exceeds 214 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 215 * @return NO_ERROR if encoding succeeds, error code if error occurs. 216 */ 217 status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_compressed_ptr yuv420jpg_image_ptr, 218 ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest); 219 220 /* 221 * Encode API-4 222 * Assemble JPEGR image from SDR JPEG and gainmap JPEG. 223 * 224 * Assemble the primary JPEG image, the gain map and the metadata to JPEG/R format. Adds an ICC 225 * profile if one isn't present in the input JPEG image. 226 * @param yuv420jpg_image_ptr SDR image compressed in jpeg format 227 * @param gainmapjpg_image_ptr gain map image compressed in jpeg format 228 * @param metadata metadata to be written in XMP of the primary jpeg 229 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 230 * represents the maximum available size of the desitination buffer, and it must be 231 * set before calling this method. If the encoded JPEGR size exceeds 232 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 233 * @return NO_ERROR if encoding succeeds, error code if error occurs. 234 */ 235 status_t encodeJPEGR(jr_compressed_ptr yuv420jpg_image_ptr, 236 jr_compressed_ptr gainmapjpg_image_ptr, ultrahdr_metadata_ptr metadata, 237 jr_compressed_ptr dest); 238 239 /* 240 * Decode API 241 * Decompress JPEGR image. 242 * 243 * This method assumes that the JPEGR image contains an ICC profile with primaries that match 244 * those of a color gamut that this library is aware of; Bt.709, Display-P3, or Bt.2100. It also 245 * assumes the base image uses the sRGB transfer function. 246 * 247 * This method only supports single gain map metadata values for fields that allow multi-channel 248 * metadata values. 249 * @param jpegr_image_ptr compressed JPEGR image. 250 * @param dest destination of the uncompressed JPEGR image. 251 * @param max_display_boost (optional) the maximum available boost supported by a display, 252 * the value must be greater than or equal to 1.0. 253 * @param exif destination of the decoded EXIF metadata. The default value is NULL where the 254 decoder will do nothing about it. If configured not NULL the decoder will write 255 EXIF data into this structure. The format is defined in {@code jpegr_exif_struct} 256 * @param output_format flag for setting output color format. Its value configures the output 257 color format. The default value is {@code JPEGR_OUTPUT_HDR_LINEAR}. 258 ---------------------------------------------------------------------- 259 | output_format | decoded color format to be written | 260 ---------------------------------------------------------------------- 261 | JPEGR_OUTPUT_SDR | RGBA_8888 | 262 ---------------------------------------------------------------------- 263 | JPEGR_OUTPUT_HDR_LINEAR | (default)RGBA_F16 linear | 264 ---------------------------------------------------------------------- 265 | JPEGR_OUTPUT_HDR_PQ | RGBA_1010102 PQ | 266 ---------------------------------------------------------------------- 267 | JPEGR_OUTPUT_HDR_HLG | RGBA_1010102 HLG | 268 ---------------------------------------------------------------------- 269 * @param gainmap_image_ptr destination of the decoded gain map. The default value is NULL 270 where the decoder will do nothing about it. If configured not NULL 271 the decoder will write the decoded gain_map data into this 272 structure. The format is defined in 273 {@code jpegr_uncompressed_struct}. 274 * @param metadata destination of the decoded metadata. The default value is NULL where the 275 decoder will do nothing about it. If configured not NULL the decoder will 276 write metadata into this structure. the format of metadata is defined in 277 {@code ultrahdr_metadata_struct}. 278 * @return NO_ERROR if decoding succeeds, error code if error occurs. 279 */ 280 status_t decodeJPEGR(jr_compressed_ptr jpegr_image_ptr, jr_uncompressed_ptr dest, 281 float max_display_boost = FLT_MAX, jr_exif_ptr exif = nullptr, 282 ultrahdr_output_format output_format = ULTRAHDR_OUTPUT_HDR_LINEAR, 283 jr_uncompressed_ptr gainmap_image_ptr = nullptr, 284 ultrahdr_metadata_ptr metadata = nullptr); 285 286 /* 287 * Gets Info from JPEGR file without decoding it. 288 * 289 * This method only supports single gain map metadata values for fields that allow multi-channel 290 * metadata values. 291 * 292 * The output is filled jpegr_info structure 293 * @param jpegr_image_ptr compressed JPEGR image 294 * @param jpeg_image_info_ptr pointer to jpegr info struct. Members of jpegr_info 295 * are owned by the caller 296 * @return NO_ERROR if JPEGR parsing succeeds, error code otherwise 297 */ 298 status_t getJPEGRInfo(jr_compressed_ptr jpegr_image_ptr, jr_info_ptr jpeg_image_info_ptr); 299 300 protected: 301 /* 302 * This method is called in the encoding pipeline. It will take the uncompressed 8-bit and 303 * 10-bit yuv images as input, and calculate the uncompressed gain map. The input images 304 * must be the same resolution. The SDR input is assumed to use the sRGB transfer function. 305 * 306 * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format 307 * @param p010_image_ptr uncompressed HDR image in P010 color format 308 * @param hdr_tf transfer function of the HDR image 309 * @param metadata everything but "version" is filled in this struct 310 * @param dest location at which gain map image is stored (caller responsible for memory 311 of data). 312 * @param sdr_is_601 if true, then use BT.601 decoding of YUV regardless of SDR image gamut 313 * @return NO_ERROR if calculation succeeds, error code if error occurs. 314 */ 315 status_t generateGainMap(jr_uncompressed_ptr yuv420_image_ptr, jr_uncompressed_ptr p010_image_ptr, 316 ultrahdr_transfer_function hdr_tf, ultrahdr_metadata_ptr metadata, 317 jr_uncompressed_ptr dest, bool sdr_is_601 = false); 318 319 /* 320 * This method is called in the decoding pipeline. It will take the uncompressed (decoded) 321 * 8-bit yuv image, the uncompressed (decoded) gain map, and extracted JPEG/R metadata as 322 * input, and calculate the 10-bit recovered image. The recovered output image is the same 323 * color gamut as the SDR image, with HLG transfer function, and is in RGBA1010102 data format. 324 * The SDR image is assumed to use the sRGB transfer function. The SDR image is also assumed to 325 * be a decoded JPEG for the purpose of YUV interpration. 326 * 327 * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format 328 * @param gainmap_image_ptr pointer to uncompressed gain map image struct. 329 * @param metadata JPEG/R metadata extracted from XMP. 330 * @param output_format flag for setting output color format. if set to 331 * {@code JPEGR_OUTPUT_SDR}, decoder will only decode the primary image 332 * which is SDR. Default value is JPEGR_OUTPUT_HDR_LINEAR. 333 * @param max_display_boost the maximum available boost supported by a display 334 * @param dest reconstructed HDR image 335 * @return NO_ERROR if calculation succeeds, error code if error occurs. 336 */ 337 status_t applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, jr_uncompressed_ptr gainmap_image_ptr, 338 ultrahdr_metadata_ptr metadata, ultrahdr_output_format output_format, 339 float max_display_boost, jr_uncompressed_ptr dest); 340 341 private: 342 /* 343 * This method is called in the encoding pipeline. It will encode the gain map. 344 * 345 * @param gainmap_image_ptr pointer to uncompressed gain map image struct 346 * @param jpeg_enc_obj_ptr helper resource to compress gain map 347 * @return NO_ERROR if encoding succeeds, error code if error occurs. 348 */ 349 status_t compressGainMap(jr_uncompressed_ptr gainmap_image_ptr, 350 JpegEncoderHelper* jpeg_enc_obj_ptr); 351 352 /* 353 * This method is called to separate primary image and gain map image from JPEGR 354 * 355 * @param jpegr_image_ptr pointer to compressed JPEGR image. 356 * @param primary_jpg_image_ptr destination of primary image 357 * @param gainmap_jpg_image_ptr destination of compressed gain map image 358 * @return NO_ERROR if calculation succeeds, error code if error occurs. 359 */ 360 status_t extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, 361 jr_compressed_ptr primary_jpg_image_ptr, 362 jr_compressed_ptr gainmap_jpg_image_ptr); 363 364 /* 365 * Gets Info from JPEG image without decoding it. 366 * 367 * The output is filled jpeg_info structure 368 * @param jpegr_image_ptr compressed JPEG image 369 * @param jpeg_image_info_ptr pointer to jpeg info struct. Members of jpeg_info_struct 370 * are owned by the caller 371 * @param img_width (optional) pointer to store width of jpeg image 372 * @param img_height (optional) pointer to store height of jpeg image 373 * @return NO_ERROR if JPEGR parsing succeeds, error code otherwise 374 */ 375 status_t parseJpegInfo(jr_compressed_ptr jpeg_image_ptr, j_info_ptr jpeg_image_info_ptr, 376 size_t* img_width = nullptr, size_t* img_height = nullptr); 377 378 /* 379 * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image, 380 * the compressed gain map and optionally the exif package as inputs, and generate the XMP 381 * metadata, and finally append everything in the order of: 382 * SOI, APP2(EXIF) (if EXIF is from outside), APP2(XMP), primary image, gain map 383 * 384 * Note that in the final JPEG/R output, EXIF package will appear if ONLY ONE of the following 385 * conditions is fulfilled: 386 * (1) EXIF package is available from outside input. I.e. pExif != nullptr. 387 * (2) Input JPEG has EXIF. 388 * If both conditions are fulfilled, this method will return ERROR_JPEGR_INVALID_INPUT_TYPE 389 * 390 * @param primary_jpg_image_ptr destination of primary image 391 * @param gainmap_jpg_image_ptr destination of compressed gain map image 392 * @param (nullable) pExif EXIF package 393 * @param (nullable) pIcc ICC package 394 * @param icc_size length in bytes of ICC package 395 * @param metadata JPEG/R metadata to encode in XMP of the jpeg 396 * @param dest compressed JPEGR image 397 * @return NO_ERROR if calculation succeeds, error code if error occurs. 398 */ 399 status_t appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, 400 jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr pExif, void* pIcc, 401 size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest); 402 403 /* 404 * This method will tone map a HDR image to an SDR image. 405 * 406 * @param src pointer to uncompressed HDR image struct. HDR image is expected to be 407 * in p010 color format 408 * @param dest pointer to store tonemapped SDR image 409 * @param hdr_tf transfer function of the HDR image 410 * @return NO_ERROR if calculation succeeds, error code if error occurs. 411 */ 412 status_t toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest, 413 ultrahdr_transfer_function hdr_tf); 414 415 /* 416 * This method will convert a YUV420 image from one YUV encoding to another in-place (eg. 417 * Bt.709 to Bt.601 YUV encoding). 418 * 419 * src_encoding and dest_encoding indicate the encoding via the YUV conversion defined for that 420 * gamut. P3 indicates Rec.601, since this is how DataSpace encodes Display-P3 YUV data. 421 * 422 * @param image the YUV420 image to convert 423 * @param src_encoding input YUV encoding 424 * @param dest_encoding output YUV encoding 425 * @return NO_ERROR if calculation succeeds, error code if error occurs. 426 */ 427 status_t convertYuv(jr_uncompressed_ptr image, ultrahdr_color_gamut src_encoding, 428 ultrahdr_color_gamut dest_encoding); 429 430 /* 431 * This method will check the validity of the input arguments. 432 * 433 * @param p010_image_ptr uncompressed HDR image in P010 color format 434 * @param yuv420_image_ptr pointer to uncompressed SDR image struct. HDR image is expected to 435 * be in 420p color format 436 * @param hdr_tf transfer function of the HDR image 437 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 438 * represents the maximum available size of the desitination buffer, and it must be 439 * set before calling this method. If the encoded JPEGR size exceeds 440 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 441 * @return NO_ERROR if the input args are valid, error code is not valid. 442 */ 443 status_t areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, 444 jr_uncompressed_ptr yuv420_image_ptr, 445 ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest_ptr); 446 447 /* 448 * This method will check the validity of the input arguments. 449 * 450 * @param p010_image_ptr uncompressed HDR image in P010 color format 451 * @param yuv420_image_ptr pointer to uncompressed SDR image struct. HDR image is expected to 452 * be in 420p color format 453 * @param hdr_tf transfer function of the HDR image 454 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 455 * represents the maximum available size of the destination buffer, and it must be 456 * set before calling this method. If the encoded JPEGR size exceeds 457 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 458 * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is 459 * the highest quality 460 * @return NO_ERROR if the input args are valid, error code is not valid. 461 */ 462 status_t areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, 463 jr_uncompressed_ptr yuv420_image_ptr, 464 ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest, 465 int quality); 466 }; 467 468 struct GlobalTonemapOutputs { 469 std::array<float, 3> rgb_out; 470 float y_hdr; 471 float y_sdr; 472 }; 473 474 // Applies a global tone mapping, based on Chrome's HLG/PQ rendering implemented 475 // at 476 // https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/color_transform.cc;l=1198-1232;drc=ac505aff1d29ec3bfcf317cb77d5e196a3664e92 477 // `rgb_in` is expected to be in the normalized range of [0.0, 1.0] and 478 // `rgb_out` is returned in this same range. `headroom` describes the ratio 479 // between the HDR and SDR peak luminances and must be > 1. The `y_sdr` output 480 // is in the range [0.0, 1.0] while `y_hdr` is in the range [0.0, headroom]. 481 GlobalTonemapOutputs hlgGlobalTonemap(const std::array<float, 3>& rgb_in, float headroom); 482 483 } // namespace ultrahdr 484 485 #endif // ULTRAHDR_JPEGR_H 486