FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/cbs_lcevc.c
Date: 2026-05-03 08:24:11
Exec Total Coverage
Lines: 0 269 0.0%
Functions: 0 20 0.0%
Branches: 0 160 0.0%

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 "libavutil/refstruct.h"
21 #include "bytestream.h"
22 #include "cbs.h"
23 #include "cbs_internal.h"
24 #include "cbs_h2645.h"
25 #include "cbs_lcevc.h"
26 #include "cbs_sei.h"
27 #include "get_bits.h"
28
29 #define HEADER(name) do { \
30 ff_cbs_trace_header(ctx, name); \
31 } while (0)
32
33 #define CHECK(call) do { \
34 err = (call); \
35 if (err < 0) \
36 return err; \
37 } while (0)
38
39 #define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name
40 #define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name)
41 #define FUNC_LCEVC(name) FUNC_NAME1(READWRITE, lcevc, name)
42 #define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## name
43 #define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name)
44 #define FUNC_SEI(name) FUNC_NAME1_EXPORT(READWRITE, sei, name)
45
46 #define SEI_FUNC(name, args) \
47 static int FUNC_LCEVC(name) args; \
48 static int FUNC_LCEVC(name ## _internal)(CodedBitstreamContext *ctx, \
49 RWContext *rw, void *cur, \
50 SEIMessageState *state) \
51 { \
52 return FUNC_LCEVC(name)(ctx, rw, cur, state); \
53 } \
54 static int FUNC_LCEVC(name) args
55
56 #define LCEVC_BLOCK_FUNC(name, args) \
57 static int FUNC(name) args; \
58 static int FUNC(name ## _internal)(CodedBitstreamContext *ctx, \
59 RWContext *rw, void *cur, \
60 LCEVCProcessBlockState *state, \
61 int nal_unit_type) \
62 { \
63 return FUNC(name)(ctx, rw, cur, state, nal_unit_type); \
64 } \
65 static int FUNC(name) args
66
67 #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
68
69 #define u(width, name, range_min, range_max) \
70 xu(width, name, current->name, range_min, range_max, 0, )
71 #define flag(name) ub(1, name)
72 #define ue(name, range_min, range_max) \
73 xue(name, current->name, range_min, range_max, 0, )
74 #define i(width, name, range_min, range_max) \
75 xi(width, name, current->name, range_min, range_max, 0, )
76 #define ib(width, name) \
77 xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, )
78 #define se(name, range_min, range_max) \
79 xse(name, current->name, range_min, range_max, 0, )
80
81 #define us(width, name, range_min, range_max, subs, ...) \
82 xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
83 #define ubs(width, name, subs, ...) \
84 xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__)
85 #define flags(name, subs, ...) \
86 xu(1, name, current->name, 0, 1, subs, __VA_ARGS__)
87 #define ues(name, range_min, range_max, subs, ...) \
88 xue(name, current->name, range_min, range_max, subs, __VA_ARGS__)
89 #define is(width, name, range_min, range_max, subs, ...) \
90 xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
91 #define ibs(width, name, subs, ...) \
92 xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__)
93 #define ses(name, range_min, range_max, subs, ...) \
94 xse(name, current->name, range_min, range_max, subs, __VA_ARGS__)
95 #define mb(name) \
96 xmb(name, current->name)
97
98 #define fixed(width, name, value) do { \
99 av_unused uint32_t fixed_value = value; \
100 xu(width, name, fixed_value, value, value, 0, ); \
101 } while (0)
102
103
104 static int cbs_read_multi_byte(CodedBitstreamContext *ctx, GetBitContext *gbc,
105 const char *name, uint32_t *write_to)
106 {
107 uint64_t value;
108 uint32_t byte;
109 int i;
110
111 CBS_TRACE_READ_START();
112
113 value = 0;
114 for (i = 0; i < 10; i++) {
115 if (get_bits_left(gbc) < 8) {
116 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid multi byte at "
117 "%s: bitstream ended.\n", name);
118 return AVERROR_INVALIDDATA;
119 }
120 byte = get_bits(gbc, 8);
121 value = (value << 7) | (byte & 0x7f);
122 if (!(byte & 0x80))
123 break;
124 }
125
126 if (value > UINT32_MAX)
127 return AVERROR_INVALIDDATA;
128
129 CBS_TRACE_READ_END_NO_SUBSCRIPTS();
130
131 *write_to = value;
132 return 0;
133 }
134
135 #define READ
136 #define READWRITE read
137 #define RWContext GetBitContext
138
139 #define ub(width, name) do { \
140 uint32_t value; \
141 CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \
142 &value)); \
143 current->name = value; \
144 } while (0)
145 #define xu(width, name, var, range_min, range_max, subs, ...) do { \
146 uint32_t value; \
147 CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
148 SUBSCRIPTS(subs, __VA_ARGS__), \
149 &value, range_min, range_max)); \
150 var = value; \
151 } while (0)
152 #define xue(name, var, range_min, range_max, subs, ...) do { \
153 uint32_t value; \
154 CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \
155 SUBSCRIPTS(subs, __VA_ARGS__), \
156 &value, range_min, range_max)); \
157 var = value; \
158 } while (0)
159 #define xi(width, name, var, range_min, range_max, subs, ...) do { \
160 int32_t value; \
161 CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \
162 SUBSCRIPTS(subs, __VA_ARGS__), \
163 &value, range_min, range_max)); \
164 var = value; \
165 } while (0)
166 #define xse(name, var, range_min, range_max, subs, ...) do { \
167 int32_t value; \
168 CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \
169 SUBSCRIPTS(subs, __VA_ARGS__), \
170 &value, range_min, range_max)); \
171 var = value; \
172 } while (0)
173 #define xmb(name, var) do { \
174 uint32_t value; \
175 CHECK(cbs_read_multi_byte(ctx, rw, #name, &value)); \
176 var = value; \
177 } while (0)
178
179 #define infer(name, value) do { \
180 current->name = value; \
181 } while (0)
182
183 #define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw))
184
185 #define bit_position(rw) (get_bits_count(rw))
186 #define byte_alignment(rw) (get_bits_count(rw) % 8)
187
188 /* The CBS LCEVC code uses the refstruct API for the allocation
189 * of its child buffers. */
190 #define allocate(name, size) do { \
191 name = av_refstruct_allocz(size + \
192 AV_INPUT_BUFFER_PADDING_SIZE); \
193 if (!name) \
194 return AVERROR(ENOMEM); \
195 } while (0)
196
197 #define FUNC(name) FUNC_LCEVC(name)
198 #include "cbs_lcevc_syntax_template.c"
199 #undef FUNC
200
201
202 #undef READ
203 #undef READWRITE
204 #undef RWContext
205 #undef ub
206 #undef xu
207 #undef xi
208 #undef xue
209 #undef xse
210 #undef xmb
211 #undef infer
212 #undef more_rbsp_data
213 #undef bit_position
214 #undef byte_alignment
215 #undef allocate
216
217
218 static int cbs_write_multi_byte(CodedBitstreamContext *ctx, PutBitContext *pbc,
219 const char *name, uint32_t value)
220 {
221 int len, i;
222 uint8_t byte;
223
224 CBS_TRACE_WRITE_START();
225
226 len = (av_log2(value) + 7) / 7;
227
228 for (i = len - 1; i >= 0; i--) {
229 if (put_bits_left(pbc) < 8)
230 return AVERROR(ENOSPC);
231
232 byte = value >> (7 * i) & 0x7f;
233 if (i > 0)
234 byte |= 0x80;
235
236 put_bits(pbc, 8, byte);
237 }
238
239 CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
240
241 return 0;
242 }
243
244 #define WRITE
245 #define READWRITE write
246 #define RWContext PutBitContext
247
248 #define ub(width, name) do { \
249 uint32_t value = current->name; \
250 CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \
251 value)); \
252 } while (0)
253 #define xu(width, name, var, range_min, range_max, subs, ...) do { \
254 uint32_t value = var; \
255 CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
256 SUBSCRIPTS(subs, __VA_ARGS__), \
257 value, range_min, range_max)); \
258 } while (0)
259 #define xue(name, var, range_min, range_max, subs, ...) do { \
260 uint32_t value = var; \
261 CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \
262 SUBSCRIPTS(subs, __VA_ARGS__), \
263 value, range_min, range_max)); \
264 } while (0)
265 #define xi(width, name, var, range_min, range_max, subs, ...) do { \
266 int32_t value = var; \
267 CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \
268 SUBSCRIPTS(subs, __VA_ARGS__), \
269 value, range_min, range_max)); \
270 } while (0)
271 #define xse(name, var, range_min, range_max, subs, ...) do { \
272 int32_t value = var; \
273 CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \
274 SUBSCRIPTS(subs, __VA_ARGS__), \
275 value, range_min, range_max)); \
276 } while (0)
277 #define xmb(name, var) do { \
278 uint32_t value = var; \
279 CHECK(cbs_write_multi_byte(ctx, rw, #name, value)); \
280 } while (0)
281
282 #define infer(name, value) do { \
283 if (current->name != (value)) { \
284 av_log(ctx->log_ctx, AV_LOG_ERROR, \
285 "%s does not match inferred value: " \
286 "%"PRId64", but should be %"PRId64".\n", \
287 #name, (int64_t)current->name, (int64_t)(value)); \
288 return AVERROR_INVALIDDATA; \
289 } \
290 } while (0)
291
292 #define more_rbsp_data(var) (var)
293
294 #define bit_position(rw) (put_bits_count(rw))
295 #define byte_alignment(rw) (put_bits_count(rw) % 8)
296
297 #define allocate(name, size) do { \
298 if (!name) { \
299 av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \
300 "for writing.\n", #name); \
301 return AVERROR_INVALIDDATA; \
302 } \
303 } while (0)
304
305 #define FUNC(name) FUNC_LCEVC(name)
306 #include "cbs_lcevc_syntax_template.c"
307 #undef FUNC
308
309 #undef WRITE
310 #undef READWRITE
311 #undef RWContext
312 #undef ub
313 #undef xu
314 #undef xi
315 #undef xue
316 #undef xse
317 #undef xmb
318 #undef u
319 #undef i
320 #undef flag
321 #undef ue
322 #undef se
323 #undef infer
324 #undef more_rbsp_data
325 #undef bit_position
326 #undef byte_alignment
327 #undef allocate
328
329
330 static int cbs_lcevc_split_fragment(CodedBitstreamContext *ctx,
331 CodedBitstreamFragment *frag,
332 int header)
333 {
334 enum AVCodecID codec_id = ctx->codec->codec_id;
335 CodedBitstreamLCEVCContext *priv = ctx->priv_data;
336 CodedBitstreamH2645Context *h2645 = &priv->common;
337 GetByteContext gbc;
338 int err;
339
340 av_assert0(frag->data && frag->nb_units == 0);
341 if (frag->data_size == 0)
342 return 0;
343
344 if (header && frag->data[0]) {
345 // LVCC header.
346 size_t size, start, end;
347 int i, j, nb_arrays, nal_unit_type, nb_nals, version;
348
349 h2645->mp4 = 1;
350
351 bytestream2_init(&gbc, frag->data, frag->data_size);
352
353 if (bytestream2_get_bytes_left(&gbc) < 14)
354 return AVERROR_INVALIDDATA;
355
356 version = bytestream2_get_byte(&gbc);
357 if (version != 1) {
358 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid LVCC header: "
359 "first byte %u.\n", version);
360 return AVERROR_INVALIDDATA;
361 }
362
363 bytestream2_skip(&gbc, 3);
364 h2645->nal_length_size = (bytestream2_get_byte(&gbc) >> 6) + 1;
365
366 bytestream2_skip(&gbc, 9);
367 nb_arrays = bytestream2_get_byte(&gbc);
368
369 for (i = 0; i < nb_arrays; i++) {
370 nal_unit_type = bytestream2_get_byte(&gbc) & 0x3f;
371 nb_nals = bytestream2_get_be16(&gbc);
372
373 start = bytestream2_tell(&gbc);
374 for (j = 0; j < nb_nals; j++) {
375 if (bytestream2_get_bytes_left(&gbc) < 2)
376 return AVERROR_INVALIDDATA;
377 size = bytestream2_get_be16(&gbc);
378 if (bytestream2_get_bytes_left(&gbc) < size)
379 return AVERROR_INVALIDDATA;
380 bytestream2_skip(&gbc, size);
381 }
382 end = bytestream2_tell(&gbc);
383
384 err = ff_h2645_packet_split(&h2645->read_packet,
385 frag->data + start, end - start,
386 ctx->log_ctx, 2, AV_CODEC_ID_LCEVC,
387 H2645_FLAG_IS_NALFF | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF);
388 if (err < 0) {
389 av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split "
390 "LVCC array %d (%d NAL units of type %d).\n",
391 i, nb_nals, nal_unit_type);
392 return err;
393 }
394 err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet);
395 if (err < 0)
396 return err;
397 }
398 } else {
399 int flags = (H2645_FLAG_IS_NALFF * !!h2645->mp4) | H2645_FLAG_SMALL_PADDING | H2645_FLAG_USE_REF;
400 // Annex B, or later MP4 with already-known parameters.
401
402 err = ff_h2645_packet_split(&h2645->read_packet,
403 frag->data, frag->data_size,
404 ctx->log_ctx,
405 h2645->nal_length_size,
406 codec_id, flags);
407 if (err < 0)
408 return err;
409
410 err = ff_cbs_h2645_fragment_add_nals(ctx, frag, &h2645->read_packet);
411 if (err < 0)
412 return err;
413 }
414
415 return 0;
416 }
417
418 static int cbs_lcevc_read_nal_unit(CodedBitstreamContext *ctx,
419 CodedBitstreamUnit *unit)
420 {
421 GetBitContext gbc;
422 int err;
423
424 err = init_get_bits8(&gbc, unit->data, unit->data_size);
425 if (err < 0)
426 return err;
427
428 err = ff_cbs_alloc_unit_content(ctx, unit);
429 if (err < 0)
430 return err;
431
432 switch (unit->type) {
433 case LCEVC_NON_IDR_NUT:
434 case LCEVC_IDR_NUT:
435 {
436 LCEVCRawNAL *nal = unit->content;
437 LCEVCRawProcessBlockList *block_list;
438
439 err = cbs_lcevc_read_nal(ctx, &gbc, unit->content, unit->type);
440
441 if (err < 0)
442 return err;
443
444 block_list = &nal->process_block_list;
445 for (int i = 0; i < block_list->nb_blocks; i++) {
446 LCEVCRawProcessBlock *block = &block_list->blocks[i];
447 LCEVCRawEncodedData *slice;
448
449 if (block->payload_type != LCEVC_PAYLOAD_TYPE_ENCODED_DATA)
450 continue;
451
452 slice = block->payload;
453 slice->data_ref = av_buffer_ref(unit->data_ref);
454 if (!slice->data_ref)
455 return AVERROR(ENOMEM);
456 slice->data = unit->data + slice->header_size;
457 }
458 }
459 break;
460 default:
461 return AVERROR(ENOSYS);
462 }
463
464 return 0;
465 }
466
467 static int cbs_lcevc_write_nal_unit(CodedBitstreamContext *ctx,
468 CodedBitstreamUnit *unit,
469 PutBitContext *pbc)
470 {
471 int err;
472
473 switch (unit->type) {
474 case LCEVC_NON_IDR_NUT:
475 case LCEVC_IDR_NUT:
476 {
477 err = cbs_lcevc_write_nal(ctx, pbc, unit->content, unit->type);
478
479 if (err < 0)
480 return err;
481 }
482 break;
483 default:
484 av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for "
485 "NAL unit type %"PRIu32".\n", unit->type);
486 return AVERROR_PATCHWELCOME;
487 }
488
489 return 0;
490 }
491
492 static void free_picture_config(AVRefStructOpaque unused, void *obj)
493 {
494 LCEVCRawPictureConfig *picture_config = obj;
495
496 av_refstruct_unref(&picture_config->gc);
497 }
498
499 static void free_encoded_data(AVRefStructOpaque unused, void *obj)
500 {
501 LCEVCRawEncodedData *slice = obj;
502
503 av_buffer_unref(&slice->data_ref);
504
505 av_refstruct_unref(&slice->sc);
506 av_refstruct_unref(&slice->gc);
507 av_refstruct_unref(&slice->pc);
508 }
509
510 static void free_additional_info(AVRefStructOpaque unused, void *obj)
511 {
512 LCEVCRawAdditionalInfo *additional_info = obj;
513 LCEVCRawSEI *sei = &additional_info->sei;
514 SEIRawMessage *message = &sei->message;
515
516 av_refstruct_unref(&additional_info->payload_ref);
517 av_refstruct_unref(&sei->payload_ref);
518 av_refstruct_unref(&message->payload_ref);
519 av_refstruct_unref(&message->extension_data);
520 }
521
522 int ff_cbs_lcevc_alloc_process_block_payload(LCEVCRawProcessBlock *block,
523 const LCEVCProcessBlockTypeDescriptor *desc)
524 {
525 void (*free_func)(AVRefStructOpaque, void*);
526
527 av_assert0(block->payload == NULL &&
528 block->payload_ref == NULL);
529 block->payload_type = desc->payload_type;
530
531 if (desc->payload_type == LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG)
532 free_func = &free_picture_config;
533 else if (desc->payload_type == LCEVC_PAYLOAD_TYPE_ENCODED_DATA)
534 free_func = &free_encoded_data;
535 else if (desc->payload_type == LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO)
536 free_func = &free_additional_info;
537 else
538 free_func = NULL;
539
540 block->payload_ref = av_refstruct_alloc_ext(desc->payload_size, 0,
541 NULL, free_func);
542 if (!block->payload_ref)
543 return AVERROR(ENOMEM);
544 block->payload = block->payload_ref;
545
546 return 0;
547 }
548
549 int ff_cbs_lcevc_list_add(LCEVCRawProcessBlockList *list, int position)
550 {
551 LCEVCRawProcessBlock *blocks;
552
553 if (position == -1)
554 position = list->nb_blocks;
555 av_assert0(position >= 0 && position <= list->nb_blocks);
556
557 if (list->nb_blocks < list->nb_blocks_allocated) {
558 blocks = list->blocks;
559
560 if (position < list->nb_blocks)
561 memmove(blocks + position + 1, blocks + position,
562 (list->nb_blocks - position) * sizeof(*blocks));
563 } else {
564 blocks = av_malloc_array(list->nb_blocks*2 + 1, sizeof(*blocks));
565 if (!blocks)
566 return AVERROR(ENOMEM);
567
568 list->nb_blocks_allocated = 2*list->nb_blocks_allocated + 1;
569
570 if (position > 0)
571 memcpy(blocks, list->blocks, position * sizeof(*blocks));
572
573 if (position < list->nb_blocks)
574 memcpy(blocks + position + 1, list->blocks + position,
575 (list->nb_blocks - position) * sizeof(*blocks));
576
577 av_free(list->blocks);
578 list->blocks = blocks;
579 }
580
581 memset(blocks + position, 0, sizeof(*blocks));
582
583 ++list->nb_blocks;
584
585 return 0;
586 }
587
588 void ff_cbs_lcevc_free_process_block_list(LCEVCRawProcessBlockList *list)
589 {
590 for (int i = 0; i < list->nb_blocks; i++) {
591 LCEVCRawProcessBlock *block = &list->blocks[i];
592 av_refstruct_unref(&block->payload_ref);
593 av_refstruct_unref(&block->extension_data);
594 }
595 av_free(list->blocks);
596 }
597
598 static int cbs_lcevc_get_process_block_list(CodedBitstreamContext *ctx,
599 CodedBitstreamUnit *unit,
600 LCEVCRawProcessBlockList **list)
601 {
602 LCEVCRawNAL *nal = unit->content;
603 if (unit->type != LCEVC_NON_IDR_NUT && unit->type != LCEVC_IDR_NUT)
604 return AVERROR(EINVAL);
605 *list = &nal->process_block_list;
606
607 return 0;
608 }
609
610 int ff_cbs_lcevc_add_process_block(CodedBitstreamContext *ctx,
611 CodedBitstreamFragment *au,
612 int position,
613 uint32_t payload_type,
614 void *payload_data,
615 void *payload_ref)
616 {
617 const LCEVCProcessBlockTypeDescriptor *desc;
618 CodedBitstreamUnit *unit = NULL;
619 LCEVCRawProcessBlockList *list;
620 LCEVCRawProcessBlock *block;
621 int err;
622
623 desc = ff_cbs_lcevc_process_block_find_type(ctx, payload_type);
624 if (!desc)
625 return AVERROR(EINVAL);
626
627 for (int i = 0; i < au->nb_units; i++) {
628 if (au->units[i].type == LCEVC_NON_IDR_NUT ||
629 au->units[i].type == LCEVC_IDR_NUT) {
630 unit = &au->units[i];
631 break;
632 }
633 }
634 if (!unit)
635 return AVERROR(EINVAL);
636
637 // Find the block list inside the codec-dependent unit.
638 err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
639 if (err < 0)
640 return err;
641
642 // Add a new block to the message list.
643 err = ff_cbs_lcevc_list_add(list, position);
644 if (err < 0)
645 return err;
646
647 if (payload_ref) {
648 /* The following just increments payload_ref's refcount,
649 * so that payload_ref is now owned by us. */
650 payload_ref = av_refstruct_ref(payload_ref);
651 }
652
653 block = &list->blocks[position];
654
655 block->payload_type = payload_type;
656 block->payload = payload_data;
657 block->payload_ref = payload_ref;
658
659 return 0;
660 }
661
662 int ff_cbs_lcevc_find_process_block(CodedBitstreamContext *ctx,
663 CodedBitstreamFragment *au,
664 uint32_t payload_type,
665 LCEVCRawProcessBlock **iter)
666 {
667 int err, found;
668
669 found = 0;
670 for (int i = 0; i < au->nb_units; i++) {
671 CodedBitstreamUnit *unit = &au->units[i];
672 LCEVCRawProcessBlockList *list;
673
674 if (!unit->content)
675 continue;
676
677 err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
678 if (err < 0)
679 continue;
680
681 for (int j = 0; j < list->nb_blocks; j++) {
682 LCEVCRawProcessBlock *block = &list->blocks[j];
683
684 if (block->payload_type == payload_type) {
685 if (!*iter || found) {
686 *iter = block;
687 return j;
688 }
689 if (block == *iter)
690 found = 1;
691 }
692 }
693 }
694
695 return AVERROR(ENOENT);
696 }
697
698 static void cbs_lcevc_delete_process_block(LCEVCRawProcessBlockList *list,
699 int position)
700 {
701 LCEVCRawProcessBlock *block;
702
703 av_assert0(0 <= position && position < list->nb_blocks);
704
705 block = &list->blocks[position];
706 av_refstruct_unref(&block->payload_ref);
707
708 --list->nb_blocks;
709
710 if (list->nb_blocks > 0) {
711 memmove(list->blocks + position,
712 list->blocks + position + 1,
713 (list->nb_blocks - position) * sizeof(*list->blocks));
714 }
715 }
716
717 void ff_cbs_lcevc_delete_process_block_type(CodedBitstreamContext *ctx,
718 CodedBitstreamFragment *au,
719 uint32_t payload_type)
720 {
721 int err;
722
723 for (int i = 0; i < au->nb_units; i++) {
724 CodedBitstreamUnit *unit = &au->units[i];
725 LCEVCRawProcessBlockList *list;
726
727 err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
728 if (err < 0)
729 continue;
730
731 for (int j = list->nb_blocks - 1; j >= 0; j--) {
732 if (list->blocks[j].payload_type == payload_type)
733 cbs_lcevc_delete_process_block(list, j);
734 }
735 }
736 }
737
738 static av_cold void cbs_lcevc_flush(CodedBitstreamContext *ctx)
739 {
740 CodedBitstreamLCEVCContext *lcevc = ctx->priv_data;
741
742 av_refstruct_unref(&lcevc->sc);
743 av_refstruct_unref(&lcevc->gc);
744 av_refstruct_unref(&lcevc->pc);
745 }
746
747 static av_cold void cbs_lcevc_close(CodedBitstreamContext *ctx)
748 {
749 CodedBitstreamLCEVCContext *lcevc = ctx->priv_data;
750
751 cbs_lcevc_flush(ctx);
752 ff_h2645_packet_uninit(&lcevc->common.read_packet);
753 }
754
755 static void cbs_lcevc_free_nal(AVRefStructOpaque unused, void *content)
756 {
757 LCEVCRawNAL *nal = content;
758 ff_cbs_lcevc_free_process_block_list(&nal->process_block_list);
759 }
760
761 static CodedBitstreamUnitTypeDescriptor cbs_lcevc_unit_types[] = {
762 CBS_UNIT_TYPES_COMPLEX((LCEVC_NON_IDR_NUT, LCEVC_IDR_NUT),
763 LCEVCRawNAL, cbs_lcevc_free_nal),
764
765 CBS_UNIT_TYPE_END_OF_LIST
766 };
767
768 // Macro for the read/write pair.
769 #define LCEVC_PROCESS_BLOCK_RW(codec, name) \
770 .read = cbs_ ## codec ## _read_ ## name ## _internal, \
771 .write = cbs_ ## codec ## _write_ ## name ## _internal
772
773 static const LCEVCProcessBlockTypeDescriptor cbs_lcevc_process_block_types[] = {
774 {
775 LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG,
776 sizeof(LCEVCRawSequenceConfig),
777 LCEVC_PROCESS_BLOCK_RW(lcevc, sequence_config),
778 },
779 {
780 LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG,
781 sizeof(LCEVCRawGlobalConfig),
782 LCEVC_PROCESS_BLOCK_RW(lcevc, global_config),
783 },
784 {
785 LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG,
786 sizeof(LCEVCRawPictureConfig),
787 LCEVC_PROCESS_BLOCK_RW(lcevc, picture_config),
788 },
789 {
790 LCEVC_PAYLOAD_TYPE_ENCODED_DATA,
791 sizeof(LCEVCRawEncodedData),
792 LCEVC_PROCESS_BLOCK_RW(lcevc, encoded_data),
793 },
794 {
795 LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO,
796 sizeof(LCEVCRawAdditionalInfo),
797 LCEVC_PROCESS_BLOCK_RW(lcevc, additional_info),
798 },
799 {
800 LCEVC_PAYLOAD_TYPE_FILLER,
801 sizeof(LCEVCRawFiller),
802 LCEVC_PROCESS_BLOCK_RW(lcevc, filler),
803 },
804 LCEVC_PROCESS_BLOCK_TYPE_END,
805 };
806
807 const LCEVCProcessBlockTypeDescriptor
808 *ff_cbs_lcevc_process_block_find_type(CodedBitstreamContext *ctx,
809 int payload_type)
810 {
811 for (int i = 0; cbs_lcevc_process_block_types[i].payload_type >= 0; i++) {
812 if (cbs_lcevc_process_block_types[i].payload_type == payload_type)
813 return &cbs_lcevc_process_block_types[i];
814 }
815
816 return NULL;
817 }
818
819 const CodedBitstreamType ff_cbs_type_lcevc = {
820 .codec_id = AV_CODEC_ID_LCEVC,
821
822 .priv_data_size = sizeof(CodedBitstreamLCEVCContext),
823
824 .unit_types = cbs_lcevc_unit_types,
825
826 .split_fragment = &cbs_lcevc_split_fragment,
827 .read_unit = &cbs_lcevc_read_nal_unit,
828 .write_unit = &cbs_lcevc_write_nal_unit,
829 .assemble_fragment = &ff_cbs_h2645_assemble_fragment,
830
831 .flush = &cbs_lcevc_flush,
832 .close = &cbs_lcevc_close,
833 };
834