FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/cbs_sei.c
Date: 2026-04-29 17:33:30
Exec Total Coverage
Lines: 77 209 36.8%
Functions: 8 12 66.7%
Branches: 35 120 29.2%

Line Branch Exec Source
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 "libavutil/mem.h"
20 #include "cbs.h"
21 #include "cbs_internal.h"
22 #include "cbs_h264.h"
23 #include "cbs_h265.h"
24 #include "cbs_h266.h"
25 #include "cbs_sei.h"
26 #include "libavutil/refstruct.h"
27
28 #define HEADER(name) do { \
29 ff_cbs_trace_header(ctx, name); \
30 } while (0)
31
32 #define CHECK(call) do { \
33 err = (call); \
34 if (err < 0) \
35 return err; \
36 } while (0)
37
38 #define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name
39 #define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name)
40 #define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## name
41 #define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name)
42 #define FUNC_SEI(name) FUNC_NAME1(READWRITE, sei, name)
43 #define FUNC_SEI_EXPORT(name) FUNC_NAME1_EXPORT(READWRITE, sei, name)
44
45 #define SEI_FUNC(name, args) \
46 static int FUNC_SEI(name) args; \
47 static int FUNC_SEI(name ## _internal)(CodedBitstreamContext *ctx, \
48 RWContext *rw, void *cur, \
49 SEIMessageState *state) \
50 { \
51 return FUNC_SEI(name)(ctx, rw, cur, state); \
52 } \
53 static int FUNC_SEI(name) args
54
55 #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
56
57 #define u(width, name, range_min, range_max) \
58 xu(width, name, current->name, range_min, range_max, 0, )
59 #define flag(name) ub(1, name)
60 #define ue(name, range_min, range_max) \
61 xue(name, current->name, range_min, range_max, 0, )
62 #define i(width, name, range_min, range_max) \
63 xi(width, name, current->name, range_min, range_max, 0, )
64 #define ib(width, name) \
65 xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, )
66 #define se(name, range_min, range_max) \
67 xse(name, current->name, range_min, range_max, 0, )
68
69 #define us(width, name, range_min, range_max, subs, ...) \
70 xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
71 #define ubs(width, name, subs, ...) \
72 xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__)
73 #define flags(name, subs, ...) \
74 xu(1, name, current->name, 0, 1, subs, __VA_ARGS__)
75 #define ues(name, range_min, range_max, subs, ...) \
76 xue(name, current->name, range_min, range_max, subs, __VA_ARGS__)
77 #define is(width, name, range_min, range_max, subs, ...) \
78 xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
79 #define ibs(width, name, subs, ...) \
80 xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__)
81 #define ses(name, range_min, range_max, subs, ...) \
82 xse(name, current->name, range_min, range_max, subs, __VA_ARGS__)
83
84 #define fixed(width, name, value) do { \
85 av_unused uint32_t fixed_value = value; \
86 xu(width, name, fixed_value, value, value, 0, ); \
87 } while (0)
88
89
90 #define READ
91 #define READWRITE read
92 #define RWContext GetBitContext
93
94 #define ub(width, name) do { \
95 uint32_t value; \
96 CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \
97 &value)); \
98 current->name = value; \
99 } while (0)
100 #define xu(width, name, var, range_min, range_max, subs, ...) do { \
101 uint32_t value; \
102 CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
103 SUBSCRIPTS(subs, __VA_ARGS__), \
104 &value, range_min, range_max)); \
105 var = value; \
106 } while (0)
107 #define xue(name, var, range_min, range_max, subs, ...) do { \
108 uint32_t value; \
109 CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \
110 SUBSCRIPTS(subs, __VA_ARGS__), \
111 &value, range_min, range_max)); \
112 var = value; \
113 } while (0)
114 #define xi(width, name, var, range_min, range_max, subs, ...) do { \
115 int32_t value; \
116 CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \
117 SUBSCRIPTS(subs, __VA_ARGS__), \
118 &value, range_min, range_max)); \
119 var = value; \
120 } while (0)
121 #define xse(name, var, range_min, range_max, subs, ...) do { \
122 int32_t value; \
123 CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \
124 SUBSCRIPTS(subs, __VA_ARGS__), \
125 &value, range_min, range_max)); \
126 var = value; \
127 } while (0)
128
129
130 #define infer(name, value) do { \
131 current->name = value; \
132 } while (0)
133
134 #define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw))
135
136 #define bit_position(rw) (get_bits_count(rw))
137 #define byte_alignment(rw) (get_bits_count(rw) % 8)
138
139 /* The CBS SEI code uses the refstruct API for the allocation
140 * of its child buffers. */
141 #define allocate(name, size) do { \
142 name = av_refstruct_allocz(size + \
143 AV_INPUT_BUFFER_PADDING_SIZE); \
144 if (!name) \
145 return AVERROR(ENOMEM); \
146 } while (0)
147
148 #define FUNC(name) FUNC_SEI_EXPORT(name)
149 #include "cbs_sei_syntax_template.c"
150 #undef FUNC
151
152 #undef READ
153 #undef READWRITE
154 #undef RWContext
155 #undef ub
156 #undef xu
157 #undef xi
158 #undef xue
159 #undef xse
160 #undef infer
161 #undef more_rbsp_data
162 #undef bit_position
163 #undef byte_alignment
164 #undef allocate
165
166
167 #define WRITE
168 #define READWRITE write
169 #define RWContext PutBitContext
170
171 #define ub(width, name) do { \
172 uint32_t value = current->name; \
173 CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \
174 value)); \
175 } while (0)
176 #define xu(width, name, var, range_min, range_max, subs, ...) do { \
177 uint32_t value = var; \
178 CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
179 SUBSCRIPTS(subs, __VA_ARGS__), \
180 value, range_min, range_max)); \
181 } while (0)
182 #define xue(name, var, range_min, range_max, subs, ...) do { \
183 uint32_t value = var; \
184 CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \
185 SUBSCRIPTS(subs, __VA_ARGS__), \
186 value, range_min, range_max)); \
187 } while (0)
188 #define xi(width, name, var, range_min, range_max, subs, ...) do { \
189 int32_t value = var; \
190 CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \
191 SUBSCRIPTS(subs, __VA_ARGS__), \
192 value, range_min, range_max)); \
193 } while (0)
194 #define xse(name, var, range_min, range_max, subs, ...) do { \
195 int32_t value = var; \
196 CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \
197 SUBSCRIPTS(subs, __VA_ARGS__), \
198 value, range_min, range_max)); \
199 } while (0)
200
201 #define infer(name, value) do { \
202 if (current->name != (value)) { \
203 av_log(ctx->log_ctx, AV_LOG_ERROR, \
204 "%s does not match inferred value: " \
205 "%"PRId64", but should be %"PRId64".\n", \
206 #name, (int64_t)current->name, (int64_t)(value)); \
207 return AVERROR_INVALIDDATA; \
208 } \
209 } while (0)
210
211 #define more_rbsp_data(var) (var)
212
213 #define bit_position(rw) (put_bits_count(rw))
214 #define byte_alignment(rw) (put_bits_count(rw) % 8)
215
216 #define allocate(name, size) do { \
217 if (!name) { \
218 av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \
219 "for writing.\n", #name); \
220 return AVERROR_INVALIDDATA; \
221 } \
222 } while (0)
223
224 #define FUNC(name) FUNC_SEI_EXPORT(name)
225 #include "cbs_sei_syntax_template.c"
226 #undef FUNC
227
228 57 static void cbs_free_user_data_registered(AVRefStructOpaque unused, void *obj)
229 {
230 57 SEIRawUserDataRegistered *udr = obj;
231 57 av_refstruct_unref(&udr->data_ref);
232 57 }
233
234 22 static void cbs_free_user_data_unregistered(AVRefStructOpaque unused, void *obj)
235 {
236 22 SEIRawUserDataUnregistered *udu = obj;
237 22 av_refstruct_unref(&udu->data_ref);
238 22 }
239
240 5979 int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
241 const SEIMessageTypeDescriptor *desc)
242 {
243 void (*free_func)(AVRefStructOpaque, void*);
244
245
2/4
✓ Branch 0 taken 5979 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5979 times.
5979 av_assert0(message->payload == NULL &&
246 message->payload_ref == NULL);
247 5979 message->payload_type = desc->type;
248
249
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 5922 times.
5979 if (desc->type == SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35)
250 57 free_func = &cbs_free_user_data_registered;
251
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 5900 times.
5922 else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
252 22 free_func = &cbs_free_user_data_unregistered;
253 else {
254 5900 free_func = NULL;
255 }
256
257 5979 message->payload_ref = av_refstruct_alloc_ext(desc->size, 0,
258 NULL, free_func);
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5979 times.
5979 if (!message->payload_ref)
260 return AVERROR(ENOMEM);
261 5979 message->payload = message->payload_ref;
262
263 5979 return 0;
264 }
265
266 6114 int ff_cbs_sei_list_add(SEIRawMessageList *list)
267 {
268 void *ptr;
269 6114 int old_count = list->nb_messages_allocated;
270
271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6114 times.
6114 av_assert0(list->nb_messages <= old_count);
272
2/2
✓ Branch 0 taken 6105 times.
✓ Branch 1 taken 9 times.
6114 if (list->nb_messages + 1 > old_count) {
273 6105 int new_count = 2 * old_count + 1;
274
275 6105 ptr = av_realloc_array(list->messages,
276 new_count, sizeof(*list->messages));
277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6105 times.
6105 if (!ptr)
278 return AVERROR(ENOMEM);
279
280 6105 list->messages = ptr;
281 6105 list->nb_messages_allocated = new_count;
282
283 // Zero the newly-added entries.
284 6105 memset(list->messages + old_count, 0,
285 6105 (new_count - old_count) * sizeof(*list->messages));
286 }
287 6114 ++list->nb_messages;
288 6114 return 0;
289 }
290
291 6094 void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
292 {
293
2/2
✓ Branch 0 taken 6114 times.
✓ Branch 1 taken 6094 times.
12208 for (int i = 0; i < list->nb_messages; i++) {
294 6114 SEIRawMessage *message = &list->messages[i];
295 6114 av_refstruct_unref(&message->payload_ref);
296 6114 av_refstruct_unref(&message->extension_data);
297 }
298 6094 av_free(list->messages);
299 6094 }
300
301 static int cbs_sei_get_unit(CodedBitstreamContext *ctx,
302 CodedBitstreamFragment *au,
303 int prefix,
304 CodedBitstreamUnit **sei_unit)
305 {
306 CodedBitstreamUnit *unit;
307 int sei_type, highest_vcl_type, err, i, position;
308
309 switch (ctx->codec->codec_id) {
310 case AV_CODEC_ID_H264:
311 // (We can ignore auxiliary slices because we only have prefix
312 // SEI in H.264 and an auxiliary picture must always follow a
313 // primary picture.)
314 highest_vcl_type = H264_NAL_IDR_SLICE;
315 if (prefix)
316 sei_type = H264_NAL_SEI;
317 else
318 return AVERROR(EINVAL);
319 break;
320 case AV_CODEC_ID_H265:
321 highest_vcl_type = HEVC_NAL_RSV_VCL31;
322 if (prefix)
323 sei_type = HEVC_NAL_SEI_PREFIX;
324 else
325 sei_type = HEVC_NAL_SEI_SUFFIX;
326 break;
327 case AV_CODEC_ID_H266:
328 highest_vcl_type = VVC_RSV_IRAP_11;
329 if (prefix)
330 sei_type = VVC_PREFIX_SEI_NUT;
331 else
332 sei_type = VVC_SUFFIX_SEI_NUT;
333 break;
334 default:
335 return AVERROR(EINVAL);
336 }
337
338 // Find an existing SEI NAL unit of the right type.
339 unit = NULL;
340 for (i = 0; i < au->nb_units; i++) {
341 if (au->units[i].type == sei_type) {
342 unit = &au->units[i];
343 break;
344 }
345 }
346
347 if (unit) {
348 *sei_unit = unit;
349 return 0;
350 }
351
352 // Need to add a new SEI NAL unit ...
353 if (prefix) {
354 // ... before the first VCL NAL unit.
355 for (i = 0; i < au->nb_units; i++) {
356 if (au->units[i].type < highest_vcl_type)
357 break;
358 }
359 position = i;
360 } else {
361 // ... after the last VCL NAL unit.
362 for (i = au->nb_units - 1; i >= 0; i--) {
363 if (au->units[i].type < highest_vcl_type)
364 break;
365 }
366 if (i < 0) {
367 // No VCL units; just put it at the end.
368 position = au->nb_units;
369 } else {
370 position = i + 1;
371 }
372 }
373
374 err = ff_cbs_insert_unit_content(au, position, sei_type,
375 NULL, NULL);
376 if (err < 0)
377 return err;
378 unit = &au->units[position];
379 unit->type = sei_type;
380
381 err = ff_cbs_alloc_unit_content(ctx, unit);
382 if (err < 0)
383 return err;
384
385 switch (ctx->codec->codec_id) {
386 case AV_CODEC_ID_H264:
387 {
388 H264RawSEI sei = {
389 .nal_unit_header = {
390 .nal_ref_idc = 0,
391 .nal_unit_type = sei_type,
392 },
393 };
394 memcpy(unit->content, &sei, sizeof(sei));
395 }
396 break;
397 case AV_CODEC_ID_H265:
398 {
399 H265RawSEI sei = {
400 .nal_unit_header = {
401 .nal_unit_type = sei_type,
402 .nuh_layer_id = 0,
403 .nuh_temporal_id_plus1 = 1,
404 },
405 };
406 memcpy(unit->content, &sei, sizeof(sei));
407 }
408 break;
409 case AV_CODEC_ID_H266:
410 {
411 H266RawSEI sei = {
412 .nal_unit_header = {
413 .nal_unit_type = sei_type,
414 .nuh_layer_id = 0,
415 .nuh_temporal_id_plus1 = 1,
416 },
417 };
418 memcpy(unit->content, &sei, sizeof(sei));
419 }
420 break;
421 default:
422 av_assert0(0);
423 }
424
425 *sei_unit = unit;
426 return 0;
427 }
428
429 104 static int cbs_sei_get_message_list(CodedBitstreamContext *ctx,
430 CodedBitstreamUnit *unit,
431 SEIRawMessageList **list)
432 {
433
1/4
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
104 switch (ctx->codec->codec_id) {
434 104 case AV_CODEC_ID_H264:
435 {
436 104 H264RawSEI *sei = unit->content;
437
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 61 times.
104 if (unit->type != H264_NAL_SEI)
438 43 return AVERROR(EINVAL);
439 61 *list = &sei->message_list;
440 }
441 61 break;
442 case AV_CODEC_ID_H265:
443 {
444 H265RawSEI *sei = unit->content;
445 if (unit->type != HEVC_NAL_SEI_PREFIX &&
446 unit->type != HEVC_NAL_SEI_SUFFIX)
447 return AVERROR(EINVAL);
448 *list = &sei->message_list;
449 }
450 break;
451 case AV_CODEC_ID_H266:
452 {
453 H266RawSEI *sei = unit->content;
454 if (unit->type != VVC_PREFIX_SEI_NUT &&
455 unit->type != VVC_SUFFIX_SEI_NUT)
456 return AVERROR(EINVAL);
457 *list = &sei->message_list;
458 }
459 break;
460 default:
461 return AVERROR(EINVAL);
462 }
463
464 61 return 0;
465 }
466
467 int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
468 CodedBitstreamFragment *au,
469 int prefix,
470 uint32_t payload_type,
471 void *payload_data,
472 void *payload_ref)
473 {
474 const SEIMessageTypeDescriptor *desc;
475 CodedBitstreamUnit *unit;
476 SEIRawMessageList *list;
477 SEIRawMessage *message;
478 int err;
479
480 desc = ff_cbs_sei_find_type(ctx, payload_type);
481 if (!desc)
482 return AVERROR(EINVAL);
483
484 // Find an existing SEI unit or make a new one to add to.
485 err = cbs_sei_get_unit(ctx, au, prefix, &unit);
486 if (err < 0)
487 return err;
488
489 // Find the message list inside the codec-dependent unit.
490 err = cbs_sei_get_message_list(ctx, unit, &list);
491 if (err < 0)
492 return err;
493
494 // Add a new message to the message list.
495 err = ff_cbs_sei_list_add(list);
496 if (err < 0)
497 return err;
498
499 if (payload_ref) {
500 /* The following just increments payload_ref's refcount,
501 * so that payload_ref is now owned by us. */
502 payload_ref = av_refstruct_ref(payload_ref);
503 }
504
505 message = &list->messages[list->nb_messages - 1];
506
507 message->payload_type = payload_type;
508 message->payload = payload_data;
509 message->payload_ref = payload_ref;
510
511 return 0;
512 }
513
514 int ff_cbs_sei_find_message(CodedBitstreamContext *ctx,
515 CodedBitstreamFragment *au,
516 uint32_t payload_type,
517 SEIRawMessage **iter)
518 {
519 int err, i, j, found;
520
521 found = 0;
522 for (i = 0; i < au->nb_units; i++) {
523 CodedBitstreamUnit *unit = &au->units[i];
524 SEIRawMessageList *list;
525
526 err = cbs_sei_get_message_list(ctx, unit, &list);
527 if (err < 0)
528 continue;
529
530 for (j = 0; j < list->nb_messages; j++) {
531 SEIRawMessage *message = &list->messages[j];
532
533 if (message->payload_type == payload_type) {
534 if (!*iter || found) {
535 *iter = message;
536 return 0;
537 }
538 if (message == *iter)
539 found = 1;
540 }
541 }
542 }
543
544 return AVERROR(ENOENT);
545 }
546
547 static void cbs_sei_delete_message(SEIRawMessageList *list,
548 int position)
549 {
550 SEIRawMessage *message;
551
552 av_assert0(0 <= position && position < list->nb_messages);
553
554 message = &list->messages[position];
555 av_refstruct_unref(&message->payload_ref);
556 av_refstruct_unref(&message->extension_data);
557
558 --list->nb_messages;
559
560 if (list->nb_messages > 0) {
561 memmove(list->messages + position,
562 list->messages + position + 1,
563 (list->nb_messages - position) * sizeof(*list->messages));
564 }
565 }
566
567 40 void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx,
568 CodedBitstreamFragment *au,
569 uint32_t payload_type)
570 {
571 int err, i, j;
572
573
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 40 times.
144 for (i = 0; i < au->nb_units; i++) {
574 104 CodedBitstreamUnit *unit = &au->units[i];
575 SEIRawMessageList *list;
576
577 104 err = cbs_sei_get_message_list(ctx, unit, &list);
578
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 61 times.
104 if (err < 0)
579 43 continue;
580
581
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 61 times.
122 for (j = list->nb_messages - 1; j >= 0; j--) {
582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if (list->messages[j].payload_type == payload_type)
583 cbs_sei_delete_message(list, j);
584 }
585 }
586 40 }
587
588 // Macro for the read/write pair.
589 #define SEI_MESSAGE_RW(codec, name) \
590 .read = cbs_ ## codec ## _read_ ## name ## _internal, \
591 .write = cbs_ ## codec ## _write_ ## name ## _internal
592
593 static const SEIMessageTypeDescriptor cbs_sei_common_types[] = {
594 {
595 SEI_TYPE_FILLER_PAYLOAD,
596 1, 1,
597 sizeof(SEIRawFillerPayload),
598 SEI_MESSAGE_RW(sei, filler_payload),
599 },
600 {
601 SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35,
602 1, 1,
603 sizeof(SEIRawUserDataRegistered),
604 SEI_MESSAGE_RW(sei, user_data_registered),
605 },
606 {
607 SEI_TYPE_USER_DATA_UNREGISTERED,
608 1, 1,
609 sizeof(SEIRawUserDataUnregistered),
610 SEI_MESSAGE_RW(sei, user_data_unregistered),
611 },
612 {
613 SEI_TYPE_FRAME_PACKING_ARRANGEMENT,
614 1, 0,
615 sizeof(SEIRawFramePackingArrangement),
616 SEI_MESSAGE_RW(sei, frame_packing_arrangement),
617 },
618 {
619 SEI_TYPE_DECODED_PICTURE_HASH,
620 0, 1,
621 sizeof(SEIRawDecodedPictureHash),
622 SEI_MESSAGE_RW(sei, decoded_picture_hash),
623 },
624 {
625 SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME,
626 1, 0,
627 sizeof(SEIRawMasteringDisplayColourVolume),
628 SEI_MESSAGE_RW(sei, mastering_display_colour_volume),
629 },
630 {
631 SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO,
632 1, 0,
633 sizeof(SEIRawContentLightLevelInfo),
634 SEI_MESSAGE_RW(sei, content_light_level_info),
635 },
636 {
637 SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS,
638 1, 0,
639 sizeof(SEIRawAlternativeTransferCharacteristics),
640 SEI_MESSAGE_RW(sei, alternative_transfer_characteristics),
641 },
642 {
643 SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT,
644 1, 0,
645 sizeof(SEIRawAmbientViewingEnvironment),
646 SEI_MESSAGE_RW(sei, ambient_viewing_environment),
647 },
648 SEI_MESSAGE_TYPE_END,
649 };
650
651 static const SEIMessageTypeDescriptor cbs_sei_h274_types[] = {
652 {
653 SEI_TYPE_FILM_GRAIN_CHARACTERISTICS,
654 1, 0,
655 sizeof(SEIRawFilmGrainCharacteristics),
656 SEI_MESSAGE_RW(sei, film_grain_characteristics),
657 },
658 {
659 SEI_TYPE_DISPLAY_ORIENTATION,
660 1, 0,
661 sizeof(SEIRawDisplayOrientation),
662 SEI_MESSAGE_RW(sei, display_orientation)
663 },
664 {
665 SEI_TYPE_FRAME_FIELD_INFO,
666 1, 0,
667 sizeof(SEIRawFrameFieldInformation),
668 SEI_MESSAGE_RW(sei, frame_field_information)
669 },
670 SEI_MESSAGE_TYPE_END,
671 };
672
673 14672 const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx,
674 int payload_type)
675 {
676 14672 const SEIMessageTypeDescriptor *codec_list = NULL;
677 int i;
678
679
3/4
✓ Branch 0 taken 1989 times.
✓ Branch 1 taken 4981 times.
✓ Branch 2 taken 7702 times.
✗ Branch 3 not taken.
14672 switch (ctx->codec->codec_id) {
680 #if CBS_H264
681 1989 case AV_CODEC_ID_H264:
682 1989 codec_list = ff_cbs_sei_h264_types;
683 1989 break;
684 #endif
685 #if CBS_H265
686 4981 case AV_CODEC_ID_H265:
687 4981 codec_list = ff_cbs_sei_h265_types;
688 4981 break;
689 #endif
690 7702 case AV_CODEC_ID_H266:
691 7702 codec_list = cbs_sei_h274_types;
692 7702 break;
693 }
694
695
3/4
✓ Branch 0 taken 72655 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64816 times.
✓ Branch 3 taken 7839 times.
72655 for (i = 0; codec_list && codec_list[i].type >= 0; i++) {
696
2/2
✓ Branch 0 taken 6833 times.
✓ Branch 1 taken 57983 times.
64816 if (codec_list[i].type == payload_type)
697 6833 return &codec_list[i];
698 }
699
700
2/2
✓ Branch 0 taken 39821 times.
✓ Branch 1 taken 269 times.
40090 for (i = 0; cbs_sei_common_types[i].type >= 0; i++) {
701
2/2
✓ Branch 0 taken 7570 times.
✓ Branch 1 taken 32251 times.
39821 if (cbs_sei_common_types[i].type == payload_type)
702 7570 return &cbs_sei_common_types[i];
703 }
704
705 269 return NULL;
706 }
707