• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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