FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/cbs_lcevc.c
Date: 2026-09-26 20:14:34
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