/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 <cstdint> |
22 | | #include <deque> |
23 | | #include <map> |
24 | | #include <memory> |
25 | | #include <string> |
26 | | #include <vector> |
27 | | |
28 | | #include "ultrahdr_api.h" |
29 | | |
30 | | // =============================================================================================== |
31 | | // Function Macros |
32 | | // =============================================================================================== |
33 | | |
34 | | #ifdef __ANDROID__ |
35 | | |
36 | | #ifdef LOG_NDEBUG |
37 | | #include "android/log.h" |
38 | | |
39 | | #ifndef LOG_TAG |
40 | | #define LOG_TAG "UHDR" |
41 | | #endif |
42 | | |
43 | | #ifndef ALOGD |
44 | | #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) |
45 | | #endif |
46 | | |
47 | | #ifndef ALOGE |
48 | | #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) |
49 | | #endif |
50 | | |
51 | | #ifndef ALOGI |
52 | | #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) |
53 | | #endif |
54 | | |
55 | | #ifndef ALOGV |
56 | | #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) |
57 | | #endif |
58 | | |
59 | | #ifndef ALOGW |
60 | | #define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) |
61 | | #endif |
62 | | |
63 | | #else |
64 | | |
65 | | #define ALOGD(...) ((void)0) |
66 | | #define ALOGE(...) ((void)0) |
67 | | #define ALOGI(...) ((void)0) |
68 | | #define ALOGV(...) ((void)0) |
69 | | #define ALOGW(...) ((void)0) |
70 | | |
71 | | #endif |
72 | | |
73 | | #else |
74 | | |
75 | | #ifdef LOG_NDEBUG |
76 | | #include <cstdio> |
77 | | |
78 | | #define ALOGD(...) \ |
79 | | do { \ |
80 | | fprintf(stderr, __VA_ARGS__); \ |
81 | | fprintf(stderr, "\n"); \ |
82 | | } while (0) |
83 | | |
84 | | #define ALOGE(...) \ |
85 | | do { \ |
86 | | fprintf(stderr, __VA_ARGS__); \ |
87 | | fprintf(stderr, "\n"); \ |
88 | | } while (0) |
89 | | |
90 | | #define ALOGI(...) \ |
91 | | do { \ |
92 | | fprintf(stdout, __VA_ARGS__); \ |
93 | | fprintf(stdout, "\n"); \ |
94 | | } while (0) |
95 | | |
96 | | #define ALOGV(...) \ |
97 | | do { \ |
98 | | fprintf(stdout, __VA_ARGS__); \ |
99 | | fprintf(stdout, "\n"); \ |
100 | | } while (0) |
101 | | |
102 | | #define ALOGW(...) \ |
103 | | do { \ |
104 | | fprintf(stderr, __VA_ARGS__); \ |
105 | | fprintf(stderr, "\n"); \ |
106 | | } while (0) |
107 | | |
108 | | #else |
109 | | |
110 | 356 | #define ALOGD(...) ((void)0) |
111 | 41.2k | #define ALOGE(...) ((void)0) |
112 | | #define ALOGI(...) ((void)0) |
113 | 75.5k | #define ALOGV(...) ((void)0) |
114 | 985 | #define ALOGW(...) ((void)0) |
115 | | |
116 | | #endif |
117 | | |
118 | | #endif |
119 | | |
120 | 85.3k | #define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m)) |
121 | | |
122 | | #define UHDR_ERR_CHECK(x) \ |
123 | 504k | { \ |
124 | 504k | uhdr_error_info_t status = (x); \ |
125 | 504k | if (status.error_code != UHDR_CODEC_OK) { \ |
126 | 17.0k | return status; \ |
127 | 17.0k | } \ |
128 | 504k | } |
129 | | |
130 | | #if defined(_MSC_VER) |
131 | | #define FORCE_INLINE __forceinline |
132 | | #define INLINE __inline |
133 | | #else |
134 | | #define FORCE_INLINE __inline__ __attribute__((always_inline)) |
135 | | #define INLINE inline |
136 | | #endif |
137 | | |
138 | | // '__has_attribute' macro was introduced by clang. later picked up by gcc. |
139 | | // If not supported by the current toolchain, define it to zero. |
140 | | #ifndef __has_attribute |
141 | | #define __has_attribute(x) 0 |
142 | | #endif |
143 | | |
144 | | // Disables undefined behavior analysis for a function. |
145 | | // GCC 4.9+ uses __attribute__((no_sanitize_undefined)) |
146 | | // clang uses __attribute__((no_sanitize("undefined"))) |
147 | | #if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 409) |
148 | | #define UHDR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined)) |
149 | | #elif __has_attribute(no_sanitize) |
150 | | #define UHDR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize("undefined"))) |
151 | | #else |
152 | | #define UHDR_NO_SANITIZE_UNDEFINED |
153 | | #endif |
154 | | |
155 | | static const uhdr_error_info_t g_no_error = {UHDR_CODEC_OK, 0, ""}; |
156 | | |
157 | | namespace ultrahdr { |
158 | | |
159 | | // =============================================================================================== |
160 | | // Globals |
161 | | // =============================================================================================== |
162 | | extern const int kMinWidth, kMinHeight; |
163 | | extern const int kMaxWidth, kMaxHeight; |
164 | | |
165 | | // =============================================================================================== |
166 | | // Structure Definitions |
167 | | // =============================================================================================== |
168 | | |
169 | | /**\brief uhdr memory block */ |
170 | | typedef struct uhdr_memory_block { |
171 | | uhdr_memory_block(size_t capacity); |
172 | | |
173 | | std::unique_ptr<uint8_t[]> m_buffer; /**< data */ |
174 | | size_t m_capacity; /**< capacity */ |
175 | | } uhdr_memory_block_t; /**< alias for struct uhdr_memory_block */ |
176 | | |
177 | | /**\brief extended raw image descriptor */ |
178 | | typedef struct uhdr_raw_image_ext : uhdr_raw_image_t { |
179 | | uhdr_raw_image_ext(uhdr_img_fmt_t fmt, uhdr_color_gamut_t cg, uhdr_color_transfer_t ct, |
180 | | uhdr_color_range_t range, unsigned w, unsigned h, unsigned align_stride_to); |
181 | | |
182 | | private: |
183 | | std::unique_ptr<ultrahdr::uhdr_memory_block> m_block; |
184 | | } uhdr_raw_image_ext_t; /**< alias for struct uhdr_raw_image_ext */ |
185 | | |
186 | | /**\brief extended compressed image descriptor */ |
187 | | typedef struct uhdr_compressed_image_ext : uhdr_compressed_image_t { |
188 | | uhdr_compressed_image_ext(uhdr_color_gamut_t cg, uhdr_color_transfer_t ct, |
189 | | uhdr_color_range_t range, size_t sz); |
190 | | |
191 | | private: |
192 | | std::unique_ptr<ultrahdr::uhdr_memory_block> m_block; |
193 | | } uhdr_compressed_image_ext_t; /**< alias for struct uhdr_compressed_image_ext */ |
194 | | |
195 | | /*!\brief forward declaration for image effect descriptor */ |
196 | | typedef struct uhdr_effect_desc uhdr_effect_desc_t; |
197 | | |
198 | | /**\brief Gain map metadata. */ |
199 | | typedef struct uhdr_gainmap_metadata_ext : uhdr_gainmap_metadata { |
200 | 25.7k | uhdr_gainmap_metadata_ext() {} |
201 | | |
202 | 2.53k | uhdr_gainmap_metadata_ext(std::string ver) : version(ver) {} |
203 | | |
204 | | uhdr_gainmap_metadata_ext(uhdr_gainmap_metadata& metadata, std::string ver) |
205 | 0 | : uhdr_gainmap_metadata_ext(ver) { |
206 | 0 | std::copy(metadata.max_content_boost, metadata.max_content_boost + 3, max_content_boost); |
207 | 0 | std::copy(metadata.min_content_boost, metadata.min_content_boost + 3, min_content_boost); |
208 | 0 | std::copy(metadata.gamma, metadata.gamma + 3, gamma); |
209 | 0 | std::copy(metadata.offset_sdr, metadata.offset_sdr + 3, offset_sdr); |
210 | 0 | std::copy(metadata.offset_hdr, metadata.offset_hdr + 3, offset_hdr); |
211 | 0 | hdr_capacity_min = metadata.hdr_capacity_min; |
212 | 0 | hdr_capacity_max = metadata.hdr_capacity_max; |
213 | 0 | use_base_cg = metadata.use_base_cg; |
214 | 0 | } |
215 | | |
216 | 6.38k | bool are_all_channels_identical() const { |
217 | 6.38k | return max_content_boost[0] == max_content_boost[1] && |
218 | 6.09k | max_content_boost[0] == max_content_boost[2] && |
219 | 6.04k | min_content_boost[0] == min_content_boost[1] && |
220 | 6.00k | min_content_boost[0] == min_content_boost[2] && gamma[0] == gamma[1] && |
221 | 5.98k | gamma[0] == gamma[2] && offset_sdr[0] == offset_sdr[1] && |
222 | 5.98k | offset_sdr[0] == offset_sdr[2] && offset_hdr[0] == offset_hdr[1] && |
223 | 5.98k | offset_hdr[0] == offset_hdr[2]; |
224 | 6.38k | } |
225 | | |
226 | | std::string version; /**< Ultra HDR format version */ |
227 | | } uhdr_gainmap_metadata_ext_t; /**< alias for struct uhdr_gainmap_metadata */ |
228 | | |
229 | | #ifdef UHDR_ENABLE_GLES |
230 | | |
231 | | typedef enum uhdr_effect_shader { |
232 | | UHDR_MIR_HORZ, |
233 | | UHDR_MIR_VERT, |
234 | | UHDR_ROT_90, |
235 | | UHDR_ROT_180, |
236 | | UHDR_ROT_270, |
237 | | UHDR_CROP, |
238 | | UHDR_RESIZE, |
239 | | } uhdr_effect_shader_t; |
240 | | |
241 | | /**\brief OpenGL context */ |
242 | | typedef struct uhdr_opengl_ctxt { |
243 | | // EGL Context |
244 | | EGLDisplay mEGLDisplay; /**< EGL display connection */ |
245 | | EGLContext mEGLContext; /**< EGL rendering context */ |
246 | | EGLSurface mEGLSurface; /**< EGL surface for rendering */ |
247 | | EGLConfig mEGLConfig; /**< EGL frame buffer configuration */ |
248 | | |
249 | | // GLES Context |
250 | | GLuint mQuadVAO, mQuadVBO, mQuadEBO; /**< GL objects */ |
251 | | GLuint mShaderProgram[UHDR_RESIZE + 1]; /**< Shader programs */ |
252 | | GLuint mDecodedImgTexture, mGainmapImgTexture; /**< GL Textures */ |
253 | | uhdr_error_info_t mErrorStatus; /**< Context status */ |
254 | | |
255 | | uhdr_opengl_ctxt(); |
256 | | ~uhdr_opengl_ctxt(); |
257 | | |
258 | | /*!\brief Initializes the OpenGL context. Mainly it prepares EGL. We want a GLES3.0 context and a |
259 | | * surface that supports pbuffer. Once this is done and surface is made current, the gl state is |
260 | | * initialized |
261 | | * |
262 | | * \return none |
263 | | */ |
264 | | void init_opengl_ctxt(); |
265 | | |
266 | | /*!\brief This method is used to compile a shader |
267 | | * |
268 | | * \param[in] type shader type |
269 | | * \param[in] source shader source code |
270 | | * |
271 | | * \return GLuint #shader_id if operation succeeds, 0 otherwise. |
272 | | */ |
273 | | GLuint compile_shader(GLenum type, const char* source); |
274 | | |
275 | | /*!\brief This method is used to create a shader program |
276 | | * |
277 | | * \param[in] vertex_source vertex shader source code |
278 | | * \param[in] fragment_source fragment shader source code |
279 | | * |
280 | | * \return GLuint #shader_program_id if operation succeeds, 0 otherwise. |
281 | | */ |
282 | | GLuint create_shader_program(const char* vertex_source, const char* fragment_source); |
283 | | |
284 | | /*!\brief This method is used to create a 2D texture for a raw image |
285 | | * NOTE: For multichannel planar image, this method assumes the channel data to be contiguous |
286 | | * NOTE: For any channel, this method assumes width and stride to be identical |
287 | | * |
288 | | * \param[in] fmt image format |
289 | | * \param[in] w image width |
290 | | * \param[in] h image height |
291 | | * \param[in] data image data |
292 | | * |
293 | | * \return GLuint #texture_id if operation succeeds, 0 otherwise. |
294 | | */ |
295 | | GLuint create_texture(uhdr_img_fmt_t fmt, int w, int h, void* data); |
296 | | |
297 | | /*!\breif This method is used to read data from texture into a raw image |
298 | | * NOTE: For any channel, this method assumes width and stride to be identical |
299 | | * |
300 | | * \param[in] texture texture_id |
301 | | * \param[in] fmt image format |
302 | | * \param[in] w image width |
303 | | * \param[in] h image height |
304 | | * \param[in] data image data |
305 | | * |
306 | | * \return none |
307 | | */ |
308 | | void read_texture(GLuint* texture, uhdr_img_fmt_t fmt, int w, int h, void* data); |
309 | | |
310 | | /*!\brief This method is used to set up quad buffers and arrays |
311 | | * |
312 | | * \return none |
313 | | */ |
314 | | void setup_quad(); |
315 | | |
316 | | /*!\brief This method is used to set up frame buffer for a 2D texture |
317 | | * |
318 | | * \param[in] texture texture id |
319 | | * |
320 | | * \return GLuint #framebuffer_id if operation succeeds, 0 otherwise. |
321 | | */ |
322 | | GLuint setup_framebuffer(GLuint& texture); |
323 | | |
324 | | /*!\brief Checks for gl errors. On error, internal error state is updated with details |
325 | | * |
326 | | * \param[in] msg useful description for logging |
327 | | * |
328 | | * \return none |
329 | | */ |
330 | | void check_gl_errors(const char* msg); |
331 | | |
332 | | /*!\brief Reset the current context to default state for reuse |
333 | | * |
334 | | * \return none |
335 | | */ |
336 | | void reset_opengl_ctxt(); |
337 | | |
338 | | /*!\brief Deletes the current context |
339 | | * |
340 | | * \return none |
341 | | */ |
342 | | void delete_opengl_ctxt(); |
343 | | |
344 | | } uhdr_opengl_ctxt_t; /**< alias for struct uhdr_opengl_ctxt */ |
345 | | |
346 | | bool isBufferDataContiguous(uhdr_raw_image_t* img); |
347 | | |
348 | | #endif |
349 | | |
350 | | uhdr_error_info_t uhdr_validate_gainmap_metadata_descriptor(uhdr_gainmap_metadata_t* metadata); |
351 | | |
352 | | } // namespace ultrahdr |
353 | | |
354 | | // =============================================================================================== |
355 | | // Extensions of ultrahdr api definitions, so outside ultrahdr namespace |
356 | | // =============================================================================================== |
357 | | |
358 | | struct uhdr_codec_private { |
359 | | std::deque<ultrahdr::uhdr_effect_desc_t*> m_effects; |
360 | | #ifdef UHDR_ENABLE_GLES |
361 | | ultrahdr::uhdr_opengl_ctxt_t m_uhdr_gl_ctxt; |
362 | | bool m_enable_gles; |
363 | | #endif |
364 | | bool m_sailed; |
365 | | |
366 | | virtual ~uhdr_codec_private(); |
367 | | }; |
368 | | |
369 | | struct uhdr_encoder_private : uhdr_codec_private { |
370 | | // config data |
371 | | std::map<uhdr_img_label, std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t>> m_raw_images; |
372 | | std::map<uhdr_img_label, std::unique_ptr<ultrahdr::uhdr_compressed_image_ext_t>> |
373 | | m_compressed_images; |
374 | | std::map<uhdr_img_label, int> m_quality; |
375 | | std::vector<uint8_t> m_exif; |
376 | | uhdr_gainmap_metadata_t m_metadata; |
377 | | uhdr_codec_t m_output_format; |
378 | | int m_gainmap_scale_factor; |
379 | | bool m_use_multi_channel_gainmap; |
380 | | float m_gamma; |
381 | | uhdr_enc_preset_t m_enc_preset; |
382 | | float m_min_content_boost; |
383 | | float m_max_content_boost; |
384 | | float m_target_disp_max_brightness; |
385 | | |
386 | | // internal data |
387 | | std::unique_ptr<ultrahdr::uhdr_compressed_image_ext_t> m_compressed_output_buffer; |
388 | | uhdr_error_info_t m_encode_call_status; |
389 | | }; |
390 | | |
391 | | struct uhdr_decoder_private : uhdr_codec_private { |
392 | | // config data |
393 | | std::unique_ptr<ultrahdr::uhdr_compressed_image_ext_t> m_uhdr_compressed_img; |
394 | | uhdr_img_fmt_t m_output_fmt; |
395 | | uhdr_color_transfer_t m_output_ct; |
396 | | float m_output_max_disp_boost; |
397 | | |
398 | | // internal data |
399 | | bool m_probed; |
400 | | std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> m_decoded_img_buffer; |
401 | | std::unique_ptr<ultrahdr::uhdr_raw_image_ext_t> m_gainmap_img_buffer; |
402 | | int m_img_wd, m_img_ht; |
403 | | int m_gainmap_wd, m_gainmap_ht, m_gainmap_num_comp; |
404 | | std::vector<uint8_t> m_exif; |
405 | | uhdr_mem_block_t m_exif_block; |
406 | | std::vector<uint8_t> m_icc; |
407 | | uhdr_mem_block_t m_icc_block; |
408 | | std::vector<uint8_t> m_base_img; |
409 | | uhdr_mem_block_t m_base_img_block; |
410 | | std::vector<uint8_t> m_gainmap_img; |
411 | | uhdr_mem_block_t m_gainmap_img_block; |
412 | | uhdr_gainmap_metadata_t m_metadata; |
413 | | uhdr_error_info_t m_probe_call_status; |
414 | | uhdr_error_info_t m_decode_call_status; |
415 | | }; |
416 | | |
417 | | #endif // ULTRAHDR_ULTRAHDRCOMMON_H |