Coverage Report

Created: 2026-05-16 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gstreamer/subprojects/gst-plugins-base/gst-libs/gst/video/video-hdr.c
Line
Count
Source
1
/* GStreamer
2
 * Copyright (C) <2018-2019> Seungha Yang <seungha.yang@navercorp.com>
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Library General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2 of the License, or (at your option) any later version.
8
 *
9
 * This library 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
 * Library General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Library General Public
15
 * License along with this library; if not, write to the
16
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17
 * Boston, MA 02110-1301, USA.
18
 */
19
20
#ifdef HAVE_CONFIG_H
21
#  include "config.h"
22
#endif
23
24
#include <string.h>
25
#include <gst/base/gstbitreader.h>
26
27
#include <gst/video/video.h>
28
29
#include "video-hdr.h"
30
31
0
#define HDR10_PLUS_MAX_BEZIER_CURVE_ANCHORS 9
32
0
#define HDR10_PLUS_NUM_DISTRIBUTIONS 9
33
static const guint8 HDR10_PLUS_DISTRIBUTION_INDEX[] = {
34
  1, 5, 10, 25, 50, 75, 90, 95, 99
35
};
36
37
38
0
#define N_ELEMENT_MASTERING_DISPLAY_INFO 10
39
#define MASTERING_FORMAT \
40
0
  "%d:%d:" \
41
0
  "%d:%d:" \
42
0
  "%d:%d:" \
43
0
  "%d:%d:" \
44
0
  "%d:%d"
45
46
#define MASTERING_PRINTF_ARGS(m) \
47
0
  (m)->display_primaries[0].x, (m)->display_primaries[0].y, \
48
0
  (m)->display_primaries[1].x, (m)->display_primaries[1].y, \
49
0
  (m)->display_primaries[2].x, (m)->display_primaries[2].y, \
50
0
  (m)->white_point.x, (m)->white_point.y, \
51
0
  (m)->max_display_mastering_luminance, \
52
0
  (m)->min_display_mastering_luminance
53
54
/**
55
 * gst_video_hdr_format_to_string:
56
 * @format: a #GstVideoHDRFormat
57
 *
58
 * Returns: (nullable): a string containing a descriptive name for
59
 * the #GstVideoHDRFormat if there is one, or %NULL otherwise.
60
 *
61
 * Since: 1.30
62
 */
63
const gchar *
64
gst_video_hdr_format_to_string (GstVideoHDRFormat format)
65
0
{
66
0
  switch (format) {
67
0
    case GST_VIDEO_HDR_FORMAT_HDR10:
68
0
      return "hdr10";
69
0
    case GST_VIDEO_HDR_FORMAT_HDR10_PLUS:
70
0
      return "hdr10+";
71
0
    default:
72
0
      return NULL;
73
0
  }
74
0
}
75
76
/**
77
 * gst_video_hdr_format_from_string:
78
 * @format: (nullable): a #GstVideoHDRFormat
79
 *
80
 * Returns: the #GstVideoHDRFormat for @format or GST_VIDEO_HDR_FORMAT_NONE when the
81
 * string is not a known format.
82
 *
83
 * Since: 1.30
84
 */
85
GstVideoHDRFormat
86
gst_video_hdr_format_from_string (const gchar * format)
87
0
{
88
0
  if (!g_strcmp0 (format, "hdr10"))
89
0
    return GST_VIDEO_HDR_FORMAT_HDR10;
90
0
  else if (!g_strcmp0 (format, "hdr10+"))
91
0
    return GST_VIDEO_HDR_FORMAT_HDR10_PLUS;
92
93
0
  return GST_VIDEO_HDR_FORMAT_NONE;
94
0
}
95
96
/**
97
 * gst_video_mastering_display_info_init:
98
 * @minfo: a #GstVideoMasteringDisplayInfo
99
 *
100
 * Initialize @minfo
101
 *
102
 * Since: 1.18
103
 */
104
void
105
gst_video_mastering_display_info_init (GstVideoMasteringDisplayInfo * minfo)
106
0
{
107
0
  g_return_if_fail (minfo != NULL);
108
109
0
  memset (minfo, 0, sizeof (GstVideoMasteringDisplayInfo));
110
0
}
111
112
/**
113
 * gst_video_mastering_display_info_from_string:
114
 * @minfo: (out): a #GstVideoMasteringDisplayInfo
115
 * @mastering: a #GstStructure representing #GstVideoMasteringDisplayInfo
116
 *
117
 * Extract #GstVideoMasteringDisplayInfo from @mastering
118
 *
119
 * Returns: %TRUE if @minfo was filled with @mastering
120
 *
121
 * Since: 1.18
122
 */
123
gboolean
124
gst_video_mastering_display_info_from_string (GstVideoMasteringDisplayInfo *
125
    minfo, const gchar * mastering)
126
0
{
127
0
  gboolean ret = FALSE;
128
0
  gchar **split;
129
0
  gint i;
130
0
  gint idx = 0;
131
0
  guint64 val;
132
133
0
  g_return_val_if_fail (minfo != NULL, FALSE);
134
0
  g_return_val_if_fail (mastering != NULL, FALSE);
135
136
0
  split = g_strsplit (mastering, ":", -1);
137
138
0
  if (g_strv_length (split) != N_ELEMENT_MASTERING_DISPLAY_INFO)
139
0
    goto out;
140
141
0
  for (i = 0; i < G_N_ELEMENTS (minfo->display_primaries); i++) {
142
0
    if (!g_ascii_string_to_unsigned (split[idx++],
143
0
            10, 0, G_MAXUINT16, &val, NULL))
144
0
      goto out;
145
146
0
    minfo->display_primaries[i].x = (guint16) val;
147
148
0
    if (!g_ascii_string_to_unsigned (split[idx++],
149
0
            10, 0, G_MAXUINT16, &val, NULL))
150
0
      goto out;
151
152
0
    minfo->display_primaries[i].y = (guint16) val;
153
0
  }
154
155
0
  if (!g_ascii_string_to_unsigned (split[idx++],
156
0
          10, 0, G_MAXUINT16, &val, NULL))
157
0
    goto out;
158
159
0
  minfo->white_point.x = (guint16) val;
160
161
0
  if (!g_ascii_string_to_unsigned (split[idx++],
162
0
          10, 0, G_MAXUINT16, &val, NULL))
163
0
    goto out;
164
165
0
  minfo->white_point.y = (guint16) val;
166
167
0
  if (!g_ascii_string_to_unsigned (split[idx++],
168
0
          10, 0, G_MAXUINT32, &val, NULL))
169
0
    goto out;
170
171
0
  minfo->max_display_mastering_luminance = (guint32) val;
172
173
0
  if (!g_ascii_string_to_unsigned (split[idx++],
174
0
          10, 0, G_MAXUINT32, &val, NULL))
175
0
    goto out;
176
177
0
  minfo->min_display_mastering_luminance = (guint32) val;
178
0
  ret = TRUE;
179
180
0
out:
181
0
  g_strfreev (split);
182
0
  if (!ret)
183
0
    gst_video_mastering_display_info_init (minfo);
184
185
0
  return ret;
186
0
}
187
188
/**
189
 * gst_video_mastering_display_info_to_string:
190
 * @minfo: a #GstVideoMasteringDisplayInfo
191
 *
192
 * Convert @minfo to its string representation
193
 *
194
 * Returns: (transfer full): a string representation of @minfo
195
 *
196
 * Since: 1.18
197
 */
198
gchar *
199
gst_video_mastering_display_info_to_string (const GstVideoMasteringDisplayInfo *
200
    minfo)
201
0
{
202
0
  g_return_val_if_fail (minfo != NULL, NULL);
203
204
0
  return g_strdup_printf (MASTERING_FORMAT, MASTERING_PRINTF_ARGS (minfo));
205
0
}
206
207
/**
208
 * gst_video_mastering_display_info_is_equal:
209
 * @minfo: a #GstVideoMasteringDisplayInfo
210
 * @other: a #GstVideoMasteringDisplayInfo
211
 *
212
 * Checks equality between @minfo and @other.
213
 *
214
 * Returns: %TRUE if @minfo and @other are equal.
215
 *
216
 * Since: 1.18
217
 */
218
gboolean
219
gst_video_mastering_display_info_is_equal (const GstVideoMasteringDisplayInfo *
220
    minfo, const GstVideoMasteringDisplayInfo * other)
221
0
{
222
0
  gint i;
223
224
0
  g_return_val_if_fail (minfo != NULL, FALSE);
225
0
  g_return_val_if_fail (other != NULL, FALSE);
226
227
0
  for (i = 0; i < G_N_ELEMENTS (minfo->display_primaries); i++) {
228
0
    if (minfo->display_primaries[i].x != other->display_primaries[i].x ||
229
0
        minfo->display_primaries[i].y != other->display_primaries[i].y)
230
0
      return FALSE;
231
0
  }
232
233
0
  if (minfo->white_point.x != other->white_point.x ||
234
0
      minfo->white_point.y != other->white_point.y ||
235
0
      minfo->max_display_mastering_luminance !=
236
0
      other->max_display_mastering_luminance
237
0
      || minfo->min_display_mastering_luminance !=
238
0
      other->min_display_mastering_luminance)
239
0
    return FALSE;
240
241
0
  return TRUE;
242
0
}
243
244
/**
245
 * gst_video_mastering_display_info_from_caps:
246
 * @minfo: a #GstVideoMasteringDisplayInfo
247
 * @caps: a #GstCaps
248
 *
249
 * Parse @caps and update @minfo
250
 *
251
 * Returns: %TRUE if @caps has #GstVideoMasteringDisplayInfo and could be parsed
252
 *
253
 * Since: 1.18
254
 */
255
gboolean
256
gst_video_mastering_display_info_from_caps (GstVideoMasteringDisplayInfo *
257
    minfo, const GstCaps * caps)
258
0
{
259
0
  GstStructure *structure;
260
0
  const gchar *s;
261
262
0
  g_return_val_if_fail (minfo != NULL, FALSE);
263
0
  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
264
265
0
  structure = gst_caps_get_structure (caps, 0);
266
267
0
  if ((s = gst_structure_get_string (structure,
268
0
              "mastering-display-info")) == NULL)
269
0
    return FALSE;
270
271
0
  return gst_video_mastering_display_info_from_string (minfo, s);
272
0
}
273
274
/**
275
 * gst_video_mastering_display_info_add_to_caps:
276
 * @minfo: a #GstVideoMasteringDisplayInfo
277
 * @caps: a #GstCaps
278
 *
279
 * Set string representation of @minfo to @caps
280
 *
281
 * Returns: %TRUE if @minfo was successfully set to @caps
282
 *
283
 * Since: 1.18
284
 */
285
gboolean
286
gst_video_mastering_display_info_add_to_caps (const GstVideoMasteringDisplayInfo
287
    * minfo, GstCaps * caps)
288
0
{
289
0
  gchar *s;
290
291
0
  g_return_val_if_fail (minfo != NULL, FALSE);
292
0
  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
293
0
  g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
294
295
0
  s = gst_video_mastering_display_info_to_string (minfo);
296
0
  if (!s)
297
0
    return FALSE;
298
299
0
  gst_caps_set_simple (caps, "mastering-display-info", G_TYPE_STRING, s, NULL);
300
0
  g_free (s);
301
302
0
  return TRUE;
303
0
}
304
305
/**
306
 * gst_video_content_light_level_init:
307
 * @linfo: a #GstVideoContentLightLevel
308
 *
309
 * Initialize @linfo
310
 *
311
 * Since: 1.18
312
 */
313
void
314
gst_video_content_light_level_init (GstVideoContentLightLevel * linfo)
315
0
{
316
0
  g_return_if_fail (linfo != NULL);
317
318
0
  memset (linfo, 0, sizeof (GstVideoContentLightLevel));
319
0
}
320
321
/**
322
 * gst_video_content_light_level_from_string:
323
 * @linfo: a #GstVideoContentLightLevel
324
 * @level: a content-light-level string from caps
325
 *
326
 * Parse the value of content-light-level caps field and update @minfo
327
 * with the parsed values.
328
 *
329
 * Returns: %TRUE if @linfo points to valid #GstVideoContentLightLevel.
330
 *
331
 * Since: 1.18
332
 */
333
gboolean
334
gst_video_content_light_level_from_string (GstVideoContentLightLevel * linfo,
335
    const gchar * level)
336
0
{
337
0
  gboolean ret = FALSE;
338
0
  gchar **split;
339
0
  guint64 val;
340
341
0
  g_return_val_if_fail (linfo != NULL, FALSE);
342
0
  g_return_val_if_fail (level != NULL, FALSE);
343
344
0
  split = g_strsplit (level, ":", -1);
345
346
0
  if (g_strv_length (split) != 2)
347
0
    goto out;
348
349
0
  if (!g_ascii_string_to_unsigned (split[0], 10, 0, G_MAXUINT16, &val, NULL))
350
0
    goto out;
351
352
0
  linfo->max_content_light_level = (guint16) val;
353
354
0
  if (!g_ascii_string_to_unsigned (split[1], 10, 0, G_MAXUINT16, &val, NULL))
355
0
    goto out;
356
357
0
  linfo->max_frame_average_light_level = (guint16) val;
358
359
0
  ret = TRUE;
360
361
0
out:
362
0
  g_strfreev (split);
363
0
  if (!ret)
364
0
    gst_video_content_light_level_init (linfo);
365
366
0
  return ret;
367
0
}
368
369
/**
370
 * gst_video_content_light_level_to_string:
371
 * @linfo: a #GstVideoContentLightLevel
372
 *
373
 * Convert @linfo to its string representation.
374
 *
375
 * Returns: (transfer full): a string representation of @linfo.
376
 *
377
 * Since: 1.18
378
 */
379
gchar *
380
gst_video_content_light_level_to_string (const GstVideoContentLightLevel *
381
    linfo)
382
0
{
383
0
  g_return_val_if_fail (linfo != NULL, NULL);
384
385
0
  return g_strdup_printf ("%d:%d",
386
0
      linfo->max_content_light_level, linfo->max_frame_average_light_level);
387
0
}
388
389
/**
390
 * gst_video_content_light_level_is_equal:
391
 * @linfo: a #GstVideoContentLightLevel
392
 * @other: a #GstVideoContentLightLevel
393
 *
394
 * Checks equality between @linfo and @other.
395
 *
396
 * Returns: %TRUE if @linfo and @other are equal.
397
 *
398
 * Since: 1.20
399
 */
400
gboolean
401
gst_video_content_light_level_is_equal (const GstVideoContentLightLevel * linfo,
402
    const GstVideoContentLightLevel * other)
403
0
{
404
0
  g_return_val_if_fail (linfo != NULL, FALSE);
405
0
  g_return_val_if_fail (other != NULL, FALSE);
406
407
0
  return (linfo->max_content_light_level == other->max_content_light_level &&
408
0
      linfo->max_frame_average_light_level ==
409
0
      other->max_frame_average_light_level);
410
0
}
411
412
/**
413
 * gst_video_content_light_level_from_caps:
414
 * @linfo: a #GstVideoContentLightLevel
415
 * @caps: a #GstCaps
416
 *
417
 * Parse @caps and update @linfo
418
 *
419
 * Returns: if @caps has #GstVideoContentLightLevel and could be parsed
420
 *
421
 * Since: 1.18
422
 */
423
gboolean
424
gst_video_content_light_level_from_caps (GstVideoContentLightLevel * linfo,
425
    const GstCaps * caps)
426
0
{
427
0
  GstStructure *structure;
428
0
  const gchar *s;
429
430
0
  g_return_val_if_fail (linfo != NULL, FALSE);
431
0
  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
432
433
0
  structure = gst_caps_get_structure (caps, 0);
434
435
0
  if ((s = gst_structure_get_string (structure, "content-light-level")) == NULL)
436
0
    return FALSE;
437
438
0
  return gst_video_content_light_level_from_string (linfo, s);
439
0
}
440
441
/**
442
 * gst_video_content_light_level_add_to_caps:
443
 * @linfo: a #GstVideoContentLightLevel
444
 * @caps: a #GstCaps
445
 *
446
 * Parse @caps and update @linfo
447
 *
448
 * Returns: %TRUE if @linfo was successfully set to @caps
449
 *
450
 * Since: 1.18
451
 */
452
gboolean
453
gst_video_content_light_level_add_to_caps (const GstVideoContentLightLevel *
454
    linfo, GstCaps * caps)
455
0
{
456
0
  gchar *s;
457
458
0
  g_return_val_if_fail (linfo != NULL, FALSE);
459
0
  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
460
0
  g_return_val_if_fail (gst_caps_is_writable (caps), FALSE);
461
462
0
  s = gst_video_content_light_level_to_string (linfo);
463
0
  gst_caps_set_simple (caps, "content-light-level", G_TYPE_STRING, s, NULL);
464
0
  g_free (s);
465
466
0
  return TRUE;
467
0
}
468
469
/* Dynamic HDR Meta implementation */
470
471
GType
472
gst_video_hdr_meta_api_get_type (void)
473
0
{
474
0
  static GType type = 0;
475
476
0
  if (g_once_init_enter (&type)) {
477
0
    static const gchar *tags[] = {
478
0
      GST_META_TAG_VIDEO_STR,
479
0
      NULL
480
0
    };
481
0
    GType _type = gst_meta_api_type_register ("GstVideoHDRMetaAPI", tags);
482
0
    g_once_init_leave (&type, _type);
483
0
  }
484
0
  return type;
485
0
}
486
487
static gboolean
488
gst_video_hdr_meta_transform (GstBuffer * dest, GstMeta * meta,
489
    GstBuffer * buffer, GQuark type, gpointer data)
490
0
{
491
0
  GstVideoHDRMeta *dmeta, *smeta;
492
493
  /* We always copy over the HDR meta */
494
0
  smeta = (GstVideoHDRMeta *) meta;
495
496
0
  GST_DEBUG ("copy HDR metadata");
497
0
  dmeta =
498
0
      gst_buffer_add_video_hdr_meta (dest, smeta->format, smeta->data,
499
0
      smeta->size);
500
0
  if (!dmeta)
501
0
    return FALSE;
502
503
0
  return TRUE;
504
0
}
505
506
static gboolean
507
gst_video_hdr_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
508
0
{
509
0
  GstVideoHDRMeta *emeta = (GstVideoHDRMeta *) meta;
510
511
0
  emeta->data = NULL;
512
513
0
  return TRUE;
514
0
}
515
516
static void
517
gst_video_hdr_meta_free (GstMeta * meta, GstBuffer * buffer)
518
0
{
519
0
  GstVideoHDRMeta *emeta = (GstVideoHDRMeta *) meta;
520
521
0
  g_free (emeta->data);
522
0
}
523
524
const GstMetaInfo *
525
gst_video_hdr_meta_get_info (void)
526
0
{
527
0
  static const GstMetaInfo *meta_info = NULL;
528
529
0
  if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
530
0
    const GstMetaInfo *mi = gst_meta_register (GST_VIDEO_HDR_META_API_TYPE,
531
0
        "GstVideoHDRMeta",
532
0
        sizeof (GstVideoHDRMeta),
533
0
        gst_video_hdr_meta_init,
534
0
        gst_video_hdr_meta_free,
535
0
        gst_video_hdr_meta_transform);
536
0
    g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) mi);
537
0
  }
538
0
  return meta_info;
539
0
}
540
541
/**
542
 * gst_buffer_add_video_hdr_meta:
543
 * @buffer: a #GstBuffer
544
 * @format: The type of dynamic HDR contained in the meta.
545
 * @data: contains the dynamic HDR data
546
 * @size: The size in bytes of @data
547
 *
548
 * Attaches #GstVideoHDRMeta metadata to @buffer with the given
549
 * parameters.
550
 *
551
 * Returns: (transfer none): the #GstVideoHDRMeta on @buffer.
552
 *
553
 * Since: 1.30
554
 */
555
GstVideoHDRMeta *
556
gst_buffer_add_video_hdr_meta (GstBuffer * buffer,
557
    GstVideoHDRFormat format, const guint8 * data, gsize size)
558
0
{
559
0
  GstVideoHDRMeta *meta;
560
561
0
  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
562
0
  g_return_val_if_fail (data != NULL, NULL);
563
564
0
  meta = (GstVideoHDRMeta *) gst_buffer_add_meta (buffer,
565
0
      GST_VIDEO_HDR_META_INFO, NULL);
566
0
  g_assert (meta != NULL);
567
568
0
  meta->format = format;
569
0
  meta->data = g_memdup2 (data, size);
570
0
  meta->size = size;
571
572
0
  return meta;
573
0
}
574
575
0
#define CHECK_HDR10PLUS_REMAINING(br, needed) \
576
0
if (gst_bit_reader_get_remaining (&br) < needed) { \
577
0
  GST_DEBUG ("Not enough bits remaining %d, needed %d", gst_bit_reader_get_remaining (&br), needed); \
578
0
  return FALSE; \
579
0
}
580
581
/**
582
 * gst_video_hdr_parse_hdr10_plus:
583
 * @data: HDR10+ data
584
 * @size: size of data
585
 * @hdr10_plus: (out): #GstVideoHDR10Plus structure to fill in.
586
 *
587
 * Parse HDR10+ (SMPTE2094-40) user data and store in @hdr10_plus
588
 * For more details, see:
589
 * https://www.atsc.org/wp-content/uploads/2018/02/S34-301r2-A341-Amendment-2094-40-1.pdf
590
 * and SMPTE ST2094-40
591
 *
592
 * Returns: %TRUE if @data was successfully parsed to @hdr10_plus
593
 *
594
 * Since: 1.30
595
 */
596
gboolean
597
gst_video_hdr_parse_hdr10_plus (const guint8 * data, gsize size,
598
    GstVideoHDR10Plus * hdr10_plus)
599
0
{
600
0
  guint16 provider_oriented_code;
601
0
  int w, i, j;
602
0
  GstBitReader br;
603
604
  /* there must be at least one byte, and not more than GST_VIDEO_HDR10_PLUS_MAX_BYTES bytes */
605
0
  g_return_val_if_fail (data != NULL, FALSE);
606
607
0
  memset (hdr10_plus, 0, sizeof (GstVideoHDR10Plus));
608
0
  gst_bit_reader_init (&br, data, size);
609
0
  GST_MEMDUMP ("HDR10+", data, size);
610
0
  CHECK_HDR10PLUS_REMAINING (br, 16 + 8 + 8 + 2);
611
0
  provider_oriented_code = gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
612
0
  if (provider_oriented_code != 0x0001)
613
0
    return FALSE;
614
615
616
0
  hdr10_plus->application_identifier =
617
0
      gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
618
0
  hdr10_plus->application_version =
619
0
      gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
620
0
  hdr10_plus->num_windows = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
621
0
  if (hdr10_plus->application_version == 1 &&
622
0
      hdr10_plus->num_windows != GST_VIDEO_HDR10_PLUS_NUM_WINDOWS)
623
0
    return FALSE;
624
0
  if (hdr10_plus->application_version == 0) {
625
0
    for (w = 0; w < hdr10_plus->num_windows; w++) {
626
0
      CHECK_HDR10PLUS_REMAINING (br,
627
0
          16 + 16 + 16 + 16 + 16 + 16 + 8 + 16 + 16 + 16 + 1);
628
0
      hdr10_plus->processing_window[w].window_upper_left_corner_x =
629
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
630
0
      hdr10_plus->processing_window[w].window_upper_left_corner_y =
631
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
632
0
      hdr10_plus->processing_window[w].window_lower_right_corner_x =
633
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
634
0
      hdr10_plus->processing_window[w].window_lower_right_corner_y =
635
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
636
0
      hdr10_plus->processing_window[w].center_of_ellipse_x =
637
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
638
0
      hdr10_plus->processing_window[w].center_of_ellipse_y =
639
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
640
0
      hdr10_plus->processing_window[w].rotation_angle =
641
0
          gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
642
0
      hdr10_plus->processing_window[w].semimajor_axis_internal_ellipse =
643
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
644
0
      hdr10_plus->processing_window[w].semimajor_axis_external_ellipse =
645
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
646
0
      hdr10_plus->processing_window[w].semiminor_axis_external_ellipse =
647
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 16);
648
0
      hdr10_plus->processing_window[w].overlap_process_option =
649
0
          gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
650
0
    }
651
0
  }
652
0
  CHECK_HDR10PLUS_REMAINING (br, 27 + 1);
653
0
  hdr10_plus->targeted_system_display_maximum_luminance =
654
0
      gst_bit_reader_get_bits_uint32_unchecked (&br, 27);
655
0
  hdr10_plus->targeted_system_display_actual_peak_luminance_flag =
656
0
      gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
657
0
  if (hdr10_plus->targeted_system_display_actual_peak_luminance_flag) {
658
0
    if (hdr10_plus->application_version == 1)
659
0
      return FALSE;
660
0
    CHECK_HDR10PLUS_REMAINING (br, 5 + 5);
661
0
    hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance =
662
0
        gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
663
0
    hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance =
664
0
        gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
665
0
    if (hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance >
666
0
        GST_VIDEO_HDR10_PLUS_MAX_ROWS_TSD_APL)
667
0
      return FALSE;
668
0
    if (hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance >
669
0
        GST_VIDEO_HDR10_PLUS_MAX_COLS_MD_APL)
670
0
      return FALSE;
671
0
    CHECK_HDR10PLUS_REMAINING (br,
672
0
        hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance *
673
0
        hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance * 4);
674
0
    for (i = 0;
675
0
        i < hdr10_plus->num_rows_targeted_system_display_actual_peak_luminance;
676
0
        i++) {
677
0
      for (j = 0;
678
0
          j <
679
0
          hdr10_plus->num_cols_targeted_system_display_actual_peak_luminance;
680
0
          j++)
681
0
        hdr10_plus->targeted_system_display_actual_peak_luminance[i][j] =
682
0
            gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
683
0
    }
684
0
  }
685
0
  for (w = 0; w < hdr10_plus->num_windows; w++) {
686
0
    CHECK_HDR10PLUS_REMAINING (br, (17 * 3));
687
0
    for (i = 0; i < 3; i++)
688
0
      hdr10_plus->processing_window[w].maxscl[i] =
689
0
          gst_bit_reader_get_bits_uint32_unchecked (&br, 17);
690
0
    CHECK_HDR10PLUS_REMAINING (br, 17 + 4);
691
0
    hdr10_plus->processing_window[w].average_maxrgb =
692
0
        gst_bit_reader_get_bits_uint32_unchecked (&br, 17);
693
0
    hdr10_plus->processing_window[w].num_distributions =
694
0
        gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
695
0
    if (hdr10_plus->processing_window[w].num_distributions !=
696
0
        HDR10_PLUS_NUM_DISTRIBUTIONS)
697
0
      return FALSE;
698
0
    CHECK_HDR10PLUS_REMAINING (br,
699
0
        hdr10_plus->processing_window[w].num_distributions * (17 + 7));
700
0
    for (i = 0; i < hdr10_plus->processing_window[w].num_distributions; i++) {
701
0
      hdr10_plus->processing_window[w].distribution_index[i] =
702
0
          gst_bit_reader_get_bits_uint8_unchecked (&br, 7);
703
0
      if (hdr10_plus->processing_window[w].distribution_index[i] !=
704
0
          HDR10_PLUS_DISTRIBUTION_INDEX[i])
705
0
        return FALSE;
706
0
      hdr10_plus->processing_window[w].distribution_values[i] =
707
0
          gst_bit_reader_get_bits_uint32_unchecked (&br, 17);
708
0
    }
709
0
    CHECK_HDR10PLUS_REMAINING (br, 10);
710
0
    hdr10_plus->processing_window[w].fraction_bright_pixels =
711
0
        gst_bit_reader_get_bits_uint16_unchecked (&br, 10);
712
0
    if (hdr10_plus->application_version == 1 &&
713
0
        hdr10_plus->processing_window[w].fraction_bright_pixels != 0)
714
0
      return FALSE;
715
0
  }
716
0
  CHECK_HDR10PLUS_REMAINING (br, 1);
717
0
  hdr10_plus->mastering_display_actual_peak_luminance_flag =
718
0
      gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
719
0
  if (hdr10_plus->mastering_display_actual_peak_luminance_flag) {
720
0
    if (hdr10_plus->application_version == 1)
721
0
      return FALSE;
722
0
    CHECK_HDR10PLUS_REMAINING (br, 5 + 5);
723
0
    hdr10_plus->num_rows_mastering_display_actual_peak_luminance =
724
0
        gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
725
0
    hdr10_plus->num_cols_mastering_display_actual_peak_luminance =
726
0
        gst_bit_reader_get_bits_uint8_unchecked (&br, 5);
727
0
    if (hdr10_plus->num_rows_mastering_display_actual_peak_luminance >
728
0
        GST_VIDEO_HDR10_PLUS_MAX_ROWS_TSD_APL)
729
0
      return FALSE;
730
0
    if (hdr10_plus->num_cols_mastering_display_actual_peak_luminance >
731
0
        GST_VIDEO_HDR10_PLUS_MAX_COLS_MD_APL)
732
0
      return FALSE;
733
0
    CHECK_HDR10PLUS_REMAINING (br,
734
0
        hdr10_plus->num_rows_mastering_display_actual_peak_luminance *
735
0
        hdr10_plus->num_cols_mastering_display_actual_peak_luminance * 4);
736
0
    for (i = 0;
737
0
        i < hdr10_plus->num_rows_mastering_display_actual_peak_luminance; i++) {
738
0
      for (j = 0;
739
0
          j < hdr10_plus->num_cols_mastering_display_actual_peak_luminance; j++)
740
0
        hdr10_plus->mastering_display_actual_peak_luminance[i][j] =
741
0
            gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
742
0
    }
743
0
  }
744
0
  for (w = 0; w < hdr10_plus->num_windows; w++) {
745
0
    CHECK_HDR10PLUS_REMAINING (br, 1);
746
0
    hdr10_plus->processing_window[w].tone_mapping_flag =
747
0
        gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
748
0
    if (hdr10_plus->processing_window[w].tone_mapping_flag) {
749
0
      CHECK_HDR10PLUS_REMAINING (br, 12 + 12 + 4);
750
0
      hdr10_plus->processing_window[w].knee_point_x =
751
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 12);
752
0
      hdr10_plus->processing_window[w].knee_point_y =
753
0
          gst_bit_reader_get_bits_uint16_unchecked (&br, 12);
754
0
      hdr10_plus->processing_window[w].num_bezier_curve_anchors =
755
0
          gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
756
0
      if (hdr10_plus->processing_window[w].num_bezier_curve_anchors >
757
0
          HDR10_PLUS_MAX_BEZIER_CURVE_ANCHORS)
758
0
        return FALSE;
759
0
      CHECK_HDR10PLUS_REMAINING (br,
760
0
          10 * hdr10_plus->processing_window[w].num_bezier_curve_anchors);
761
0
      for (i = 0;
762
0
          i < hdr10_plus->processing_window[w].num_bezier_curve_anchors; i++)
763
0
        hdr10_plus->processing_window[w].bezier_curve_anchors[i] =
764
0
            gst_bit_reader_get_bits_uint16_unchecked (&br, 10);
765
0
    }
766
0
    CHECK_HDR10PLUS_REMAINING (br, 1);
767
0
    hdr10_plus->processing_window[w].color_saturation_mapping_flag =
768
0
        gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
769
0
    if (hdr10_plus->processing_window[w].color_saturation_mapping_flag) {
770
0
      if (hdr10_plus->application_version == 1)
771
0
        return FALSE;
772
0
      CHECK_HDR10PLUS_REMAINING (br, 6);
773
0
      hdr10_plus->processing_window[w].color_saturation_weight =
774
0
          gst_bit_reader_get_bits_uint8_unchecked (&br, 6);
775
0
    }
776
0
  }
777
0
  return TRUE;
778
0
}