FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/cbs_lcevc.c
Date: 2026-03-13 22:30:28
Exec Total Coverage
Lines: 0 271 0.0%
Functions: 0 20 0.0%
Branches: 0 162 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 if (err < 0)
460 return err;
461 }
462 break;
463 default:
464 return AVERROR(ENOSYS);
465 }
466
467 return 0;
468 }
469
470 static int cbs_lcevc_write_nal_unit(CodedBitstreamContext *ctx,
471 CodedBitstreamUnit *unit,
472 PutBitContext *pbc)
473 {
474 int err;
475
476 switch (unit->type) {
477 case LCEVC_NON_IDR_NUT:
478 case LCEVC_IDR_NUT:
479 {
480 err = cbs_lcevc_write_nal(ctx, pbc, unit->content, unit->type);
481
482 if (err < 0)
483 return err;
484 }
485 break;
486 default:
487 av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for "
488 "NAL unit type %"PRIu32".\n", unit->type);
489 return AVERROR_PATCHWELCOME;
490 }
491
492 return 0;
493 }
494
495 static void free_picture_config(AVRefStructOpaque unused, void *obj)
496 {
497 LCEVCRawPictureConfig *picture_config = obj;
498
499 av_refstruct_unref(&picture_config->gc);
500 }
501
502 static void free_encoded_data(AVRefStructOpaque unused, void *obj)
503 {
504 LCEVCRawEncodedData *slice = obj;
505
506 av_buffer_unref(&slice->data_ref);
507
508 av_refstruct_unref(&slice->sc);
509 av_refstruct_unref(&slice->gc);
510 av_refstruct_unref(&slice->pc);
511 }
512
513 static void free_additional_info(AVRefStructOpaque unused, void *obj)
514 {
515 LCEVCRawAdditionalInfo *additional_info = obj;
516 LCEVCRawSEI *sei = &additional_info->sei;
517 SEIRawMessage *message = &sei->message;
518
519 av_refstruct_unref(&additional_info->payload_ref);
520 av_refstruct_unref(&sei->payload_ref);
521 av_refstruct_unref(&message->payload_ref);
522 av_refstruct_unref(&message->extension_data);
523 }
524
525 int ff_cbs_lcevc_alloc_process_block_payload(LCEVCRawProcessBlock *block,
526 const LCEVCProcessBlockTypeDescriptor *desc)
527 {
528 void (*free_func)(AVRefStructOpaque, void*);
529
530 av_assert0(block->payload == NULL &&
531 block->payload_ref == NULL);
532 block->payload_type = desc->payload_type;
533
534 if (desc->payload_type == LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG)
535 free_func = &free_picture_config;
536 else if (desc->payload_type == LCEVC_PAYLOAD_TYPE_ENCODED_DATA)
537 free_func = &free_encoded_data;
538 else if (desc->payload_type == LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO)
539 free_func = &free_additional_info;
540 else
541 free_func = NULL;
542
543 block->payload_ref = av_refstruct_alloc_ext(desc->payload_size, 0,
544 NULL, free_func);
545 if (!block->payload_ref)
546 return AVERROR(ENOMEM);
547 block->payload = block->payload_ref;
548
549 return 0;
550 }
551
552 int ff_cbs_lcevc_list_add(LCEVCRawProcessBlockList *list, int position)
553 {
554 LCEVCRawProcessBlock *blocks;
555
556 if (position == -1)
557 position = list->nb_blocks;
558 av_assert0(position >= 0 && position <= list->nb_blocks);
559
560 if (list->nb_blocks < list->nb_blocks_allocated) {
561 blocks = list->blocks;
562
563 if (position < list->nb_blocks)
564 memmove(blocks + position + 1, blocks + position,
565 (list->nb_blocks - position) * sizeof(*blocks));
566 } else {
567 blocks = av_malloc_array(list->nb_blocks*2 + 1, sizeof(*blocks));
568 if (!blocks)
569 return AVERROR(ENOMEM);
570
571 list->nb_blocks_allocated = 2*list->nb_blocks_allocated + 1;
572
573 if (position > 0)
574 memcpy(blocks, list->blocks, position * sizeof(*blocks));
575
576 if (position < list->nb_blocks)
577 memcpy(blocks + position + 1, list->blocks + position,
578 (list->nb_blocks - position) * sizeof(*blocks));
579
580 av_free(list->blocks);
581 list->blocks = blocks;
582 }
583
584 memset(blocks + position, 0, sizeof(*blocks));
585
586 ++list->nb_blocks;
587
588 return 0;
589 }
590
591 void ff_cbs_lcevc_free_process_block_list(LCEVCRawProcessBlockList *list)
592 {
593 for (int i = 0; i < list->nb_blocks; i++) {
594 LCEVCRawProcessBlock *block = &list->blocks[i];
595 av_refstruct_unref(&block->payload_ref);
596 av_refstruct_unref(&block->extension_data);
597 }
598 av_free(list->blocks);
599 }
600
601 static int cbs_lcevc_get_process_block_list(CodedBitstreamContext *ctx,
602 CodedBitstreamUnit *unit,
603 LCEVCRawProcessBlockList **list)
604 {
605 LCEVCRawNAL *nal = unit->content;
606 if (unit->type != LCEVC_NON_IDR_NUT && unit->type != LCEVC_IDR_NUT)
607 return AVERROR(EINVAL);
608 *list = &nal->process_block_list;
609
610 return 0;
611 }
612
613 int ff_cbs_lcevc_add_process_block(CodedBitstreamContext *ctx,
614 CodedBitstreamFragment *au,
615 int position,
616 uint32_t payload_type,
617 void *payload_data,
618 void *payload_ref)
619 {
620 const LCEVCProcessBlockTypeDescriptor *desc;
621 CodedBitstreamUnit *unit = NULL;
622 LCEVCRawProcessBlockList *list;
623 LCEVCRawProcessBlock *block;
624 int err;
625
626 desc = ff_cbs_lcevc_process_block_find_type(ctx, payload_type);
627 if (!desc)
628 return AVERROR(EINVAL);
629
630 for (int i = 0; i < au->nb_units; i++) {
631 if (au->units[i].type == LCEVC_NON_IDR_NUT ||
632 au->units[i].type == LCEVC_IDR_NUT) {
633 unit = &au->units[i];
634 break;
635 }
636 }
637 if (!unit)
638 return AVERROR(EINVAL);
639
640 // Find the block list inside the codec-dependent unit.
641 err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
642 if (err < 0)
643 return err;
644
645 // Add a new block to the message list.
646 err = ff_cbs_lcevc_list_add(list, position);
647 if (err < 0)
648 return err;
649
650 if (payload_ref) {
651 /* The following just increments payload_ref's refcount,
652 * so that payload_ref is now owned by us. */
653 payload_ref = av_refstruct_ref(payload_ref);
654 }
655
656 block = &list->blocks[position];
657
658 block->payload_type = payload_type;
659 block->payload = payload_data;
660 block->payload_ref = payload_ref;
661
662 return 0;
663 }
664
665 int ff_cbs_lcevc_find_process_block(CodedBitstreamContext *ctx,
666 CodedBitstreamFragment *au,
667 uint32_t payload_type,
668 LCEVCRawProcessBlock **iter)
669 {
670 int err, found;
671
672 found = 0;
673 for (int i = 0; i < au->nb_units; i++) {
674 CodedBitstreamUnit *unit = &au->units[i];
675 LCEVCRawProcessBlockList *list;
676
677 if (!unit->content)
678 continue;
679
680 err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
681 if (err < 0)
682 continue;
683
684 for (int j = 0; j < list->nb_blocks; j++) {
685 LCEVCRawProcessBlock *block = &list->blocks[j];
686
687 if (block->payload_type == payload_type) {
688 if (!*iter || found) {
689 *iter = block;
690 return j;
691 }
692 if (block == *iter)
693 found = 1;
694 }
695 }
696 }
697
698 return AVERROR(ENOENT);
699 }
700
701 static void cbs_lcevc_delete_process_block(LCEVCRawProcessBlockList *list,
702 int position)
703 {
704 LCEVCRawProcessBlock *block;
705
706 av_assert0(0 <= position && position < list->nb_blocks);
707
708 block = &list->blocks[position];
709 av_refstruct_unref(&block->payload_ref);
710
711 --list->nb_blocks;
712
713 if (list->nb_blocks > 0) {
714 memmove(list->blocks + position,
715 list->blocks + position + 1,
716 (list->nb_blocks - position) * sizeof(*list->blocks));
717 }
718 }
719
720 void ff_cbs_lcevc_delete_process_block_type(CodedBitstreamContext *ctx,
721 CodedBitstreamFragment *au,
722 uint32_t payload_type)
723 {
724 int err;
725
726 for (int i = 0; i < au->nb_units; i++) {
727 CodedBitstreamUnit *unit = &au->units[i];
728 LCEVCRawProcessBlockList *list;
729
730 err = cbs_lcevc_get_process_block_list(ctx, unit, &list);
731 if (err < 0)
732 continue;
733
734 for (int j = list->nb_blocks - 1; j >= 0; j--) {
735 if (list->blocks[j].payload_type == payload_type)
736 cbs_lcevc_delete_process_block(list, j);
737 }
738 }
739 }
740
741 static av_cold void cbs_lcevc_flush(CodedBitstreamContext *ctx)
742 {
743 CodedBitstreamLCEVCContext *lcevc = ctx->priv_data;
744
745 av_refstruct_unref(&lcevc->sc);
746 av_refstruct_unref(&lcevc->gc);
747 av_refstruct_unref(&lcevc->pc);
748 }
749
750 static av_cold void cbs_lcevc_close(CodedBitstreamContext *ctx)
751 {
752 CodedBitstreamLCEVCContext *lcevc = ctx->priv_data;
753
754 cbs_lcevc_flush(ctx);
755 ff_h2645_packet_uninit(&lcevc->common.read_packet);
756 }
757
758 static void cbs_lcevc_free_nal(AVRefStructOpaque unused, void *content)
759 {
760 LCEVCRawNAL *nal = content;
761 ff_cbs_lcevc_free_process_block_list(&nal->process_block_list);
762 }
763
764 static CodedBitstreamUnitTypeDescriptor cbs_lcevc_unit_types[] = {
765 CBS_UNIT_TYPES_COMPLEX((LCEVC_NON_IDR_NUT, LCEVC_IDR_NUT),
766 LCEVCRawNAL, cbs_lcevc_free_nal),
767
768 CBS_UNIT_TYPE_END_OF_LIST
769 };
770
771 // Macro for the read/write pair.
772 #define LCEVC_PROCESS_BLOCK_RW(codec, name) \
773 .read = cbs_ ## codec ## _read_ ## name ## _internal, \
774 .write = cbs_ ## codec ## _write_ ## name ## _internal
775
776 static const LCEVCProcessBlockTypeDescriptor cbs_lcevc_process_block_types[] = {
777 {
778 LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG,
779 sizeof(LCEVCRawSequenceConfig),
780 LCEVC_PROCESS_BLOCK_RW(lcevc, sequence_config),
781 },
782 {
783 LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG,
784 sizeof(LCEVCRawGlobalConfig),
785 LCEVC_PROCESS_BLOCK_RW(lcevc, global_config),
786 },
787 {
788 LCEVC_PAYLOAD_TYPE_PICTURE_CONFIG,
789 sizeof(LCEVCRawPictureConfig),
790 LCEVC_PROCESS_BLOCK_RW(lcevc, picture_config),
791 },
792 {
793 LCEVC_PAYLOAD_TYPE_ENCODED_DATA,
794 sizeof(LCEVCRawEncodedData),
795 LCEVC_PROCESS_BLOCK_RW(lcevc, encoded_data),
796 },
797 {
798 LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO,
799 sizeof(LCEVCRawAdditionalInfo),
800 LCEVC_PROCESS_BLOCK_RW(lcevc, additional_info),
801 },
802 {
803 LCEVC_PAYLOAD_TYPE_FILLER,
804 sizeof(LCEVCRawFiller),
805 LCEVC_PROCESS_BLOCK_RW(lcevc, filler),
806 },
807 LCEVC_PROCESS_BLOCK_TYPE_END,
808 };
809
810 const LCEVCProcessBlockTypeDescriptor
811 *ff_cbs_lcevc_process_block_find_type(CodedBitstreamContext *ctx,
812 int payload_type)
813 {
814 for (int i = 0; cbs_lcevc_process_block_types[i].payload_type >= 0; i++) {
815 if (cbs_lcevc_process_block_types[i].payload_type == payload_type)
816 return &cbs_lcevc_process_block_types[i];
817 }
818
819 return NULL;
820 }
821
822 const CodedBitstreamType ff_cbs_type_lcevc = {
823 .codec_id = AV_CODEC_ID_LCEVC,
824
825 .priv_data_size = sizeof(CodedBitstreamLCEVCContext),
826
827 .unit_types = cbs_lcevc_unit_types,
828
829 .split_fragment = &cbs_lcevc_split_fragment,
830 .read_unit = &cbs_lcevc_read_nal_unit,
831 .write_unit = &cbs_lcevc_write_nal_unit,
832 .assemble_fragment = &ff_cbs_h2645_assemble_fragment,
833
834 .flush = &cbs_lcevc_flush,
835 .close = &cbs_lcevc_close,
836 };
837