FFmpeg
Loading...
Searching...
No Matches
hdr_dynamic_metadata.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <limits.h>
20#include <stdio.h>
21#include <string.h>
22
23#include "libavutil/error.h"
24#include "libavutil/frame.h"
26#include "libavutil/mem.h"
27#include "libavutil/rational.h"
28
29/* Denominators av_dynamic_hdr_plus_to_t35() quantises to. The fixtures below
30 * express every rational in these terms, so a correct round trip reproduces
31 * the input exactly and the decoded values printed here can be compared
32 * against the fixture directly. */
33#define LUMINANCE_DEN 1
34#define PEAK_LUMINANCE_DEN 15
35#define RGB_DEN 100000
36#define FRACTION_PIXEL_DEN 1000
37#define KNEE_POINT_DEN 4095
38#define BEZIER_ANCHOR_DEN 1023
39#define SATURATION_DEN 8
40
41/*
42 * Printers. Every field a fixture populates is printed, so that a serializer
43 * or parser which drops or corrupts a value changes the FATE reference
44 * instead of silently passing a flag-only check.
45 */
46
47static void print_peak_matrix(const char *label, int rows, int cols,
48 const AVRational m[25][25])
49{
50 printf(" %s %dx%d:", label, rows, cols);
51 for (int i = 0; i < rows; i++)
52 for (int j = 0; j < cols; j++)
53 printf(" %d/%d", m[i][j].num, m[i][j].den);
54 printf("\n");
55}
56
58 int geometry)
59{
60 printf(" window %d:\n", w);
61 /* Window 0 covers the whole frame; its geometry is not serialized. */
62 if (geometry) {
63 printf(" corners: ul=%d/%d,%d/%d lr=%d/%d,%d/%d\n",
64 p->window_upper_left_corner_x.num,
65 p->window_upper_left_corner_x.den,
66 p->window_upper_left_corner_y.num,
67 p->window_upper_left_corner_y.den,
68 p->window_lower_right_corner_x.num,
69 p->window_lower_right_corner_x.den,
70 p->window_lower_right_corner_y.num,
71 p->window_lower_right_corner_y.den);
72 printf(" ellipse: center=%u,%u rotation=%u semimajor_int=%u"
73 " semimajor_ext=%u semiminor_ext=%u overlap=%u\n",
74 p->center_of_ellipse_x, p->center_of_ellipse_y,
75 p->rotation_angle, p->semimajor_axis_internal_ellipse,
76 p->semimajor_axis_external_ellipse,
77 p->semiminor_axis_external_ellipse,
78 p->overlap_process_option);
79 }
80 printf(" maxscl: %d/%d %d/%d %d/%d average_maxrgb=%d/%d\n",
81 p->maxscl[0].num, p->maxscl[0].den,
82 p->maxscl[1].num, p->maxscl[1].den,
83 p->maxscl[2].num, p->maxscl[2].den,
84 p->average_maxrgb.num, p->average_maxrgb.den);
85 printf(" distribution_maxrgb: n=%u",
86 p->num_distribution_maxrgb_percentiles);
87 for (int i = 0; i < p->num_distribution_maxrgb_percentiles; i++)
88 printf(" %u%%=%d/%d", p->distribution_maxrgb[i].percentage,
89 p->distribution_maxrgb[i].percentile.num,
90 p->distribution_maxrgb[i].percentile.den);
91 printf("\n fraction_bright_pixels=%d/%d\n",
92 p->fraction_bright_pixels.num, p->fraction_bright_pixels.den);
93 printf(" tone_mapping_flag=%u", p->tone_mapping_flag);
94 if (p->tone_mapping_flag) {
95 printf(" knee=%d/%d,%d/%d anchors=%u:",
96 p->knee_point_x.num, p->knee_point_x.den,
97 p->knee_point_y.num, p->knee_point_y.den,
98 p->num_bezier_curve_anchors);
99 for (int i = 0; i < p->num_bezier_curve_anchors; i++)
100 printf(" %d/%d", p->bezier_curve_anchors[i].num,
101 p->bezier_curve_anchors[i].den);
102 }
103 printf("\n color_saturation_mapping_flag=%u",
104 p->color_saturation_mapping_flag);
105 if (p->color_saturation_mapping_flag)
106 printf(" weight=%d/%d", p->color_saturation_weight.num,
107 p->color_saturation_weight.den);
108 printf("\n");
109}
110
111static void print_hdr_plus(const char *label, const AVDynamicHDRPlus *s)
112{
113 printf("%s:\n", label);
114 printf(" application_version=%u num_windows=%u"
115 " targeted_system_display_maximum_luminance=%d/%d\n",
116 s->application_version, s->num_windows,
117 s->targeted_system_display_maximum_luminance.num,
118 s->targeted_system_display_maximum_luminance.den);
119 printf(" targeted_system_display_actual_peak_luminance_flag=%u\n",
120 s->targeted_system_display_actual_peak_luminance_flag);
121 if (s->targeted_system_display_actual_peak_luminance_flag)
122 print_peak_matrix("targeted_peak",
123 s->num_rows_targeted_system_display_actual_peak_luminance,
124 s->num_cols_targeted_system_display_actual_peak_luminance,
125 s->targeted_system_display_actual_peak_luminance);
126 printf(" mastering_display_actual_peak_luminance_flag=%u\n",
127 s->mastering_display_actual_peak_luminance_flag);
128 if (s->mastering_display_actual_peak_luminance_flag)
129 print_peak_matrix("mastering_peak",
130 s->num_rows_mastering_display_actual_peak_luminance,
131 s->num_cols_mastering_display_actual_peak_luminance,
132 s->mastering_display_actual_peak_luminance);
133 for (int w = 0; w < s->num_windows; w++)
134 print_window(w, &s->params[w], w > 0);
135}
136
137static void print_app5(const char *label, const AVDynamicHDRSmpte2094App5 *s)
138{
139 printf("%s:\n", label);
140 printf(" application_version=%u minimum_application_version=%u\n",
141 s->application_version, s->minimum_application_version);
142 printf(" has_custom_hdr_reference_white_flag=%u",
143 s->has_custom_hdr_reference_white_flag);
144 if (s->has_custom_hdr_reference_white_flag)
145 printf(" hdr_reference_white=0x%04x", s->hdr_reference_white);
146 printf("\n has_adaptive_tone_map_flag=%u\n",
147 s->has_adaptive_tone_map_flag);
148 if (!s->has_adaptive_tone_map_flag)
149 return;
150
151 printf(" baseline_hdr_headroom=0x%04x"
152 " use_reference_white_tone_mapping_flag=%u\n",
153 s->baseline_hdr_headroom, s->use_reference_white_tone_mapping_flag);
154 if (s->use_reference_white_tone_mapping_flag)
155 return;
156
157 printf(" num_alternate_images=%u chromaticities_flag=%u"
158 " has_common_component_mix_params_flag=%u"
159 " has_common_curve_params_flag=%u\n",
160 s->num_alternate_images,
161 s->gain_application_space_chromaticities_flag,
162 s->has_common_component_mix_params_flag,
163 s->has_common_curve_params_flag);
164 if (s->gain_application_space_chromaticities_flag == 3) {
165 printf(" chromaticities:");
166 for (int r = 0; r < 8; r++)
167 printf(" 0x%04x", s->gain_application_space_chromaticities[r]);
168 printf("\n");
169 }
170
171 for (int a = 0; a < s->num_alternate_images; a++) {
172 int n = s->gain_curve_num_control_points_minus_1[a] + 1;
173 printf(" alternate %d: hdr_headroom=0x%04x component_mixing_type=%u\n",
174 a, s->alternate_hdr_headrooms[a], s->component_mixing_type[a]);
175 if (s->component_mixing_type[a] == 3) {
176 printf(" mixing flag:coefficient:");
177 for (int k = 0; k < 6; k++)
178 printf(" %u:0x%04x",
179 s->has_component_mixing_coefficient_flag[a][k],
180 s->component_mixing_coefficient[a][k]);
181 printf("\n");
182 }
183 printf(" curve: num_control_points=%d use_pchip_slope=%u\n", n,
184 s->gain_curve_use_pchip_slope_flag[a]);
185 printf(" x:");
186 for (int c = 0; c < n; c++)
187 printf(" 0x%04x", s->gain_curve_control_points_x[a][c]);
188 printf("\n y:");
189 for (int c = 0; c < n; c++)
190 printf(" 0x%04x", s->gain_curve_control_points_y[a][c]);
191 printf("\n");
192 /* theta is only serialized when the pchip slope is not used. */
193 if (!s->gain_curve_use_pchip_slope_flag[a]) {
194 printf(" theta:");
195 for (int c = 0; c < n; c++)
196 printf(" 0x%04x", s->gain_curve_control_points_theta[a][c]);
197 printf("\n");
198 }
199 }
200}
201
202/*
203 * Round-trip helpers: serialize, then parse back into a zeroed struct.
204 */
205
207{
208 uint8_t *buf = NULL;
209 size_t size = 0;
210 int ret;
211
212 ret = av_dynamic_hdr_plus_to_t35(in, &buf, &size);
213 if (ret < 0)
214 return ret;
215
216 memset(out, 0, sizeof(*out));
218 av_free(buf);
219 return ret;
220}
221
224{
225 uint8_t *buf = NULL;
226 size_t size = 0;
227 int ret;
228
230 if (ret < 0)
231 return ret;
232
233 memset(out, 0, sizeof(*out));
235 av_free(buf);
236 return ret;
237}
238
239/*
240 * Fixtures.
241 */
242
243/* A conforming ST 2094-40:2020 ApplicationVersion 1 payload: exactly one
244 * processing window, neither actual-peak-luminance item and no
245 * ColorSaturationWeight (§9.4 excludes all three for Version 1), and the nine
246 * distribution maxrgb percentiles §8.5.4 requires for that version.
247 * CTA-861-H fixes application_version at 1 for HDR10+ carried over T.35.
248 *
249 * The entries for 5% and 10% are not CFD percentile samples: §8.5.4 reserves
250 * every value other than 0.00000 and 0.00255 for that pair. No other entry may
251 * exceed the largest MaxSCL component either, since §8.3 takes MaxSCL over each
252 * RGB component separately while §8.5.2 draws the distribution from the
253 * per-pixel maximum component. */
255{
256 static const uint8_t percentages[9] = { 1, 5, 10, 25, 50, 75, 90, 95, 99 };
257 static const int percentiles[9] = {
258 1000, 0, 255, 25000, 50000, 75000, 90000, 95000, 99000,
259 };
260
261 memset(s, 0, sizeof(*s));
262
263 s->application_version = 1;
264 s->num_windows = 1;
265 s->targeted_system_display_maximum_luminance =
266 (AVRational){ 400, LUMINANCE_DEN };
267 s->targeted_system_display_actual_peak_luminance_flag = 0;
268 s->mastering_display_actual_peak_luminance_flag = 0;
269
270 s->params[0].maxscl[0] = (AVRational){ 50000, RGB_DEN };
271 s->params[0].maxscl[1] = (AVRational){ 60000, RGB_DEN };
272 s->params[0].maxscl[2] = (AVRational){ 99000, RGB_DEN };
273 s->params[0].average_maxrgb = (AVRational){ 40000, RGB_DEN };
274
275 s->params[0].num_distribution_maxrgb_percentiles = 9;
276 for (int i = 0; i < 9; i++) {
277 s->params[0].distribution_maxrgb[i].percentage = percentages[i];
278 s->params[0].distribution_maxrgb[i].percentile =
279 (AVRational){ percentiles[i], RGB_DEN };
280 }
281 s->params[0].fraction_bright_pixels =
283
284 s->params[0].tone_mapping_flag = 1;
285 s->params[0].knee_point_x = (AVRational){ 512, KNEE_POINT_DEN };
286 s->params[0].knee_point_y = (AVRational){ 1024, KNEE_POINT_DEN };
287 s->params[0].num_bezier_curve_anchors = 9;
288 for (int i = 0; i < 9; i++)
289 s->params[0].bezier_curve_anchors[i] =
290 (AVRational){ 100 * (i + 1), BEZIER_ANCHOR_DEN };
291
292 s->params[0].color_saturation_mapping_flag = 0;
293}
294
295/* Deliberately NOT a conforming Version 1 payload: it combines a second
296 * processing window, both actual-peak-luminance matrices and
297 * ColorSaturationWeight, all of which §9.4 excludes for Version 1. It exists
298 * only to drive the optional serializer/parser branches those fields guard. */
300{
301 memset(s, 0, sizeof(*s));
302
303 s->application_version = 1;
304 s->num_windows = 2;
305 s->targeted_system_display_maximum_luminance =
306 (AVRational){ 10000, LUMINANCE_DEN };
307
308 s->params[1].window_upper_left_corner_x = (AVRational){ 100, 1 };
309 s->params[1].window_upper_left_corner_y = (AVRational){ 120, 1 };
310 s->params[1].window_lower_right_corner_x = (AVRational){ 500, 1 };
311 s->params[1].window_lower_right_corner_y = (AVRational){ 520, 1 };
312 s->params[1].center_of_ellipse_x = 300;
313 s->params[1].center_of_ellipse_y = 320;
314 s->params[1].rotation_angle = 45;
315 s->params[1].semimajor_axis_internal_ellipse = 50;
316 s->params[1].semimajor_axis_external_ellipse = 100;
317 s->params[1].semiminor_axis_external_ellipse = 80;
318 s->params[1].overlap_process_option = 1;
319
320 s->params[0].maxscl[0] = (AVRational){ 50000, RGB_DEN };
321 s->params[0].maxscl[1] = (AVRational){ 60000, RGB_DEN };
322 s->params[0].maxscl[2] = (AVRational){ 70000, RGB_DEN };
323 s->params[0].average_maxrgb = (AVRational){ 40000, RGB_DEN };
324 s->params[0].num_distribution_maxrgb_percentiles = 2;
325 s->params[0].distribution_maxrgb[0].percentage = 50;
326 s->params[0].distribution_maxrgb[0].percentile =
327 (AVRational){ 30000, RGB_DEN };
328 s->params[0].distribution_maxrgb[1].percentage = 99;
329 s->params[0].distribution_maxrgb[1].percentile =
330 (AVRational){ 90000, RGB_DEN };
331 s->params[0].fraction_bright_pixels =
333
334 s->params[1].maxscl[0] = (AVRational){ 20000, RGB_DEN };
335 s->params[1].maxscl[1] = (AVRational){ 30000, RGB_DEN };
336 s->params[1].maxscl[2] = (AVRational){ 40000, RGB_DEN };
337 s->params[1].average_maxrgb = (AVRational){ 25000, RGB_DEN };
338 s->params[1].num_distribution_maxrgb_percentiles = 1;
339 s->params[1].distribution_maxrgb[0].percentage = 25;
340 s->params[1].distribution_maxrgb[0].percentile =
341 (AVRational){ 12500, RGB_DEN };
342 s->params[1].fraction_bright_pixels =
344
345 s->targeted_system_display_actual_peak_luminance_flag = 1;
346 s->num_rows_targeted_system_display_actual_peak_luminance = 2;
347 s->num_cols_targeted_system_display_actual_peak_luminance = 3;
348 for (int i = 0; i < 2; i++)
349 for (int j = 0; j < 3; j++)
350 s->targeted_system_display_actual_peak_luminance[i][j] =
351 (AVRational){ i * 3 + j, PEAK_LUMINANCE_DEN };
352
353 s->mastering_display_actual_peak_luminance_flag = 1;
354 s->num_rows_mastering_display_actual_peak_luminance = 3;
355 s->num_cols_mastering_display_actual_peak_luminance = 2;
356 for (int i = 0; i < 3; i++)
357 for (int j = 0; j < 2; j++)
358 s->mastering_display_actual_peak_luminance[i][j] =
359 (AVRational){ 15 - (i * 2 + j), PEAK_LUMINANCE_DEN };
360
361 s->params[0].tone_mapping_flag = 1;
362 s->params[0].knee_point_x = (AVRational){ 500, KNEE_POINT_DEN };
363 s->params[0].knee_point_y = (AVRational){ 800, KNEE_POINT_DEN };
364 s->params[0].num_bezier_curve_anchors = 3;
365 s->params[0].bezier_curve_anchors[0] = (AVRational){ 100, BEZIER_ANCHOR_DEN };
366 s->params[0].bezier_curve_anchors[1] = (AVRational){ 500, BEZIER_ANCHOR_DEN };
367 s->params[0].bezier_curve_anchors[2] = (AVRational){ 900, BEZIER_ANCHOR_DEN };
368 s->params[1].tone_mapping_flag = 0;
369
370 for (int w = 0; w < 2; w++) {
371 s->params[w].color_saturation_mapping_flag = 1;
372 s->params[w].color_saturation_weight =
373 (AVRational){ 8 + w, SATURATION_DEN };
374 }
375}
376
377static void test_hdr_plus(void)
378{
379 AVDynamicHDRPlus *hdr, *hdr_rt;
380 AVFrame *frame;
381 size_t size = 0, required = 0;
382 uint8_t *buf = NULL;
383 int ret;
384
385 printf("=== AVDynamicHDRPlus ===\n");
386
387 printf("Testing av_dynamic_hdr_plus_alloc()\n");
389 printf("alloc: %s size>0=%s\n", hdr ? "OK" : "FAIL",
390 size > 0 ? "yes" : "no");
391 av_freep(&hdr);
392
394 printf("alloc (no size): %s\n", hdr ? "OK" : "FAIL");
395 av_freep(&hdr);
396
397 printf("\nTesting av_dynamic_hdr_plus_create_side_data()\n");
399 if (frame) {
401 printf("create_side_data: %s\n", hdr ? "OK" : "FAIL");
403 }
404
407 if (!hdr || !hdr_rt) {
408 av_freep(&hdr);
409 av_freep(&hdr_rt);
410 return;
411 }
413
414 /* Size-query mode: data=NULL, size receives the required byte count. */
415 printf("\nTesting av_dynamic_hdr_plus_to_t35() size query\n");
416 required = 0;
417 ret = av_dynamic_hdr_plus_to_t35(hdr, NULL, &required);
418 printf("size query: ret=%d required>0=%s\n", ret,
419 required > 0 ? "yes" : "no");
420
421 /* Allocation mode: *data=NULL, the function allocates the buffer. */
422 printf("\nTesting av_dynamic_hdr_plus_to_t35() allocation\n");
423 buf = NULL;
424 size = 0;
425 ret = av_dynamic_hdr_plus_to_t35(hdr, &buf, &size);
426 printf("alloc mode: ret=%d size_match=%s\n", ret,
427 size == required ? "yes" : "no");
428 av_freep(&buf);
429
430 /* Existing-buffer mode: a caller-owned buffer is filled in place. */
431 printf("\nTesting av_dynamic_hdr_plus_to_t35() existing buffer\n");
432 buf = av_malloc(required);
433 if (buf) {
434 uint8_t *orig = buf;
435 size = required;
436 ret = av_dynamic_hdr_plus_to_t35(hdr, &buf, &size);
437 printf("existing buf: ret=%d same_pointer=%s size_match=%s\n", ret,
438 buf == orig ? "yes" : "no",
439 size == required ? "yes" : "no");
440 av_freep(&buf);
441 }
442
443 /* Buffer-too-small: caller-owned buffer shorter than required. */
444 printf("\nTesting av_dynamic_hdr_plus_to_t35() buffer too small\n");
445 if (required > 1) {
446 buf = av_malloc(required - 1);
447 if (buf) {
448 size = required - 1;
449 ret = av_dynamic_hdr_plus_to_t35(hdr, &buf, &size);
450 printf("too small: ret==AVERROR_BUFFER_TOO_SMALL=%s\n",
451 ret == AVERROR_BUFFER_TOO_SMALL ? "yes" : "no");
452 av_freep(&buf);
453 }
454 }
455
456 printf("\nTesting round trip, conforming ST 2094-40 Version 1 payload\n");
457 ret = hdr_plus_round_trip(hdr, hdr_rt);
458 printf("round trip: ret=%d\n", ret);
459 if (ret >= 0)
460 print_hdr_plus("decoded", hdr_rt);
461
462 /* to_t35() ignores application_version and always writes the CTA-861-H
463 * value, so the parsed field does not echo an out-of-range input. */
464 printf("\nTesting that to_t35() overrides application_version\n");
465 hdr->application_version = 7;
466 ret = hdr_plus_round_trip(hdr, hdr_rt);
467 printf("input=7 ret=%d decoded application_version=%u\n", ret,
468 hdr_rt->application_version);
469 hdr->application_version = 1;
470
471 printf("\nTesting round trip, synthetic payload (branch coverage only)\n");
473 ret = hdr_plus_round_trip(hdr, hdr_rt);
474 printf("round trip: ret=%d\n", ret);
475 if (ret >= 0)
476 print_hdr_plus("decoded", hdr_rt);
477
478 printf("\nTesting error paths\n");
479 buf = NULL;
480 size = 0;
481 ret = av_dynamic_hdr_plus_to_t35(NULL, &buf, &size);
482 printf("to_t35 NULL s: ret==AVERROR(EINVAL)=%s\n",
483 ret == AVERROR(EINVAL) ? "yes" : "no");
484
486 printf("to_t35 no data no size: ret==AVERROR(EINVAL)=%s\n",
487 ret == AVERROR(EINVAL) ? "yes" : "no");
488
489 ret = av_dynamic_hdr_plus_from_t35(NULL, (const uint8_t *)"", 0);
490 printf("from_t35 NULL s: ret==AVERROR(EINVAL)=%s\n",
491 ret == AVERROR(EINVAL) ? "yes" : "no");
492
493 {
494 /* Oversized input is rejected before parsing. */
495 size_t big = AV_HDR_PLUS_MAX_PAYLOAD_SIZE + 1;
496 uint8_t *oversized = av_mallocz(big);
497 if (oversized) {
498 ret = av_dynamic_hdr_plus_from_t35(hdr_rt, oversized, big);
499 printf("from_t35 oversized: ret==AVERROR(EINVAL)=%s\n",
500 ret == AVERROR(EINVAL) ? "yes" : "no");
501 av_free(oversized);
502 }
503 }
504
505 av_freep(&hdr);
506 av_freep(&hdr_rt);
507
508 printf("\nTesting OOM path\n");
509 av_max_alloc(1);
511 printf("alloc OOM: %s\n", hdr ? "FAIL" : "OK");
512 av_max_alloc(INT_MAX);
513 av_freep(&hdr);
514}
515
516/* Table C.2 early-out: no adaptive tone map, custom reference white only. */
518{
519 memset(s, 0, sizeof(*s));
520 s->application_version = 1;
521 s->minimum_application_version = 0;
522 s->has_custom_hdr_reference_white_flag = 1;
523 s->hdr_reference_white = 0x0203;
524 s->has_adaptive_tone_map_flag = 0;
525}
526
527/* Table C.3 early-out: reference-white tone mapping, no alternate images. */
529{
530 memset(s, 0, sizeof(*s));
531 s->application_version = 2;
532 s->has_adaptive_tone_map_flag = 1;
533 s->baseline_hdr_headroom = 0x0abc;
534 s->use_reference_white_tone_mapping_flag = 1;
535}
536
537/* Per-image parameters: explicit gain application space chromaticities,
538 * component mixing type 3 with a mix of present and absent coefficients, and
539 * explicit control point slopes (theta). */
541{
542 memset(s, 0, sizeof(*s));
543 s->application_version = 1;
544 s->has_adaptive_tone_map_flag = 1;
545 s->baseline_hdr_headroom = 0x0abc;
546 s->num_alternate_images = 2;
547 s->gain_application_space_chromaticities_flag = 3;
548 for (int r = 0; r < 8; r++)
549 s->gain_application_space_chromaticities[r] = 100 * (r + 1);
550 s->has_common_component_mix_params_flag = 0;
551 s->has_common_curve_params_flag = 0;
552 for (int a = 0; a < 2; a++) {
553 s->alternate_hdr_headrooms[a] = 0x0100 + a;
554 s->component_mixing_type[a] = 3;
555 for (int k = 0; k < 6; k++) {
556 s->has_component_mixing_coefficient_flag[a][k] = k & 1;
557 s->component_mixing_coefficient[a][k] = 0x1000 + 0x10 * a + k;
558 }
559 s->gain_curve_num_control_points_minus_1[a] = 1;
560 s->gain_curve_use_pchip_slope_flag[a] = 0;
561 for (int c = 0; c < 2; c++) {
562 s->gain_curve_control_points_x[a][c] = 0x2000 + 0x10 * a + c;
563 s->gain_curve_control_points_y[a][c] = 0x3000 + 0x10 * a + c;
564 s->gain_curve_control_points_theta[a][c] = 0x4000 + 0x10 * a + c;
565 }
566 }
567}
568
569/* The complementary selectors: no explicit chromaticities, a component mixing
570 * type other than 3, mixing and curve parameters shared from alternate 0, and
571 * the pchip slope, which omits theta from the payload.
572 *
573 * The common_* flags make the parser copy alternate 0's parameters to the
574 * other alternates, so the fixture sets them identically everywhere; only
575 * alternate_hdr_headrooms and the y control points stay per-image. */
577{
578 memset(s, 0, sizeof(*s));
579 s->application_version = 1;
580 s->has_adaptive_tone_map_flag = 1;
581 s->baseline_hdr_headroom = 0x0def;
582 s->num_alternate_images = 3;
583 s->gain_application_space_chromaticities_flag = 0;
584 s->has_common_component_mix_params_flag = 1;
585 s->has_common_curve_params_flag = 1;
586 for (int a = 0; a < 3; a++) {
587 s->alternate_hdr_headrooms[a] = 0x0200 + a;
588 s->component_mixing_type[a] = 1;
589 s->gain_curve_num_control_points_minus_1[a] = 2;
590 s->gain_curve_use_pchip_slope_flag[a] = 1;
591 for (int c = 0; c < 3; c++) {
592 s->gain_curve_control_points_x[a][c] = 0x5000 + c;
593 s->gain_curve_control_points_y[a][c] = 0x6000 + 0x10 * a + c;
594 }
595 }
596}
597
598static void test_app5(void)
599{
600 AVDynamicHDRSmpte2094App5 *app5, *app5_rt;
601 AVFrame *frame;
602 size_t size = 0, required = 0;
603 uint8_t *buf = NULL;
604 int ret;
605
606 printf("\n=== AVDynamicHDRSmpte2094App5 ===\n");
607 printf("Testing av_dynamic_hdr_smpte2094_app5_alloc()\n");
609 printf("alloc: %s size>0=%s\n", app5 ? "OK" : "FAIL",
610 size > 0 ? "yes" : "no");
611 av_freep(&app5);
612
613 printf("\nTesting av_dynamic_hdr_smpte2094_app5_create_side_data()\n");
615 if (frame) {
617 printf("create_side_data: %s\n", app5 ? "OK" : "FAIL");
619 }
620
623 if (!app5 || !app5_rt) {
624 av_freep(&app5);
625 av_freep(&app5_rt);
626 return;
627 }
628 fill_app5_minimal(app5);
629
630 printf("\nTesting av_dynamic_hdr_smpte2094_app5_to_t35()\n");
631 required = 0;
632 ret = av_dynamic_hdr_smpte2094_app5_to_t35(app5, NULL, &required);
633 printf("size query: ret=%d required>0=%s\n", ret,
634 required > 0 ? "yes" : "no");
635
636 buf = NULL;
637 size = 0;
638 ret = av_dynamic_hdr_smpte2094_app5_to_t35(app5, &buf, &size);
639 printf("alloc mode: ret=%d size_match=%s\n", ret,
640 size == required ? "yes" : "no");
641 av_freep(&buf);
642
643 printf("\nTesting round trip, no adaptive tone map\n");
644 ret = app5_round_trip(app5, app5_rt);
645 printf("round trip: ret=%d\n", ret);
646 if (ret >= 0)
647 print_app5("decoded", app5_rt);
648
649 printf("\nTesting round trip, reference-white tone mapping\n");
651 ret = app5_round_trip(app5, app5_rt);
652 printf("round trip: ret=%d\n", ret);
653 if (ret >= 0)
654 print_app5("decoded", app5_rt);
655
656 printf("\nTesting round trip, per-image mixing and curve parameters\n");
658 ret = app5_round_trip(app5, app5_rt);
659 printf("round trip: ret=%d\n", ret);
660 if (ret >= 0)
661 print_app5("decoded", app5_rt);
662
663 printf("\nTesting round trip, common mixing and curve parameters\n");
664 fill_app5_common(app5);
665 ret = app5_round_trip(app5, app5_rt);
666 printf("round trip: ret=%d\n", ret);
667 if (ret >= 0)
668 print_app5("decoded", app5_rt);
669
670 printf("\nTesting error paths\n");
671 buf = NULL;
672 size = 0;
674 printf("to_t35 NULL s: ret==AVERROR(EINVAL)=%s\n",
675 ret == AVERROR(EINVAL) ? "yes" : "no");
676
677 ret = av_dynamic_hdr_smpte2094_app5_from_t35(NULL, (const uint8_t *)"", 0);
678 printf("from_t35 NULL s: ret==AVERROR(EINVAL)=%s\n",
679 ret == AVERROR(EINVAL) ? "yes" : "no");
680
681 /* application_version does not fit the 3-bit field. */
682 app5->application_version = 8;
684 printf("to_t35 invalid application_version: ret==AVERROR_INVALIDDATA=%s\n",
685 ret == AVERROR_INVALIDDATA ? "yes" : "no");
686 app5->application_version = 1;
687
688 /* minimum_application_version above the documented maximum. */
691 printf("to_t35 invalid minimum_application_version:"
692 " ret==AVERROR_INVALIDDATA=%s\n",
693 ret == AVERROR_INVALIDDATA ? "yes" : "no");
695
696 /* More alternate images than the 3-bit count admits. */
697 app5->num_alternate_images = 5;
699 printf("to_t35 too many alternate images: ret==AVERROR_INVALIDDATA=%s\n",
700 ret == AVERROR_INVALIDDATA ? "yes" : "no");
701
702 av_freep(&app5);
703 av_freep(&app5_rt);
704
705 printf("\nTesting OOM path\n");
706 av_max_alloc(1);
708 printf("alloc OOM: %s\n", app5 ? "FAIL" : "OK");
709 av_max_alloc(INT_MAX);
710 av_freep(&app5);
711}
712
713int main(void)
714{
716 test_app5();
717 return 0;
718}
static FILE * out
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
__device__ int printf(const char *,...)
static AVFrame * frame
error code definitions
const char * label
Definition ffplay.c:1187
reference-counted frame API
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition error.h:53
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
void av_max_alloc(size_t max)
Set the maximum size that may be allocated in one block.
Definition mem.c:171
int a
AVDynamicHDRPlus * av_dynamic_hdr_plus_alloc(size_t *size)
Allocate an AVDynamicHDRPlus structure and set its fields to default values.
AVDynamicHDRPlus * av_dynamic_hdr_plus_create_side_data(AVFrame *frame)
Allocate a complete AVDynamicHDRPlus and add it to the frame.
AVDynamicHDRSmpte2094App5 * av_dynamic_hdr_smpte2094_app5_alloc(size_t *size)
Allocate an AVDynamicHDRSmpte2094App5 structure and set its fields to default values.
int av_dynamic_hdr_smpte2094_app5_to_t35(const AVDynamicHDRSmpte2094App5 *s, uint8_t **data, size_t *size)
Serialize dynamic SMPTE-2094-50 metadata to a ITU-T T.35 message.
int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, size_t size)
Parse the user data registered ITU-T T.35 to AVbuffer (AVDynamicHDRPlus).
int av_dynamic_hdr_plus_to_t35(const AVDynamicHDRPlus *s, uint8_t **data, size_t *size)
Serialize dynamic HDR10+ metadata to a user data registered ITU-T T.35 buffer, excluding the first 48...
int av_dynamic_hdr_smpte2094_app5_from_t35(AVDynamicHDRSmpte2094App5 *s, const uint8_t *data, size_t size)
Parse the user data formatted as ITU-T T.35 message to AVDynamicHDRSmpte2094App5.
AVDynamicHDRSmpte2094App5 * av_dynamic_hdr_smpte2094_app5_create_side_data(AVFrame *frame)
Allocate a complete AVDynamicHDRSmpte2094App5 and add it to the frame.
#define AV_HDR_PLUS_MAX_PAYLOAD_SIZE
#define r
Definition input.c:42
uint8_t w
Definition llvidencdsp.c:39
Memory handling functions.
#define av_malloc(s)
Definition ops_static.c:52
Utilities for rational number calculation.
This struct represents dynamic metadata for color volume transform - application 4 of SMPTE 2094-40:2...
uint8_t application_version
Application version in the application defining document in ST-2094 suite.
This struct represents dynamic metadata for color volume transform as specified in the SMPTE 2094-50 ...
uint8_t application_version
Section C.2.1.
This structure describes decoded (raw) audio or video data.
Definition frame.h:479
Color transform parameters at a processing window in a dynamic metadata for SMPTE 2094-40.
Rational number (pair of numerator and denominator).
Definition rational.h:58
#define av_free(p)
#define av_mallocz(s)
#define av_freep(p)
int num
Definition error.c:23
#define PEAK_LUMINANCE_DEN
#define KNEE_POINT_DEN
static void fill_hdr_plus_conforming(AVDynamicHDRPlus *s)
static void test_hdr_plus(void)
static int hdr_plus_round_trip(const AVDynamicHDRPlus *in, AVDynamicHDRPlus *out)
static void print_peak_matrix(const char *label, int rows, int cols, const AVRational m[25][25])
#define LUMINANCE_DEN
static void print_app5(const char *label, const AVDynamicHDRSmpte2094App5 *s)
static void test_app5(void)
#define FRACTION_PIXEL_DEN
static void fill_app5_reference_white(AVDynamicHDRSmpte2094App5 *s)
static void fill_app5_per_image(AVDynamicHDRSmpte2094App5 *s)
int main(void)
static int app5_round_trip(const AVDynamicHDRSmpte2094App5 *in, AVDynamicHDRSmpte2094App5 *out)
#define SATURATION_DEN
static void fill_app5_common(AVDynamicHDRSmpte2094App5 *s)
#define BEZIER_ANCHOR_DEN
static void print_hdr_plus(const char *label, const AVDynamicHDRPlus *s)
#define RGB_DEN
static void fill_app5_minimal(AVDynamicHDRSmpte2094App5 *s)
static void fill_hdr_plus_synthetic(AVDynamicHDRPlus *s)
static void print_window(int w, const AVHDRPlusColorTransformParams *p, int geometry)
int size
static double c[64]