/src/libultrahdr/lib/include/ultrahdr/ultrahdrcommon.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2023 The Android Open Source Project |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
5 | | * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
6 | | * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your |
7 | | * option. This file may not be copied, modified, or distributed |
8 | | * except according to those terms. |
9 | | */ |
10 | | |
11 | | #ifndef ULTRAHDR_ULTRAHDRCOMMON_H |
12 | | #define ULTRAHDR_ULTRAHDRCOMMON_H |
13 | | |
14 | | //#define LOG_NDEBUG 0 |
15 | | |
16 | | #ifdef UHDR_ENABLE_GLES |
17 | | #include <EGL/egl.h> |
18 | | #include <GLES3/gl3.h> |
19 | | #endif |
20 | | |
21 | | #include <array> |
22 | | #include <cfloat> |
23 | | #include <cstdint> |
24 | | #include <deque> |
25 | | #include <map> |
26 | | #include <memory> |
27 | | #include <string> |
28 | | #include <vector> |
29 | | |
30 | | #include "ultrahdr_api.h" |
31 | | |
32 | | // =============================================================================================== |
33 | | // Function Macros |
34 | | // =============================================================================================== |
35 | | |
36 | | #ifdef __ANDROID__ |
37 | | |
38 | | #ifdef LOG_NDEBUG |
39 | | #include "android/log.h" |
40 | | |
41 | | #ifndef LOG_TAG |
42 | | #define LOG_TAG "UHDR" |
43 | | #endif |
44 | | |
45 | | #ifndef ALOGD |
46 | | #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) |
47 | | #endif |
48 | | |
49 | | #ifndef ALOGE |
50 | | #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) |
51 | | #endif |
52 | | |
53 | | #ifndef ALOGI |
54 | | #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) |
55 | | #endif |
56 | | |
57 | | #ifndef ALOGV |
58 | | #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) |
59 | | #endif |
60 | | |
61 | | #ifndef ALOGW |
62 | | #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) |
63 | | #endif |
64 | | |
65 | | #else |
66 | | |
67 | | #define ALOGD(...) ((void)0) |
68 | | #define ALOGE(...) ((void)0) |
69 | | #define ALOGI(...) ((void)0) |
70 | | #define ALOGV(...) ((void)0) |
71 | | #define ALOGW(...) ((void)0) |
72 | | |
73 | | #endif |
74 | | |
75 | | #else |
76 | | |
77 | | #ifdef LOG_NDEBUG |
78 | | #include <cstdio> |
79 | | |
80 | | #define ALOGD(...) \ |
81 | | do { \ |
82 | | fprintf(stderr, __VA_ARGS__); \ |
83 | | fprintf(stderr, "\n"); \ |
84 | | } while (0) |
85 | | |
86 | | #define ALOGE(...) \ |
87 | | do { \ |
88 | | fprintf(stderr, __VA_ARGS__); \ |
89 | | fprintf(stderr, "\n"); \ |
90 | | } while (0) |
91 | | |
92 | | #define ALOGI(...) \ |
93 | | do { \ |
94 | | fprintf(stdout, __VA_ARGS__); \ |
95 | | fprintf(stdout, "\n"); \ |
96 | | } while (0) |
97 | | |
98 | | #define ALOGV(...) \ |
99 | | do { \ |
100 | | fprintf(stdout, __VA_ARGS__); \ |
101 | | fprintf(stdout, "\n"); \ |
102 | | } while (0) |
103 | | |
104 | | #define ALOGW(...) \ |
105 | | do { \ |
106 | | fprintf(stderr, __VA_ARGS__); \ |
107 | | fprintf(stderr, "\n"); \ |
108 | | } while (0) |
109 | | |
110 | | #else |
111 | | |
112 | 924 | #define ALOGD(...) ((void)0) |
113 | 37.5k | #define ALOGE(...) ((void)0) |
114 | | #define ALOGI(...) ((void)0) |
115 | 84.5k | #define ALOGV(...) ((void)0) |
116 | 811 | #define ALOGW(...) ((void)0) |
117 | | |
118 | | #endif |
119 | | |
120 | | #endif |
121 | | |
122 | 43.7k | #define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m)) |
123 | | |
124 | | #define UHDR_ERR_CHECK(x) \ |
125 | 319k | { \ |
126 | 319k | uhdr_error_info_t status = (x); \ |
127 | 319k | if (status.error_code != UHDR_CODEC_OK) { \ |
128 | 18.6k | return status; \ |
129 | 18.6k | } \ |
130 | 319k | } |
131 | | |
132 | | #if defined(_MSC_VER) |
133 | | #define FORCE_INLINE __forceinline |
134 | | #define INLINE __inline |
135 | | #else |
136 | | #define FORCE_INLINE __inline__ __attribute__((always_inline)) |
137 | | #define INLINE inline |
138 | | #endif |
139 | | |
140 | | // '__has_attribute' macro was introduced by clang. later picked up by gcc. |
141 | | // If not supported by the current toolchain, define it to zero. |
142 | | #ifndef __has_attribute |
143 | | #define __has_attribute(x) 0 |
144 | | #endif |
145 | | |
146 | | // Disables undefined behavior analysis for a function. |
147 | | // GCC 4.9+ uses __attribute__((no_sanitize_undefined)) |
148 | | // clang uses __attribute__((no_sanitize("undefined"))) |
149 | | #if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409) |
150 | | #define UHDR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined)) |
151 | | #elif __has_attribute(no_sanitize) |
152 | | #define UHDR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined"))) |
153 | | #else |
154 | | #define UHDR_NO_SANITIZE_UNDEFINED |
155 | | #endif |
156 | | |
157 | | static const uhdr_error_info_t g_no_error = {UHDR_CODEC_OK, 0, ""}; |
158 | | |
159 | | namespace ultrahdr { |
160 | | |
161 | | // =============================================================================================== |
162 | | // Globals |
163 | | // =============================================================================================== |
164 | | extern const int kMinWidth, kMinHeight; |
165 | | extern const int kMaxWidth, kMaxHeight; |
166 | | |
167 | | // =============================================================================================== |
168 | | // Structure Definitions |
169 | | // =============================================================================================== |
170 | | |
171 | | /**\brief uhdr memory block */ |
172 | | typedef struct uhdr_memory_block { |
173 | | uhdr_memory_block(size_t capacity); |
174 | | |
175 | | std::unique_ptr<uint8_t[]> m_buffer; /**< data */ |
176 | | size_t m_capacity; /**< capacity */ |
177 | | } uhdr_memory_block_t; /**< alias for struct uhdr_memory_block */ |
178 | | |
179 | | /**\brief extended raw image descriptor */ |
180 | | typedef struct uhdr_raw_image_ext : uhdr_raw_image_t { |
181 | | uhdr_raw_image_ext(uhdr_img_fmt_t fmt, uhdr_color_gamut_t cg, uhdr_color_transfer_t ct, |
182 | | uhdr_color_range_t range, unsigned w, unsigned h, unsigned align_stride_to); |
183 | | |
184 | | private: |
185 | | std::unique_ptr<ultrahdr::uhdr_memory_block> m_block; |
186 | | } uhdr_raw_image_ext_t; /**< alias for struct uhdr_raw_image_ext */ |
187 | | |
188 | | /**\brief extended compressed image descriptor */ |
189 | | typedef struct uhdr_compressed_image_ext : uhdr_compressed_image_t { |
190 | | uhdr_compressed_image_ext(uhdr_color_gamut_t cg, uhdr_color_transfer_t ct, |
191 | | uhdr_color_range_t range, size_t sz); |
192 | | |
193 | | private: |
194 | | std::unique_ptr<ultrahdr::uhdr_memory_block> m_block; |
195 | | } uhdr_compressed_image_ext_t; /**< alias for struct uhdr_compressed_image_ext */ |
196 | | |
197 | | /*!\brief forward declaration for image effect descriptor */ |
198 | | typedef struct uhdr_effect_desc uhdr_effect_desc_t; |
199 | | |
200 | | /**\brief Gain map metadata. */ |
201 | | typedef struct uhdr_gainmap_metadata_ext : uhdr_gainmap_metadata { |
202 | 18.2k | uhdr_gainmap_metadata_ext() {} |
203 | | |
204 | 439 | uhdr_gainmap_metadata_ext(std::string ver) : version(ver) {} |
205 | | |
206 | | uhdr_gainmap_metadata_ext(uhdr_gainmap_metadata& metadata, std::string ver) |
207 | 0 | : uhdr_gainmap_metadata_ext(ver) { |
208 | 0 | std::copy(metadata.max_content_boost, metadata.max_content_boost + 3, max_content_boost); |
209 | 0 | std::copy(metadata.min_content_boost, metadata.min_content_boost + 3, min_content_boost); |
210 | 0 | std::copy(metadata.gamma, metadata.gamma + 3, gamma); |
211 | 0 | std::copy(metadata.offset_sdr, metadata.offset_sdr + 3, offset_sdr); |
212 | 0 | std::copy(metadata.offset_hdr, metadata.offset_hdr + 3, offset_hdr); |
213 | 0 | hdr_capacity_min = metadata.hdr_capacity_min; |
214 | 0 | hdr_capacity_max = metadata.hdr_capacity_max; |
215 | 0 | use_base_cg = metadata.use_base_cg; |
216 | 0 | } |
217 | | |
218 | 1.11k | bool are_all_channels_identical() const { |
219 | 1.11k | return max_content_boost[0] == max_content_boost[1] && |
220 | 1.11k | max_content_boost[0] == max_content_boost[2] && |
221 | 1.11k | min_content_boost[0] == min_content_boost[1] && |
222 | 1.11k | min_content_boost[0] == min_content_boost[2] && gamma[0] == gamma[1] && |
223 | 1.11k | gamma[0] == gamma[2] && offset_sdr[0] == offset_sdr[1] && |
224 | 1.10k | offset_sdr[0] == offset_sdr[2] && offset_hdr[0] == offset_hdr[1] && |
225 | 1.10k | offset_hdr[0] == offset_hdr[2]; |
226 | 1.11k | } |
227 | | |
228 | | std::string version; /**< Ultra HDR format version */ |
229 | | } uhdr_gainmap_metadata_ext_t; /**< alias for struct uhdr_gainmap_metadata */ |
230 | | |
231 | | #ifdef UHDR_ENABLE_GLES |
232 | | |
233 | | typedef enum uhdr_effect_shader { |
234 | | UHDR_MIR_HORZ, |
235 | | UHDR_MIR_VERT, |
236 | | UHDR_ROT_90, |
237 | | UHDR_ROT_180, |
238 | | UHDR_ROT_270, |
239 | | UHDR_CROP, |
240 | | UHDR_RESIZE, |
241 | | } uhdr_effect_shader_t; |
242 | | |
243 | | /**\brief OpenGL context */ |
244 | | typedef struct uhdr_opengl_ctxt { |
245 | | // EGL Context |
246 | | EGLDisplay mEGLDisplay; /**< EGL display connection */ |
247 | | EGLContext mEGLContext; /**< EGL rendering context */ |
248 | | EGLSurface mEGLSurface; /**< EGL surface for rendering */ |
249 | | EGLConfig mEGLConfig; /**< EGL frame buffer configuration */ |
250 | | |
251 | | // GLES Context |
252 | | GLuint mQuadVAO, mQuadVBO, mQuadEBO; /**< GL objects */ |
253 | | GLuint mShaderProgram[UHDR_RESIZE + 1]; /**< Shader programs */ |
254 | | GLuint mDecodedImgTexture, mGainmapImgTexture; /**< GL Textures */ |
255 | | uhdr_error_info_t mErrorStatus; /**< Context status */ |
256 | | |
257 | | uhdr_opengl_ctxt(); |
258 | | ~uhdr_opengl_ctxt(); |
259 | | |
260 | | /*!\brief Initializes the OpenGL context. Mainly it prepares EGL. We want a GLES3.0 context and a |
261 | | * surface that supports pbuffer. Once this is done and surface is made current, the gl state is |
262 | | * initialized |
263 | | * |
264 | | * \return none |
265 | | */ |
266 | | void init_opengl_ctxt(); |
267 | | |
268 | | /*!\brief This method is used to compile a shader |
269 | | * |
270 | | * \param[in] type shader type |
271 | | * \param[in] source shader source code |
272 | | * |
273 | | * \return GLuint #shader_id if operation succeeds, 0 otherwise. |
274 | | */ |
275 | | GLuint compile_shader(GLenum type, const char* source); |
276 | | |
277 | | /*!\brief This method is used to create a shader program |
278 | | * |
279 | | * \param[in] vertex_source vertex shader source code |
280 | | * \param[in] fragment_source fragment shader source code |
281 | | * |
282 | | * \return GLuint #shader_program_id if operation succeeds, 0 otherwise. |
283 | | */ |
284 | | GLuint create_shader_program(const char* vertex_source, const char* fragment_source); |
285 | | |
286 | | /*!\brief This method is used to create a 2D texture for a raw image |
287 | | * NOTE: For multichannel planar image, this method assumes the channel data to be contiguous |
288 | | * NOTE: For any channel, this method assumes width and stride to be identical |
289 | | * |
290 | | * \param[in] fmt image format |
291 | | * \param[in] w image width |
292 | | * \param[in] h image height |
293 | | * \param[in] data image data |
294 | | * |
295 | | * \return GLuint #texture_id if operation succeeds, 0 otherwise. |
296 | | */ |
297 | | GLuint create_texture(uhdr_img_fmt_t fmt, int w, int h, void* data); |
298 | | |
299 | | /*!\breif This method is used to read data from texture into a raw image |
300 | | * NOTE: For any channel, this method assumes width and stride to be identical |
301 | | * |
302 | | * \param[in] texture texture_id |
303 | | * \param[in] fmt image format |
304 | | * \param[in] w image width |
305 | | * \param[in] h image height |
306 | | * \param[in] data image data |
307 | | * |
308 | | * \return none |
309 | | */ |
310 | | void read_texture(GLuint* texture, uhdr_img_fmt_t fmt, int w, int h, void* data); |
311 | | |
312 | | /*!\brief This method is used to set up quad buffers and arrays |
313 | | * |
314 | | * \return none |
315 | | */ |
316 | | void setup_quad(); |
317 | | |
318 | | /*!\brief This method is used to set up frame buffer for a 2D texture |
319 | | * |
320 | | * \param[in] texture texture id |
321 | | * |
322 | | * \return GLuint #framebuffer_id if operation succeeds, 0 otherwise. |
323 | | */ |
324 | | GLuint setup_framebuffer(GLuint& texture); |
325 | | |
326 | | /*!\brief Checks for gl errors. On error, internal error state is updated with details |
327 | | * |
328 | | * \param[in] msg useful description for logging |
329 | | * |
330 | | * \return none |
331 | | */ |
332 | | void check_gl_errors(const char* msg); |
333 | | |
334 | | /*!\brief Reset the current context to default state for reuse |
335 | | * |
336 | | * \return none |
337 | | */ |
338 | | void reset_opengl_ctxt(); |
339 | | |
340 | | /*!\brief Deletes the current context |
341 | | * |
342 | | * \return none |
343 | | */ |
344 | | void delete_opengl_ctxt(); |
345 | | |
346 | | } uhdr_opengl_ctxt_t; /**< alias for struct uhdr_opengl_ctxt */ |
347 | | |
348 | | bool isBufferDataContiguous(uhdr_raw_image_t* img); |
349 | | |
350 | | #endif |
351 | | |
352 | | uhdr_error_info_t uhdr_validate_gainmap_metadata_descriptor(uhdr_gainmap_metadata_t* metadata); |
353 | | |
354 | | } // namespace ultrahdr |
355 | | |
356 | | // =============================================================================================== |
357 | | // Extensions of ultrahdr api definitions, so outside ultrahdr namespace |
358 | | // =============================================================================================== |
359 | | |
360 | | struct uhdr_codec_private { |
361 | | std::deque<ultrahdr::uhdr_effect_desc_t*> m_effects; |
362 | | #ifdef UHDR_ENABLE_GLES |
363 | | ultrahdr::uhdr_opengl_ctxt_t m_uhdr_gl_ctxt; |
364 | | bool m_enable_gles; |
365 | | #endif |
366 | | bool m_sailed; |
367 | | |
368 | | virtual ~uhdr_codec_private(); |
369 | | }; |
370 | | |
371 | | struct uhdr_encoder_private : uhdr_codec_private { |
372 | | // config data |
373 | | std::map<uhdr_img_label, std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t>> m_raw_images; |
374 | | std::map<uhdr_img_label, std::unique_ptr<ultrahdr::uhdr_compressed_image_ext_t>> |
375 | | m_compressed_images; |
376 | | std::map<uhdr_img_label, int> m_quality; |
377 | | std::vector<uint8_t> m_exif; |
378 | | uhdr_gainmap_metadata_t m_metadata; |
379 | | uhdr_codec_t m_output_format; |
380 | | int m_gainmap_scale_factor; |
381 | | bool m_use_multi_channel_gainmap; |
382 | | float m_gamma; |
383 | | uhdr_enc_preset_t m_enc_preset; |
384 | | float m_min_content_boost; |
385 | | float m_max_content_boost; |
386 | | float m_target_disp_max_brightness; |
387 | | |
388 | | // internal data |
389 | | std::unique_ptr<ultrahdr::uhdr_compressed_image_ext_t> m_compressed_output_buffer; |
390 | | uhdr_error_info_t m_encode_call_status; |
391 | | }; |
392 | | |
393 | | struct uhdr_decoder_private : uhdr_codec_private { |
394 | | // config data |
395 | | std::unique_ptr<ultrahdr::uhdr_compressed_image_ext_t> m_uhdr_compressed_img; |
396 | | uhdr_img_fmt_t m_output_fmt; |
397 | | uhdr_color_transfer_t m_output_ct; |
398 | | float m_output_max_disp_boost; |
399 | | |
400 | | // internal data |
401 | | bool m_probed; |
402 | | bool m_is_jpeg; |
403 | | std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> m_decoded_img_buffer; |
404 | | std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> m_gainmap_img_buffer; |
405 | | int m_img_wd, m_img_ht; |
406 | | int m_gainmap_wd, m_gainmap_ht, m_gainmap_num_comp; |
407 | | std::vector<uint8_t> m_exif; |
408 | | uhdr_mem_block_t m_exif_block; |
409 | | std::vector<uint8_t> m_icc; |
410 | | uhdr_mem_block_t m_icc_block; |
411 | | std::vector<uint8_t> m_base_img; |
412 | | uhdr_mem_block_t m_base_img_block; |
413 | | std::vector<uint8_t> m_gainmap_img; |
414 | | uhdr_mem_block_t m_gainmap_img_block; |
415 | | uhdr_gainmap_metadata_t m_metadata; |
416 | | uhdr_error_info_t m_probe_call_status; |
417 | | uhdr_error_info_t m_decode_call_status; |
418 | | }; |
419 | | |
420 | | namespace ultrahdr { |
421 | | |
422 | | // Default configurations |
423 | | // gainmap image downscale factor |
424 | | static const int kMapDimensionScaleFactorDefault = 1; |
425 | | static const int kMapDimensionScaleFactorAndroidDefault = 4; |
426 | | |
427 | | // JPEG compress quality (0 ~ 100) for base image |
428 | | static const int kBaseCompressQualityDefault = 95; |
429 | | |
430 | | // JPEG compress quality (0 ~ 100) for gain map |
431 | | static const int kMapCompressQualityDefault = 95; |
432 | | static const int kMapCompressQualityAndroidDefault = 85; |
433 | | |
434 | | // Gain map calculation |
435 | | static const bool kUseMultiChannelGainMapDefault = true; |
436 | | static const bool kUseMultiChannelGainMapAndroidDefault = false; |
437 | | |
438 | | // encoding preset |
439 | | static const uhdr_enc_preset_t kEncSpeedPresetDefault = UHDR_USAGE_BEST_QUALITY; |
440 | | static const uhdr_enc_preset_t kEncSpeedPresetAndroidDefault = UHDR_USAGE_REALTIME; |
441 | | |
442 | | // Default gamma value for gain map |
443 | | static const float kGainMapGammaDefault = 1.0f; |
444 | | |
445 | | // The current JPEGR version that we encode to |
446 | | static const char* const kJpegrVersion = "1.0"; |
447 | | |
448 | | class UltraHdr { |
449 | | public: |
450 | | UltraHdr(void* uhdrGLESCtxt = nullptr, |
451 | | int mapDimensionScaleFactor = kMapDimensionScaleFactorAndroidDefault, |
452 | | int mapCompressQuality = kMapCompressQualityAndroidDefault, |
453 | | bool useMultiChannelGainMap = kUseMultiChannelGainMapAndroidDefault, |
454 | | float gamma = kGainMapGammaDefault, |
455 | | uhdr_enc_preset_t preset = kEncSpeedPresetAndroidDefault, |
456 | | float minContentBoost = FLT_MIN, float maxContentBoost = FLT_MAX, |
457 | | float targetDispPeakBrightness = -1.0f); |
458 | | |
459 | | /*!\brief This function receives iso block and / or xmp block and parses gainmap metadata and fill |
460 | | * the output descriptor. If both iso block and xmp block are available, then iso block is |
461 | | * preferred over xmp. |
462 | | * |
463 | | * \param[in] iso_data iso memory block |
464 | | * \param[in] iso_size iso block size |
465 | | * \param[in] xmp_data xmp memory block |
466 | | * \param[in] xmp_size xmp block size |
467 | | * \param[in, out] gainmap_metadata gainmap metadata descriptor |
468 | | * |
469 | | * \return uhdr_error_info_t #UHDR_CODEC_OK if operation succeeds, uhdr_codec_err_t otherwise. |
470 | | */ |
471 | | uhdr_error_info_t parseGainMapMetadata(uint8_t* iso_data, size_t iso_size, uint8_t* xmp_data, |
472 | | size_t xmp_size, uint8_t* exif_data, int exif_size, |
473 | | uhdr_gainmap_metadata_ext_t* uhdr_metadata); |
474 | | |
475 | | /*!\brief This method is used to tone map a hdr image |
476 | | * |
477 | | * \param[in] hdr_intent hdr image descriptor |
478 | | * \param[in, out] sdr_intent sdr image descriptor |
479 | | * |
480 | | * \return uhdr_error_info_t #UHDR_CODEC_OK if operation succeeds, uhdr_codec_err_t otherwise. |
481 | | */ |
482 | | uhdr_error_info_t toneMap(uhdr_raw_image_t* hdr_intent, uhdr_raw_image_t* sdr_intent); |
483 | | |
484 | | /*!\brief This method takes hdr intent and sdr intent and computes gainmap coefficient. |
485 | | * |
486 | | * This method is called in the encoding pipeline. It takes uncompressed 8-bit and 10-bit yuv |
487 | | * images as input and calculates gainmap. |
488 | | * |
489 | | * NOTE: The input images must be the same resolution. |
490 | | * NOTE: The SDR input is assumed to use the sRGB transfer function. |
491 | | * |
492 | | * \param[in] sdr_intent sdr intent raw input image descriptor |
493 | | * \param[in] hdr_intent hdr intent raw input image descriptor |
494 | | * \param[in, out] gainmap_metadata gainmap metadata descriptor |
495 | | * \param[in, out] gainmap_img gainmap image descriptor |
496 | | * \param[in] sdr_is_601 (optional) if sdr_is_601 is true, then use BT.601 |
497 | | * gamut to represent sdr intent regardless of the value |
498 | | * present in the sdr intent image descriptor |
499 | | * \param[in] use_luminance (optional) used for single channel gainmap. If |
500 | | * use_luminance is true, gainmap calculation is based |
501 | | * on the pixel's luminance which is a weighted |
502 | | * combination of r, g, b channels; otherwise, gainmap |
503 | | * calculation is based of the maximun value of r, g, b |
504 | | * channels. |
505 | | * |
506 | | * \return uhdr_error_info_t #UHDR_CODEC_OK if operation succeeds, uhdr_codec_err_t otherwise. |
507 | | */ |
508 | | uhdr_error_info_t generateGainMap(uhdr_raw_image_t* sdr_intent, uhdr_raw_image_t* hdr_intent, |
509 | | uhdr_gainmap_metadata_ext_t* gainmap_metadata, |
510 | | std::unique_ptr<uhdr_raw_image_ext_t>& gainmap_img, |
511 | | bool sdr_is_601 = false, bool use_luminance = true); |
512 | | |
513 | | /*!\brief This method takes sdr intent, gainmap image and gainmap metadata and computes hdr |
514 | | * intent. This method is called in the decoding pipeline. The output hdr intent image will have |
515 | | * same color gamut as sdr intent. |
516 | | * |
517 | | * NOTE: The SDR input is assumed to use the sRGB transfer function. |
518 | | * |
519 | | * \param[in] sdr_intent sdr intent raw input image descriptor |
520 | | * \param[in] gainmap_img gainmap image descriptor |
521 | | * \param[in] gainmap_metadata gainmap metadata descriptor |
522 | | * \param[in] output_ct output color transfer |
523 | | * \param[in] output_format output pixel format |
524 | | * \param[in] max_display_boost the maximum available boost supported by a |
525 | | * display, the value must be greater than or equal |
526 | | * to 1.0 |
527 | | * \param[in, out] dest output image descriptor to store output |
528 | | * |
529 | | * \return uhdr_error_info_t #UHDR_CODEC_OK if operation succeeds, uhdr_codec_err_t otherwise. |
530 | | */ |
531 | | uhdr_error_info_t applyGainMap(uhdr_raw_image_t* sdr_intent, uhdr_raw_image_t* gainmap_img, |
532 | | uhdr_gainmap_metadata_ext_t* gainmap_metadata, |
533 | | uhdr_color_transfer_t output_ct, uhdr_img_fmt_t output_format, |
534 | | float max_display_boost, uhdr_raw_image_t* dest); |
535 | | |
536 | | /*!\brief This method is used to convert a raw image from one gamut space to another gamut space |
537 | | * in-place. |
538 | | * |
539 | | * \param[in, out] image raw image descriptor |
540 | | * \param[in] src_encoding input gamut space |
541 | | * \param[in] dst_encoding destination gamut space |
542 | | * |
543 | | * \return uhdr_error_info_t #UHDR_CODEC_OK if operation succeeds, uhdr_codec_err_t otherwise. |
544 | | */ |
545 | | uhdr_error_info_t convertYuv(uhdr_raw_image_t* image, uhdr_color_gamut_t src_encoding, |
546 | | uhdr_color_gamut_t dst_encoding); |
547 | | |
548 | | protected: |
549 | | /*!\brief set gain map dimension scale factor |
550 | | * NOTE: Applicable only in encoding scenario |
551 | | * |
552 | | * \param[in] mapDimensionScaleFactor scale factor |
553 | | * |
554 | | * \return none |
555 | | */ |
556 | 0 | void setMapDimensionScaleFactor(int mapDimensionScaleFactor) { |
557 | 0 | this->mMapDimensionScaleFactor = mapDimensionScaleFactor; |
558 | 0 | } |
559 | | |
560 | | /*!\brief get gain map dimension scale factor |
561 | | * NOTE: Applicable only in encoding scenario |
562 | | * |
563 | | * \return mapDimensionScaleFactor |
564 | | */ |
565 | 0 | int getMapDimensionScaleFactor() { return this->mMapDimensionScaleFactor; } |
566 | | |
567 | | /*!\brief set gain map compression quality factor |
568 | | * NOTE: Applicable only in encoding scenario |
569 | | * |
570 | | * \param[in] mapCompressQuality quality factor for gain map image compression |
571 | | * |
572 | | * \return none |
573 | | */ |
574 | 0 | void setMapCompressQuality(int mapCompressQuality) { |
575 | 0 | this->mMapCompressQuality = mapCompressQuality; |
576 | 0 | } |
577 | | |
578 | | /*!\brief get gain map quality factor |
579 | | * NOTE: Applicable only in encoding scenario |
580 | | * |
581 | | * \return quality factor |
582 | | */ |
583 | 0 | int getMapCompressQuality() { return this->mMapCompressQuality; } |
584 | | |
585 | | /*!\brief set gain map gamma |
586 | | * NOTE: Applicable only in encoding scenario |
587 | | * |
588 | | * \param[in] gamma gamma parameter that is used for gain map calculation |
589 | | * |
590 | | * \return none |
591 | | */ |
592 | 0 | void setGainMapGamma(float gamma) { this->mGamma = gamma; } |
593 | | |
594 | | /*!\brief get gain map gamma |
595 | | * NOTE: Applicable only in encoding scenario |
596 | | * |
597 | | * \return gamma parameter |
598 | | */ |
599 | 0 | float getGainMapGamma() { return this->mGamma; } |
600 | | |
601 | | /*!\brief enable / disable multi channel gain map |
602 | | * NOTE: Applicable only in encoding scenario |
603 | | * |
604 | | * \param[in] useMultiChannelGainMap enable / disable multi channel gain map |
605 | | * |
606 | | * \return none |
607 | | */ |
608 | 0 | void setUseMultiChannelGainMap(bool useMultiChannelGainMap) { |
609 | 0 | this->mUseMultiChannelGainMap = useMultiChannelGainMap; |
610 | 0 | } |
611 | | |
612 | | /*!\brief check if multi channel gain map is enabled |
613 | | * NOTE: Applicable only in encoding scenario |
614 | | * |
615 | | * \return true if multi channel gain map is enabled, false otherwise |
616 | | */ |
617 | 0 | bool isUsingMultiChannelGainMap() { return this->mUseMultiChannelGainMap; } |
618 | | |
619 | | /*!\brief set gain map min and max content boost |
620 | | * NOTE: Applicable only in encoding scenario |
621 | | * |
622 | | * \param[in] minBoost gain map min content boost |
623 | | * \param[in] maxBoost gain map max content boost |
624 | | * |
625 | | * \return none |
626 | | */ |
627 | 0 | void setGainMapMinMaxContentBoost(float minBoost, float maxBoost) { |
628 | 0 | this->mMinContentBoost = minBoost; |
629 | 0 | this->mMaxContentBoost = maxBoost; |
630 | 0 | } |
631 | | |
632 | | /*!\brief get gain map min max content boost |
633 | | * NOTE: Applicable only in encoding scenario |
634 | | * |
635 | | * \param[out] minBoost gain map min content boost |
636 | | * \param[out] maxBoost gain map max content boost |
637 | | * |
638 | | * \return none |
639 | | */ |
640 | 0 | void getGainMapMinMaxContentBoost(float& minBoost, float& maxBoost) { |
641 | 0 | minBoost = this->mMinContentBoost; |
642 | 0 | maxBoost = this->mMaxContentBoost; |
643 | 0 | } |
644 | | |
645 | | // Configurations |
646 | | void* mUhdrGLESCtxt; // opengl es context |
647 | | int mMapDimensionScaleFactor; // gain map scale factor |
648 | | int mMapCompressQuality; // gain map quality factor |
649 | | bool mUseMultiChannelGainMap; // enable multichannel gain map |
650 | | float mGamma; // gain map gamma parameter |
651 | | uhdr_enc_preset_t mEncPreset; // encoding speed preset |
652 | | float mMinContentBoost; // min content boost recommendation |
653 | | float mMaxContentBoost; // max content boost recommendation |
654 | | float mTargetDispPeakBrightness; // target display max luminance in nits |
655 | | }; |
656 | | |
657 | | /* |
658 | | * Holds tonemapping results of a pixel |
659 | | */ |
660 | | struct GlobalTonemapOutputs { |
661 | | std::array<float, 3> rgb_out; |
662 | | float y_hdr; |
663 | | float y_sdr; |
664 | | }; |
665 | | |
666 | | /*!\brief Applies a global tone mapping, based on Chrome's HLG/PQ rendering implemented at |
667 | | * https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/color_transform.cc;l=1197-1252;drc=ac505aff1d29ec3bfcf317cb77d5e196a3664e92 |
668 | | * |
669 | | * \param[in] rgb_in hdr intent pixel in array format. |
670 | | * \param[in] headroom ratio between hdr and sdr peak luminances. Must be greater |
671 | | * than 1. If the input is normalized, then this is used to |
672 | | * stretch it linearly from [0.0..1.0] to [0.0..headroom] |
673 | | * \param[in] is_normalized marker to differentiate, if the input is normalized. |
674 | | * |
675 | | * \return tonemapped pixel in the normalized range [0.0..1.0] |
676 | | */ |
677 | | GlobalTonemapOutputs globalTonemap(const std::array<float, 3>& rgb_in, float headroom, |
678 | | bool is_normalized); |
679 | | } // namespace ultrahdr |
680 | | |
681 | | #endif // ULTRAHDR_ULTRAHDRCOMMON_H |