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 ANDROID_ULTRAHDR_JPEGR_H 18 #define ANDROID_ULTRAHDR_JPEGR_H 19 20 #include "jpegencoderhelper.h" 21 #include "jpegrerrorcode.h" 22 #include "ultrahdr.h" 23 24 #ifndef FLT_MAX 25 #define FLT_MAX 0x1.fffffep127f 26 #endif 27 28 namespace android::ultrahdr { 29 30 struct jpegr_info_struct { 31 size_t width; 32 size_t height; 33 std::vector<uint8_t>* iccData; 34 std::vector<uint8_t>* exifData; 35 }; 36 37 /* 38 * Holds information for uncompressed image or gain map. 39 */ 40 struct jpegr_uncompressed_struct { 41 // Pointer to the data location. 42 void* data; 43 // Width of the gain map or the luma plane of the image in pixels. 44 int width; 45 // Height of the gain map or the luma plane of the image in pixels. 46 int height; 47 // Color gamut. 48 ultrahdr_color_gamut colorGamut; 49 50 // Values below are optional 51 // Pointer to chroma data, if it's NULL, chroma plane is considered to be immediately 52 // following after the luma plane. 53 // Note: currently this feature is only supported for P010 image (HDR input). 54 void* chroma_data = nullptr; 55 // Strides of Y plane in number of pixels, using 0 to present uninitialized, must be 56 // larger than or equal to luma width. 57 // Note: currently this feature is only supported for P010 image (HDR input). 58 int luma_stride = 0; 59 // Strides of UV plane in number of pixels, using 0 to present uninitialized, must be 60 // larger than or equal to chroma width. 61 // Note: currently this feature is only supported for P010 image (HDR input). 62 int chroma_stride = 0; 63 }; 64 65 /* 66 * Holds information for compressed image or gain map. 67 */ 68 struct jpegr_compressed_struct { 69 // Pointer to the data location. 70 void* data; 71 // Used data length in bytes. 72 int length; 73 // Maximum available data length in bytes. 74 int maxLength; 75 // Color gamut. 76 ultrahdr_color_gamut colorGamut; 77 }; 78 79 /* 80 * Holds information for EXIF metadata. 81 */ 82 struct jpegr_exif_struct { 83 // Pointer to the data location. 84 void* data; 85 // Data length; 86 int length; 87 }; 88 89 typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr; 90 typedef struct jpegr_compressed_struct* jr_compressed_ptr; 91 typedef struct jpegr_exif_struct* jr_exif_ptr; 92 typedef struct jpegr_info_struct* jr_info_ptr; 93 94 class JpegR { 95 public: 96 /* 97 * Experimental only 98 * 99 * Encode API-0 100 * Compress JPEGR image from 10-bit HDR YUV. 101 * 102 * Tonemap the HDR input to a SDR image, generate gain map from the HDR and SDR images, 103 * compress SDR YUV to 8-bit JPEG and append the gain map to the end of the compressed 104 * JPEG. 105 * @param uncompressed_p010_image uncompressed HDR image in P010 color format 106 * @param hdr_tf transfer function of the HDR image 107 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 108 * represents the maximum available size of the desitination buffer, and it must be 109 * set before calling this method. If the encoded JPEGR size exceeds 110 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 111 * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is 112 * the highest quality 113 * @param exif pointer to the exif metadata. 114 * @return NO_ERROR if encoding succeeds, error code if error occurs. 115 */ 116 status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, 117 ultrahdr_transfer_function hdr_tf, 118 jr_compressed_ptr dest, 119 int quality, 120 jr_exif_ptr exif); 121 122 /* 123 * Encode API-1 124 * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV. 125 * 126 * Generate gain map from the HDR and SDR inputs, compress SDR YUV to 8-bit JPEG and append 127 * the gain map to the end of the compressed JPEG. HDR and SDR inputs must be the same 128 * resolution. SDR input is assumed to use the sRGB transfer function. 129 * @param uncompressed_p010_image uncompressed HDR image in P010 color format 130 * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format 131 * @param hdr_tf transfer function of the HDR image 132 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 133 * represents the maximum available size of the desitination buffer, and it must be 134 * set before calling this method. If the encoded JPEGR size exceeds 135 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 136 * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is 137 * the highest quality 138 * @param exif pointer to the exif metadata. 139 * @return NO_ERROR if encoding succeeds, error code if error occurs. 140 */ 141 status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, 142 jr_uncompressed_ptr uncompressed_yuv_420_image, 143 ultrahdr_transfer_function hdr_tf, 144 jr_compressed_ptr dest, 145 int quality, 146 jr_exif_ptr exif); 147 148 /* 149 * Encode API-2 150 * Compress JPEGR image from 10-bit HDR YUV, 8-bit SDR YUV and compressed 8-bit JPEG. 151 * 152 * This method requires HAL Hardware JPEG encoder. 153 * 154 * Generate gain map from the HDR and SDR inputs, append the gain map to the end of the 155 * compressed JPEG. Adds an ICC profile if one isn't present in the input JPEG image. HDR and 156 * SDR inputs must be the same resolution and color space. SDR image is assumed to use the sRGB 157 * transfer function. 158 * @param uncompressed_p010_image uncompressed HDR image in P010 color format 159 * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format 160 * Note: the SDR image must be the decoded version of the JPEG 161 * input 162 * @param compressed_jpeg_image compressed 8-bit JPEG image 163 * @param hdr_tf transfer function of the HDR image 164 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 165 * represents the maximum available size of the desitination buffer, and it must be 166 * set before calling this method. If the encoded JPEGR size exceeds 167 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 168 * @return NO_ERROR if encoding succeeds, error code if error occurs. 169 */ 170 status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, 171 jr_uncompressed_ptr uncompressed_yuv_420_image, 172 jr_compressed_ptr compressed_jpeg_image, 173 ultrahdr_transfer_function hdr_tf, 174 jr_compressed_ptr dest); 175 176 /* 177 * Encode API-3 178 * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV. 179 * 180 * This method requires HAL Hardware JPEG encoder. 181 * 182 * Decode the compressed 8-bit JPEG image to YUV SDR, generate gain map from the HDR input 183 * and the decoded SDR result, append the gain map to the end of the compressed JPEG. Adds an 184 * ICC profile if one isn't present in the input JPEG image. HDR and SDR inputs must be the same 185 * resolution. JPEG image is assumed to use the sRGB transfer function. 186 * @param uncompressed_p010_image uncompressed HDR image in P010 color format 187 * @param compressed_jpeg_image compressed 8-bit JPEG image 188 * @param hdr_tf transfer function of the HDR image 189 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 190 * represents the maximum available size of the desitination buffer, and it must be 191 * set before calling this method. If the encoded JPEGR size exceeds 192 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 193 * @return NO_ERROR if encoding succeeds, error code if error occurs. 194 */ 195 status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, 196 jr_compressed_ptr compressed_jpeg_image, 197 ultrahdr_transfer_function hdr_tf, 198 jr_compressed_ptr dest); 199 200 /* 201 * Encode API-4 202 * Assemble JPEGR image from SDR JPEG and gainmap JPEG. 203 * 204 * Assemble the primary JPEG image, the gain map and the metadata to JPEG/R format. Adds an ICC 205 * profile if one isn't present in the input JPEG image. 206 * @param compressed_jpeg_image compressed 8-bit JPEG image 207 * @param compressed_gainmap compressed 8-bit JPEG single channel image 208 * @param metadata metadata to be written in XMP of the primary jpeg 209 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 210 * represents the maximum available size of the desitination buffer, and it must be 211 * set before calling this method. If the encoded JPEGR size exceeds 212 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 213 * @return NO_ERROR if encoding succeeds, error code if error occurs. 214 */ 215 status_t encodeJPEGR(jr_compressed_ptr compressed_jpeg_image, 216 jr_compressed_ptr compressed_gainmap, 217 ultrahdr_metadata_ptr metadata, 218 jr_compressed_ptr dest); 219 220 /* 221 * Decode API 222 * Decompress JPEGR image. 223 * 224 * This method assumes that the JPEGR image contains an ICC profile with primaries that match 225 * those of a color gamut that this library is aware of; Bt.709, Display-P3, or Bt.2100. It also 226 * assumes the base image uses the sRGB transfer function. 227 * 228 * This method only supports single gain map metadata values for fields that allow multi-channel 229 * metadata values. 230 * 231 * @param compressed_jpegr_image compressed JPEGR image. 232 * @param dest destination of the uncompressed JPEGR image. 233 * @param max_display_boost (optional) the maximum available boost supported by a display, 234 * the value must be greater than or equal to 1.0. 235 * @param exif destination of the decoded EXIF metadata. The default value is NULL where the 236 decoder will do nothing about it. If configured not NULL the decoder will write 237 EXIF data into this structure. The format is defined in {@code jpegr_exif_struct} 238 * @param output_format flag for setting output color format. Its value configures the output 239 color format. The default value is {@code JPEGR_OUTPUT_HDR_LINEAR}. 240 ---------------------------------------------------------------------- 241 | output_format | decoded color format to be written | 242 ---------------------------------------------------------------------- 243 | JPEGR_OUTPUT_SDR | RGBA_8888 | 244 ---------------------------------------------------------------------- 245 | JPEGR_OUTPUT_HDR_LINEAR | (default)RGBA_F16 linear | 246 ---------------------------------------------------------------------- 247 | JPEGR_OUTPUT_HDR_PQ | RGBA_1010102 PQ | 248 ---------------------------------------------------------------------- 249 | JPEGR_OUTPUT_HDR_HLG | RGBA_1010102 HLG | 250 ---------------------------------------------------------------------- 251 * @param gain_map destination of the decoded gain map. The default value is NULL where 252 the decoder will do nothing about it. If configured not NULL the decoder 253 will write the decoded gain_map data into this structure. The format 254 is defined in {@code jpegr_uncompressed_struct}. 255 * @param metadata destination of the decoded metadata. The default value is NULL where the 256 decoder will do nothing about it. If configured not NULL the decoder will 257 write metadata into this structure. the format of metadata is defined in 258 {@code ultrahdr_metadata_struct}. 259 * @return NO_ERROR if decoding succeeds, error code if error occurs. 260 */ 261 status_t decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, 262 jr_uncompressed_ptr dest, 263 float max_display_boost = FLT_MAX, 264 jr_exif_ptr exif = nullptr, 265 ultrahdr_output_format output_format = ULTRAHDR_OUTPUT_HDR_LINEAR, 266 jr_uncompressed_ptr gain_map = nullptr, 267 ultrahdr_metadata_ptr metadata = nullptr); 268 269 /* 270 * Gets Info from JPEGR file without decoding it. 271 * 272 * This method only supports single gain map metadata values for fields that allow multi-channel 273 * metadata values. 274 * 275 * The output is filled jpegr_info structure 276 * @param compressed_jpegr_image compressed JPEGR image 277 * @param jpegr_info pointer to output JPEGR info. Members of jpegr_info 278 * are owned by the caller 279 * @return NO_ERROR if JPEGR parsing succeeds, error code otherwise 280 */ 281 status_t getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, 282 jr_info_ptr jpegr_info); 283 protected: 284 /* 285 * This method is called in the encoding pipeline. It will take the uncompressed 8-bit and 286 * 10-bit yuv images as input, and calculate the uncompressed gain map. The input images 287 * must be the same resolution. The SDR input is assumed to use the sRGB transfer function. 288 * 289 * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format 290 * @param uncompressed_p010_image uncompressed HDR image in P010 color format 291 * @param hdr_tf transfer function of the HDR image 292 * @param dest gain map; caller responsible for memory of data 293 * @param metadata max_content_boost is filled in 294 * @param sdr_is_601 if true, then use BT.601 decoding of YUV regardless of SDR image gamut 295 * @return NO_ERROR if calculation succeeds, error code if error occurs. 296 */ 297 status_t generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, 298 jr_uncompressed_ptr uncompressed_p010_image, 299 ultrahdr_transfer_function hdr_tf, 300 ultrahdr_metadata_ptr metadata, 301 jr_uncompressed_ptr dest, 302 bool sdr_is_601 = false); 303 304 /* 305 * This method is called in the decoding pipeline. It will take the uncompressed (decoded) 306 * 8-bit yuv image, the uncompressed (decoded) gain map, and extracted JPEG/R metadata as 307 * input, and calculate the 10-bit recovered image. The recovered output image is the same 308 * color gamut as the SDR image, with HLG transfer function, and is in RGBA1010102 data format. 309 * The SDR image is assumed to use the sRGB transfer function. The SDR image is also assumed to 310 * be a decoded JPEG for the purpose of YUV interpration. 311 * 312 * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format 313 * @param uncompressed_gain_map uncompressed gain map 314 * @param metadata JPEG/R metadata extracted from XMP. 315 * @param output_format flag for setting output color format. if set to 316 * {@code JPEGR_OUTPUT_SDR}, decoder will only decode the primary image 317 * which is SDR. Default value is JPEGR_OUTPUT_HDR_LINEAR. 318 * @param max_display_boost the maximum available boost supported by a display 319 * @param dest reconstructed HDR image 320 * @return NO_ERROR if calculation succeeds, error code if error occurs. 321 */ 322 status_t applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, 323 jr_uncompressed_ptr uncompressed_gain_map, 324 ultrahdr_metadata_ptr metadata, 325 ultrahdr_output_format output_format, 326 float max_display_boost, 327 jr_uncompressed_ptr dest); 328 329 private: 330 /* 331 * This method is called in the encoding pipeline. It will encode the gain map. 332 * 333 * @param uncompressed_gain_map uncompressed gain map 334 * @param resource to compress gain map 335 * @return NO_ERROR if encoding succeeds, error code if error occurs. 336 */ 337 status_t compressGainMap(jr_uncompressed_ptr uncompressed_gain_map, 338 JpegEncoderHelper* jpeg_encoder); 339 340 /* 341 * This methoud is called to separate primary image and gain map image from JPEGR 342 * 343 * @param compressed_jpegr_image compressed JPEGR image 344 * @param primary_image destination of primary image 345 * @param gain_map destination of compressed gain map 346 * @return NO_ERROR if calculation succeeds, error code if error occurs. 347 */ 348 status_t extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr_image, 349 jr_compressed_ptr primary_image, 350 jr_compressed_ptr gain_map); 351 352 /* 353 * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image, 354 * the compressed gain map and optionally the exif package as inputs, and generate the XMP 355 * metadata, and finally append everything in the order of: 356 * SOI, APP2(EXIF) (if EXIF is from outside), APP2(XMP), primary image, gain map 357 * Note that EXIF package is only available for encoding API-0 and API-1. For encoding API-2 and 358 * API-3 this parameter is null, but the primary image in JPEG/R may still have EXIF as long as 359 * the input JPEG has EXIF. 360 * 361 * @param compressed_jpeg_image compressed 8-bit JPEG image 362 * @param compress_gain_map compressed recover map 363 * @param (nullable) exif EXIF package 364 * @param (nullable) icc ICC package 365 * @param icc_size length in bytes of ICC package 366 * @param metadata JPEG/R metadata to encode in XMP of the jpeg 367 * @param dest compressed JPEGR image 368 * @return NO_ERROR if calculation succeeds, error code if error occurs. 369 */ 370 status_t appendGainMap(jr_compressed_ptr compressed_jpeg_image, 371 jr_compressed_ptr compressed_gain_map, 372 jr_exif_ptr exif, 373 void* icc, size_t icc_size, 374 ultrahdr_metadata_ptr metadata, 375 jr_compressed_ptr dest); 376 377 /* 378 * This method will tone map a HDR image to an SDR image. 379 * 380 * @param src (input) uncompressed P010 image 381 * @param dest (output) tone mapping result as a YUV_420 image 382 * @return NO_ERROR if calculation succeeds, error code if error occurs. 383 */ 384 status_t toneMap(jr_uncompressed_ptr src, 385 jr_uncompressed_ptr dest); 386 387 /* 388 * This method will convert a YUV420 image from one YUV encoding to another in-place (eg. 389 * Bt.709 to Bt.601 YUV encoding). 390 * 391 * src_encoding and dest_encoding indicate the encoding via the YUV conversion defined for that 392 * gamut. P3 indicates Rec.601, since this is how DataSpace encodes Display-P3 YUV data. 393 * 394 * @param image the YUV420 image to convert 395 * @param src_encoding input YUV encoding 396 * @param dest_encoding output YUV encoding 397 * @return NO_ERROR if calculation succeeds, error code if error occurs. 398 */ 399 status_t convertYuv(jr_uncompressed_ptr image, 400 ultrahdr_color_gamut src_encoding, 401 ultrahdr_color_gamut dest_encoding); 402 403 /* 404 * This method will check the validity of the input arguments. 405 * 406 * @param uncompressed_p010_image uncompressed HDR image in P010 color format 407 * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format 408 * @param hdr_tf transfer function of the HDR image 409 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 410 * represents the maximum available size of the desitination buffer, and it must be 411 * set before calling this method. If the encoded JPEGR size exceeds 412 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 413 * @return NO_ERROR if the input args are valid, error code is not valid. 414 */ 415 status_t areInputArgumentsValid(jr_uncompressed_ptr uncompressed_p010_image, 416 jr_uncompressed_ptr uncompressed_yuv_420_image, 417 ultrahdr_transfer_function hdr_tf, 418 jr_compressed_ptr dest); 419 420 /* 421 * This method will check the validity of the input arguments. 422 * 423 * @param uncompressed_p010_image uncompressed HDR image in P010 color format 424 * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format 425 * @param hdr_tf transfer function of the HDR image 426 * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} 427 * represents the maximum available size of the desitination buffer, and it must be 428 * set before calling this method. If the encoded JPEGR size exceeds 429 * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. 430 * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is 431 * the highest quality 432 * @return NO_ERROR if the input args are valid, error code is not valid. 433 */ 434 status_t areInputArgumentsValid(jr_uncompressed_ptr uncompressed_p010_image, 435 jr_uncompressed_ptr uncompressed_yuv_420_image, 436 ultrahdr_transfer_function hdr_tf, 437 jr_compressed_ptr dest, 438 int quality); 439 }; 440 441 } // namespace android::ultrahdr 442 443 #endif // ANDROID_ULTRAHDR_JPEGR_H 444