2 * This file is part of FFmpeg.
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.
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.
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
23 #include "libavutil/avassert.h"
24 #include "libavutil/buffer.h"
25 #include "libavutil/common.h"
26 #include "libavutil/opt.h"
29 #include "cbs_internal.h"
32 static const CodedBitstreamType *const cbs_type_table[] = {
53 const enum AVCodecID ff_cbs_all_codec_ids[] = {
67 AV_CODEC_ID_MPEG2VIDEO,
75 int ff_cbs_init(CodedBitstreamContext **ctx_ptr,
76 enum AVCodecID codec_id, void *log_ctx)
78 CodedBitstreamContext *ctx;
79 const CodedBitstreamType *type;
83 for (i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) {
84 if (cbs_type_table[i]->codec_id == codec_id) {
85 type = cbs_type_table[i];
90 return AVERROR(EINVAL);
92 ctx = av_mallocz(sizeof(*ctx));
94 return AVERROR(ENOMEM);
96 ctx->log_ctx = log_ctx;
97 ctx->codec = type; /* Must be before any error */
99 if (type->priv_data_size) {
100 ctx->priv_data = av_mallocz(ctx->codec->priv_data_size);
101 if (!ctx->priv_data) {
103 return AVERROR(ENOMEM);
105 if (type->priv_class) {
106 *(const AVClass **)ctx->priv_data = type->priv_class;
107 av_opt_set_defaults(ctx->priv_data);
111 ctx->decompose_unit_types = NULL;
113 ctx->trace_enable = 0;
114 ctx->trace_level = AV_LOG_TRACE;
120 void ff_cbs_flush(CodedBitstreamContext *ctx)
122 if (ctx->codec->flush)
123 ctx->codec->flush(ctx);
126 void ff_cbs_close(CodedBitstreamContext **ctx_ptr)
128 CodedBitstreamContext *ctx = *ctx_ptr;
133 if (ctx->codec->close)
134 ctx->codec->close(ctx);
136 av_freep(&ctx->write_buffer);
138 if (ctx->codec->priv_class && ctx->priv_data)
139 av_opt_free(ctx->priv_data);
141 av_freep(&ctx->priv_data);
145 static void cbs_unit_uninit(CodedBitstreamUnit *unit)
147 av_buffer_unref(&unit->content_ref);
148 unit->content = NULL;
150 av_buffer_unref(&unit->data_ref);
153 unit->data_bit_padding = 0;
156 void ff_cbs_fragment_reset(CodedBitstreamFragment *frag)
160 for (i = 0; i < frag->nb_units; i++)
161 cbs_unit_uninit(&frag->units[i]);
164 av_buffer_unref(&frag->data_ref);
167 frag->data_bit_padding = 0;
170 void ff_cbs_fragment_free(CodedBitstreamFragment *frag)
172 ff_cbs_fragment_reset(frag);
174 av_freep(&frag->units);
175 frag->nb_units_allocated = 0;
178 static int cbs_read_fragment_content(CodedBitstreamContext *ctx,
179 CodedBitstreamFragment *frag)
183 for (i = 0; i < frag->nb_units; i++) {
184 CodedBitstreamUnit *unit = &frag->units[i];
186 if (ctx->decompose_unit_types) {
187 for (j = 0; j < ctx->nb_decompose_unit_types; j++) {
188 if (ctx->decompose_unit_types[j] == unit->type)
191 if (j >= ctx->nb_decompose_unit_types)
195 av_buffer_unref(&unit->content_ref);
196 unit->content = NULL;
198 av_assert0(unit->data && unit->data_ref);
200 err = ctx->codec->read_unit(ctx, unit);
201 if (err == AVERROR(ENOSYS)) {
202 av_log(ctx->log_ctx, AV_LOG_VERBOSE,
203 "Decomposition unimplemented for unit %d "
204 "(type %"PRIu32").\n", i, unit->type);
205 } else if (err == AVERROR(EAGAIN)) {
206 av_log(ctx->log_ctx, AV_LOG_VERBOSE,
207 "Skipping decomposition of unit %d "
208 "(type %"PRIu32").\n", i, unit->type);
209 av_buffer_unref(&unit->content_ref);
210 unit->content = NULL;
211 } else if (err < 0) {
212 av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d "
213 "(type %"PRIu32").\n", i, unit->type);
221 static int cbs_fill_fragment_data(CodedBitstreamFragment *frag,
222 const uint8_t *data, size_t size)
224 av_assert0(!frag->data && !frag->data_ref);
227 av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
229 return AVERROR(ENOMEM);
231 frag->data = frag->data_ref->data;
232 frag->data_size = size;
234 memcpy(frag->data, data, size);
235 memset(frag->data + size, 0,
236 AV_INPUT_BUFFER_PADDING_SIZE);
241 static int cbs_read_data(CodedBitstreamContext *ctx,
242 CodedBitstreamFragment *frag,
244 const uint8_t *data, size_t size,
250 frag->data_ref = av_buffer_ref(buf);
252 return AVERROR(ENOMEM);
254 frag->data = (uint8_t *)data;
255 frag->data_size = size;
258 err = cbs_fill_fragment_data(frag, data, size);
263 err = ctx->codec->split_fragment(ctx, frag, header);
267 return cbs_read_fragment_content(ctx, frag);
270 int ff_cbs_read_extradata(CodedBitstreamContext *ctx,
271 CodedBitstreamFragment *frag,
272 const AVCodecParameters *par)
274 return cbs_read_data(ctx, frag, NULL,
276 par->extradata_size, 1);
279 int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx,
280 CodedBitstreamFragment *frag,
281 const AVCodecContext *avctx)
283 return cbs_read_data(ctx, frag, NULL,
285 avctx->extradata_size, 1);
288 int ff_cbs_read_packet(CodedBitstreamContext *ctx,
289 CodedBitstreamFragment *frag,
292 return cbs_read_data(ctx, frag, pkt->buf,
293 pkt->data, pkt->size, 0);
296 int ff_cbs_read(CodedBitstreamContext *ctx,
297 CodedBitstreamFragment *frag,
298 const uint8_t *data, size_t size)
300 return cbs_read_data(ctx, frag, NULL,
304 static int cbs_write_unit_data(CodedBitstreamContext *ctx,
305 CodedBitstreamUnit *unit)
310 if (!ctx->write_buffer) {
311 // Initial write buffer size is 1MB.
312 ctx->write_buffer_size = 1024 * 1024;
314 reallocate_and_try_again:
315 ret = av_reallocp(&ctx->write_buffer, ctx->write_buffer_size);
317 av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a "
318 "sufficiently large write buffer (last attempt "
319 "%"SIZE_SPECIFIER" bytes).\n", ctx->write_buffer_size);
324 init_put_bits(&pbc, ctx->write_buffer, ctx->write_buffer_size);
326 ret = ctx->codec->write_unit(ctx, unit, &pbc);
328 if (ret == AVERROR(ENOSPC)) {
330 if (ctx->write_buffer_size == INT_MAX / 8)
331 return AVERROR(ENOMEM);
332 ctx->write_buffer_size = FFMIN(2 * ctx->write_buffer_size, INT_MAX / 8);
333 goto reallocate_and_try_again;
335 // Write failed for some other reason.
339 // Overflow but we didn't notice.
340 av_assert0(put_bits_count(&pbc) <= 8 * ctx->write_buffer_size);
342 if (put_bits_count(&pbc) % 8)
343 unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8;
345 unit->data_bit_padding = 0;
347 flush_put_bits(&pbc);
349 ret = ff_cbs_alloc_unit_data(unit, put_bytes_output(&pbc));
353 memcpy(unit->data, ctx->write_buffer, unit->data_size);
358 int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx,
359 CodedBitstreamFragment *frag)
363 for (i = 0; i < frag->nb_units; i++) {
364 CodedBitstreamUnit *unit = &frag->units[i];
369 av_buffer_unref(&unit->data_ref);
372 err = cbs_write_unit_data(ctx, unit);
374 av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d "
375 "(type %"PRIu32").\n", i, unit->type);
378 av_assert0(unit->data && unit->data_ref);
381 av_buffer_unref(&frag->data_ref);
384 err = ctx->codec->assemble_fragment(ctx, frag);
386 av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n");
389 av_assert0(frag->data && frag->data_ref);
394 int ff_cbs_write_extradata(CodedBitstreamContext *ctx,
395 AVCodecParameters *par,
396 CodedBitstreamFragment *frag)
400 err = ff_cbs_write_fragment_data(ctx, frag);
404 av_freep(&par->extradata);
406 par->extradata = av_malloc(frag->data_size +
407 AV_INPUT_BUFFER_PADDING_SIZE);
409 return AVERROR(ENOMEM);
411 memcpy(par->extradata, frag->data, frag->data_size);
412 memset(par->extradata + frag->data_size, 0,
413 AV_INPUT_BUFFER_PADDING_SIZE);
414 par->extradata_size = frag->data_size;
419 int ff_cbs_write_packet(CodedBitstreamContext *ctx,
421 CodedBitstreamFragment *frag)
426 err = ff_cbs_write_fragment_data(ctx, frag);
430 buf = av_buffer_ref(frag->data_ref);
432 return AVERROR(ENOMEM);
434 av_buffer_unref(&pkt->buf);
437 pkt->data = frag->data;
438 pkt->size = frag->data_size;
444 void ff_cbs_trace_header(CodedBitstreamContext *ctx,
447 if (!ctx->trace_enable)
450 av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name);
453 void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
454 const char *str, const int *subscripts,
455 const char *bits, int64_t value)
458 size_t name_len, bits_len;
459 int pad, subs, i, j, k, n;
461 if (!ctx->trace_enable)
464 av_assert0(value >= INT_MIN && value <= UINT32_MAX);
466 subs = subscripts ? subscripts[0] : 0;
468 for (i = j = 0; str[i];) {
472 k = snprintf(name + j, sizeof(name) - j, "[%d", subscripts[n]);
473 av_assert0(k > 0 && j + k < sizeof(name));
475 for (++i; str[i] && str[i] != ']'; i++);
476 av_assert0(str[i] == ']');
478 while (str[i] && str[i] != ']')
479 name[j++] = str[i++];
480 av_assert0(str[i] == ']');
483 av_assert0(j + 1 < sizeof(name));
484 name[j++] = str[i++];
487 av_assert0(j + 1 < sizeof(name));
489 av_assert0(n == subs);
491 name_len = strlen(name);
492 bits_len = strlen(bits);
494 if (name_len + bits_len > 60)
499 av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n",
500 position, name, pad, bits, value);
503 int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
504 int width, const char *name,
505 const int *subscripts, uint32_t *write_to,
506 uint32_t range_min, uint32_t range_max)
511 av_assert0(width > 0 && width <= 32);
513 if (get_bits_left(gbc) < width) {
514 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at "
515 "%s: bitstream ended.\n", name);
516 return AVERROR_INVALIDDATA;
519 if (ctx->trace_enable)
520 position = get_bits_count(gbc);
522 value = get_bits_long(gbc, width);
524 if (ctx->trace_enable) {
527 for (i = 0; i < width; i++)
528 bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
531 ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
535 if (value < range_min || value > range_max) {
536 av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
537 "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n",
538 name, value, range_min, range_max);
539 return AVERROR_INVALIDDATA;
546 int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
547 int width, const char *name,
548 const int *subscripts, uint32_t value,
549 uint32_t range_min, uint32_t range_max)
551 av_assert0(width > 0 && width <= 32);
553 if (value < range_min || value > range_max) {
554 av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
555 "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n",
556 name, value, range_min, range_max);
557 return AVERROR_INVALIDDATA;
560 if (put_bits_left(pbc) < width)
561 return AVERROR(ENOSPC);
563 if (ctx->trace_enable) {
566 for (i = 0; i < width; i++)
567 bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
570 ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
571 name, subscripts, bits, value);
575 put_bits(pbc, width, value);
577 put_bits32(pbc, value);
582 int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
583 int width, const char *name,
584 const int *subscripts, int32_t *write_to,
585 int32_t range_min, int32_t range_max)
590 av_assert0(width > 0 && width <= 32);
592 if (get_bits_left(gbc) < width) {
593 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at "
594 "%s: bitstream ended.\n", name);
595 return AVERROR_INVALIDDATA;
598 if (ctx->trace_enable)
599 position = get_bits_count(gbc);
601 value = get_sbits_long(gbc, width);
603 if (ctx->trace_enable) {
606 for (i = 0; i < width; i++)
607 bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
610 ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
614 if (value < range_min || value > range_max) {
615 av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
616 "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
617 name, value, range_min, range_max);
618 return AVERROR_INVALIDDATA;
625 int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
626 int width, const char *name,
627 const int *subscripts, int32_t value,
628 int32_t range_min, int32_t range_max)
630 av_assert0(width > 0 && width <= 32);
632 if (value < range_min || value > range_max) {
633 av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
634 "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
635 name, value, range_min, range_max);
636 return AVERROR_INVALIDDATA;
639 if (put_bits_left(pbc) < width)
640 return AVERROR(ENOSPC);
642 if (ctx->trace_enable) {
645 for (i = 0; i < width; i++)
646 bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
649 ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
650 name, subscripts, bits, value);
654 put_sbits(pbc, width, value);
656 put_bits32(pbc, value);
662 int ff_cbs_alloc_unit_content(CodedBitstreamUnit *unit,
664 void (*free)(void *opaque, uint8_t *data))
666 av_assert0(!unit->content && !unit->content_ref);
668 unit->content = av_mallocz(size);
670 return AVERROR(ENOMEM);
672 unit->content_ref = av_buffer_create(unit->content, size,
674 if (!unit->content_ref) {
675 av_freep(&unit->content);
676 return AVERROR(ENOMEM);
682 int ff_cbs_alloc_unit_data(CodedBitstreamUnit *unit,
685 av_assert0(!unit->data && !unit->data_ref);
687 unit->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
689 return AVERROR(ENOMEM);
691 unit->data = unit->data_ref->data;
692 unit->data_size = size;
694 memset(unit->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
699 static int cbs_insert_unit(CodedBitstreamFragment *frag,
702 CodedBitstreamUnit *units;
704 if (frag->nb_units < frag->nb_units_allocated) {
707 if (position < frag->nb_units)
708 memmove(units + position + 1, units + position,
709 (frag->nb_units - position) * sizeof(*units));
711 units = av_malloc_array(frag->nb_units*2 + 1, sizeof(*units));
713 return AVERROR(ENOMEM);
715 frag->nb_units_allocated = 2*frag->nb_units_allocated + 1;
718 memcpy(units, frag->units, position * sizeof(*units));
720 if (position < frag->nb_units)
721 memcpy(units + position + 1, frag->units + position,
722 (frag->nb_units - position) * sizeof(*units));
725 memset(units + position, 0, sizeof(*units));
727 if (units != frag->units) {
728 av_free(frag->units);
737 int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag,
739 CodedBitstreamUnitType type,
741 AVBufferRef *content_buf)
743 CodedBitstreamUnit *unit;
744 AVBufferRef *content_ref;
748 position = frag->nb_units;
749 av_assert0(position >= 0 && position <= frag->nb_units);
752 content_ref = av_buffer_ref(content_buf);
754 return AVERROR(ENOMEM);
759 err = cbs_insert_unit(frag, position);
761 av_buffer_unref(&content_ref);
765 unit = &frag->units[position];
767 unit->content = content;
768 unit->content_ref = content_ref;
773 int ff_cbs_insert_unit_data(CodedBitstreamFragment *frag,
775 CodedBitstreamUnitType type,
776 uint8_t *data, size_t data_size,
777 AVBufferRef *data_buf)
779 CodedBitstreamUnit *unit;
780 AVBufferRef *data_ref;
784 position = frag->nb_units;
785 av_assert0(position >= 0 && position <= frag->nb_units);
788 data_ref = av_buffer_ref(data_buf);
790 data_ref = av_buffer_create(data, data_size, NULL, NULL, 0);
794 return AVERROR(ENOMEM);
797 err = cbs_insert_unit(frag, position);
799 av_buffer_unref(&data_ref);
803 unit = &frag->units[position];
806 unit->data_size = data_size;
807 unit->data_ref = data_ref;
812 void ff_cbs_delete_unit(CodedBitstreamFragment *frag,
815 av_assert0(0 <= position && position < frag->nb_units
816 && "Unit to be deleted not in fragment.");
818 cbs_unit_uninit(&frag->units[position]);
822 if (frag->nb_units > 0)
823 memmove(frag->units + position,
824 frag->units + position + 1,
825 (frag->nb_units - position) * sizeof(*frag->units));
828 static void cbs_default_free_unit_content(void *opaque, uint8_t *data)
830 const CodedBitstreamUnitTypeDescriptor *desc = opaque;
831 if (desc->content_type == CBS_CONTENT_TYPE_INTERNAL_REFS) {
833 for (i = 0; i < desc->nb_ref_offsets; i++) {
834 void **ptr = (void**)(data + desc->ref_offsets[i]);
835 av_buffer_unref((AVBufferRef**)(ptr + 1));
841 static const CodedBitstreamUnitTypeDescriptor
842 *cbs_find_unit_type_desc(CodedBitstreamContext *ctx,
843 CodedBitstreamUnit *unit)
845 const CodedBitstreamUnitTypeDescriptor *desc;
848 if (!ctx->codec->unit_types)
852 desc = &ctx->codec->unit_types[i];
853 if (desc->nb_unit_types == 0)
855 if (desc->nb_unit_types == CBS_UNIT_TYPE_RANGE) {
856 if (unit->type >= desc->unit_type_range_start &&
857 unit->type <= desc->unit_type_range_end)
860 for (j = 0; j < desc->nb_unit_types; j++) {
861 if (desc->unit_types[j] == unit->type)
869 int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx,
870 CodedBitstreamUnit *unit)
872 const CodedBitstreamUnitTypeDescriptor *desc;
874 av_assert0(!unit->content && !unit->content_ref);
876 desc = cbs_find_unit_type_desc(ctx, unit);
878 return AVERROR(ENOSYS);
880 unit->content = av_mallocz(desc->content_size);
882 return AVERROR(ENOMEM);
885 av_buffer_create(unit->content, desc->content_size,
886 desc->content_free ? desc->content_free
887 : cbs_default_free_unit_content,
889 if (!unit->content_ref) {
890 av_freep(&unit->content);
891 return AVERROR(ENOMEM);
897 static int cbs_clone_unit_content(AVBufferRef **clone_ref,
898 CodedBitstreamUnit *unit,
899 const CodedBitstreamUnitTypeDescriptor *desc)
902 uint8_t **src_ptr, **copy_ptr;
903 AVBufferRef **src_buf, **copy_buf;
906 av_assert0(unit->content);
909 copy = av_memdup(src, desc->content_size);
911 return AVERROR(ENOMEM);
913 for (i = 0; i < desc->nb_ref_offsets; i++) {
914 src_ptr = (uint8_t**)(src + desc->ref_offsets[i]);
915 src_buf = (AVBufferRef**)(src_ptr + 1);
916 copy_ptr = (uint8_t**)(copy + desc->ref_offsets[i]);
917 copy_buf = (AVBufferRef**)(copy_ptr + 1);
920 av_assert0(!*src_buf);
924 // We can't handle a non-refcounted pointer here - we don't
925 // have enough information to handle whatever structure lies
926 // at the other end of it.
927 err = AVERROR(EINVAL);
931 // src_ptr is required to point somewhere inside src_buf. If it
932 // doesn't, there is a bug somewhere.
933 av_assert0(*src_ptr >= (*src_buf)->data &&
934 *src_ptr < (*src_buf)->data + (*src_buf)->size);
936 *copy_buf = av_buffer_ref(*src_buf);
938 err = AVERROR(ENOMEM);
941 *copy_ptr = (*copy_buf)->data + (*src_ptr - (*src_buf)->data);
944 *clone_ref = av_buffer_create(copy, desc->content_size,
945 desc->content_free ? desc->content_free :
946 cbs_default_free_unit_content,
949 err = AVERROR(ENOMEM);
956 for (--i; i >= 0; i--)
957 av_buffer_unref((AVBufferRef**)(copy + desc->ref_offsets[i]));
963 int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx,
964 CodedBitstreamUnit *unit)
966 const CodedBitstreamUnitTypeDescriptor *desc;
970 av_assert0(unit->content);
971 if (unit->content_ref) {
972 // Already refcounted, nothing to do.
976 desc = cbs_find_unit_type_desc(ctx, unit);
978 return AVERROR(ENOSYS);
980 switch (desc->content_type) {
981 case CBS_CONTENT_TYPE_POD:
982 ref = av_buffer_alloc(desc->content_size);
984 return AVERROR(ENOMEM);
985 memcpy(ref->data, unit->content, desc->content_size);
989 case CBS_CONTENT_TYPE_INTERNAL_REFS:
990 err = cbs_clone_unit_content(&ref, unit, desc);
993 case CBS_CONTENT_TYPE_COMPLEX:
994 if (!desc->content_clone)
995 return AVERROR_PATCHWELCOME;
996 err = desc->content_clone(&ref, unit);
1000 av_assert0(0 && "Invalid content type.");
1006 unit->content_ref = ref;
1007 unit->content = ref->data;
1011 int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx,
1012 CodedBitstreamUnit *unit)
1014 const CodedBitstreamUnitTypeDescriptor *desc;
1018 // This can only be applied to refcounted units.
1019 err = ff_cbs_make_unit_refcounted(ctx, unit);
1022 av_assert0(unit->content && unit->content_ref);
1024 if (av_buffer_is_writable(unit->content_ref))
1027 desc = cbs_find_unit_type_desc(ctx, unit);
1029 return AVERROR(ENOSYS);
1031 switch (desc->content_type) {
1032 case CBS_CONTENT_TYPE_POD:
1033 err = av_buffer_make_writable(&unit->content_ref);
1036 case CBS_CONTENT_TYPE_INTERNAL_REFS:
1037 err = cbs_clone_unit_content(&ref, unit, desc);
1040 case CBS_CONTENT_TYPE_COMPLEX:
1041 if (!desc->content_clone)
1042 return AVERROR_PATCHWELCOME;
1043 err = desc->content_clone(&ref, unit);
1047 av_assert0(0 && "Invalid content type.");
1052 if (desc->content_type != CBS_CONTENT_TYPE_POD) {
1053 av_buffer_unref(&unit->content_ref);
1054 unit->content_ref = ref;
1056 unit->content = unit->content_ref->data;