From 721a5e228983707d98611e29bdc3b49539be958a Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt Date: Mon, 5 May 2025 20:03:18 +0200 Subject: [PATCH 06/11] avcodec/cbs: Allow to avoid refcounting/data copying This will make it possible to avoid copying data when using CBS with e.g. a parser. Signed-off-by: Andreas Rheinhardt --- libavcodec/cbs.c | 26 ++++++++++++++++---------- libavcodec/cbs.h | 22 +++++++++++++++++++--- libavcodec/cbs_apv.c | 14 ++++++++------ libavcodec/cbs_av1.c | 8 +++++--- libavcodec/cbs_h2645.c | 24 +++++++++++++++--------- libavcodec/cbs_jpeg.c | 8 +++++--- libavcodec/cbs_mpeg2.c | 8 +++++--- libavcodec/cbs_vp8.c | 8 +++++--- libavcodec/cbs_vp9.c | 8 +++++--- 9 files changed, 83 insertions(+), 43 deletions(-) diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index 39411d4cf5..b9c9284f3d 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -114,6 +114,7 @@ av_cold int CBS_FUNC(init)(CodedBitstreamContext **ctx_ptr, ctx->log_ctx = log_ctx; ctx->codec = type; /* Must be before any error */ + ctx->force_refcounting = 1; if (type->priv_data_size) { ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); @@ -216,7 +217,7 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx, av_refstruct_unref(&unit->content_ref); unit->content = NULL; - av_assert0(unit->data && unit->data_ref); + av_assert0(unit->data); err = ctx->codec->read_unit(ctx, unit); if (err == AVERROR(ENOSYS)) { @@ -267,7 +268,10 @@ static int cbs_read_data(CodedBitstreamContext *ctx, { int err; - if (buf) { + if (!ctx->force_refcounting) { + frag->data = (uint8_t*)data; + frag->data_size = size; + } else if (buf) { frag->data_ref = av_buffer_ref(buf); if (!frag->data_ref) return AVERROR(ENOMEM); @@ -856,9 +860,13 @@ int CBS_FUNC(append_unit_data)(CodedBitstreamFragment *frag, uint8_t *data, size_t data_size, const AVBufferRef *data_buf) { - AVBufferRef *data_ref = av_buffer_ref(data_buf); - if (!data_ref) - return AVERROR(ENOMEM); + AVBufferRef *data_ref = NULL; + + if (data_buf) { + data_ref = av_buffer_ref(data_buf); + if (!data_ref) + return AVERROR(ENOMEM); + } return cbs_insert_unit_data(frag, type, data, data_size, data_ref, @@ -990,11 +998,9 @@ static int cbs_clone_noncomplex_unit_content(void **clonep, continue; } if (!src_buf) { - // We can't handle a non-refcounted pointer here - we don't - // have enough information to handle whatever structure lies - // at the other end of it. - err = AVERROR(EINVAL); - goto fail; + // Both original and copy point to the same data and + // neither are refcounted. + continue; } *copy_buf = av_buffer_ref(src_buf); diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index 958b00cc05..40159d3c6d 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -100,7 +100,7 @@ typedef struct CodedBitstreamUnit { /** * A reference to the buffer containing data. * - * Must be set if data is not NULL. + * If unset, it is the user's responsibility to ensure that data stays valid. */ AVBufferRef *data_ref; @@ -147,7 +147,7 @@ typedef struct CodedBitstreamFragment { /** * A reference to the buffer containing data. * - * Must be set if data is not NULL. + * If unset, it is the user's responsibility to ensure that data stays valid. */ AVBufferRef *data_ref; @@ -258,6 +258,22 @@ typedef struct CodedBitstreamContext { */ int nb_decompose_unit_types; + /** + * If set (the default), CBS will ensure that CodedBitstreamUnit.data + * and CodedBitstreamFragment.data are valid indefinitely by setting + * the corresponding data_ref (this involves copying non-refcounted data + * to newly allocated buffers). + * If unset, it is the user's responsibility to ensure that CodedBitstreamUnit.data + * and CodedBitstreamFragment.data stays valid long enough. CBS will try + * to avoid creating references and copying data. + * + * This flag does not influence whether buffers allocated by CBS are + * refcounted (they always are). Also, CBS will still ensure that + * non-transient data (kept in the codec-specific private data) is always + * valid indefinitely. + */ + int force_refcounting; + /** * Enable trace output during read/write operations. */ @@ -460,7 +476,7 @@ int CBS_FUNC(insert_unit_content)(CodedBitstreamFragment *frag, /** * Add a new unit to a fragment with the given data bitstream. * - * data must be owned by data_buf (which must be provided); + * If data_buf is provided, data must be owned by data_buf; * ownership of the reference stays with the caller. */ int CBS_FUNC(append_unit_data)(CodedBitstreamFragment *frag, diff --git a/libavcodec/cbs_apv.c b/libavcodec/cbs_apv.c index ebf57d3bbb..ddc363fbf3 100644 --- a/libavcodec/cbs_apv.c +++ b/libavcodec/cbs_apv.c @@ -276,12 +276,14 @@ static int cbs_apv_read_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - // Each tile inside the frame has pointers into the unit - // data buffer; make a single reference here for all of - // them together. - frame->tile_data_ref = av_buffer_ref(unit->data_ref); - if (!frame->tile_data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + // Each tile inside the frame has pointers into the unit + // data buffer; make a single reference here for all of + // them together. + frame->tile_data_ref = av_buffer_ref(unit->data_ref); + if (!frame->tile_data_ref) + return AVERROR(ENOMEM); + } } break; case APV_PBU_ACCESS_UNIT_INFORMATION: diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c index 4edb6ecd50..40c3cc8167 100644 --- a/libavcodec/cbs_av1.c +++ b/libavcodec/cbs_av1.c @@ -824,9 +824,11 @@ static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx, // Must be byte-aligned at this point. av_assert0(pos % 8 == 0); - *data_ref = av_buffer_ref(unit->data_ref); - if (!*data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + *data_ref = av_buffer_ref(unit->data_ref); + if (!*data_ref) + return AVERROR(ENOMEM); + } *data = unit->data + pos / 8; *data_size = unit->data_size - pos / 8; diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c index 369e3ac876..45b0c2ce87 100644 --- a/libavcodec/cbs_h2645.c +++ b/libavcodec/cbs_h2645.c @@ -902,9 +902,11 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, len = unit->data_size; slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_ref(unit->data_ref); - if (!slice->data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) + return AVERROR(ENOMEM); + } slice->data = unit->data + pos / 8; slice->data_bit_start = pos % 8; } @@ -1039,9 +1041,11 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, len = unit->data_size; slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_ref(unit->data_ref); - if (!slice->data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) + return AVERROR(ENOMEM); + } slice->data = unit->data + pos / 8; slice->data_bit_start = pos % 8; } @@ -1205,9 +1209,11 @@ static int cbs_h266_read_nal_unit(CodedBitstreamContext *ctx, slice->header_size = pos / 8; slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_ref(unit->data_ref); - if (!slice->data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) + return AVERROR(ENOMEM); + } slice->data = unit->data + pos / 8; slice->data_bit_start = pos % 8; } diff --git a/libavcodec/cbs_jpeg.c b/libavcodec/cbs_jpeg.c index 281606e7af..cfb9b6d46c 100644 --- a/libavcodec/cbs_jpeg.c +++ b/libavcodec/cbs_jpeg.c @@ -255,9 +255,11 @@ static int cbs_jpeg_read_unit(CodedBitstreamContext *ctx, av_assert0(pos % 8 == 0); if (pos > 0) { scan->data_size = unit->data_size - pos / 8; - scan->data_ref = av_buffer_ref(unit->data_ref); - if (!scan->data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + scan->data_ref = av_buffer_ref(unit->data_ref); + if (!scan->data_ref) + return AVERROR(ENOMEM); + } scan->data = unit->data + pos / 8; } diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c index 37fc28a4e6..4b51647b13 100644 --- a/libavcodec/cbs_mpeg2.c +++ b/libavcodec/cbs_mpeg2.c @@ -234,9 +234,11 @@ static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx, len = unit->data_size; slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_ref(unit->data_ref); - if (!slice->data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + slice->data_ref = av_buffer_ref(unit->data_ref); + if (!slice->data_ref) + return AVERROR(ENOMEM); + } slice->data = unit->data + pos / 8; slice->data_bit_start = pos % 8; diff --git a/libavcodec/cbs_vp8.c b/libavcodec/cbs_vp8.c index 1f80f34faf..9bfba71d9e 100644 --- a/libavcodec/cbs_vp8.c +++ b/libavcodec/cbs_vp8.c @@ -344,9 +344,11 @@ static int cbs_vp8_read_unit(CodedBitstreamContext *ctx, pos = (pos + 7) / 8; av_assert0(pos <= unit->data_size); - frame->data_ref = av_buffer_ref(unit->data_ref); - if (!frame->data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + frame->data_ref = av_buffer_ref(unit->data_ref); + if (!frame->data_ref) + return AVERROR(ENOMEM); + } frame->data = unit->data + pos; frame->data_size = unit->data_size - pos; diff --git a/libavcodec/cbs_vp9.c b/libavcodec/cbs_vp9.c index ff99fe32fb..3ca52770f3 100644 --- a/libavcodec/cbs_vp9.c +++ b/libavcodec/cbs_vp9.c @@ -460,9 +460,11 @@ static int cbs_vp9_read_unit(CodedBitstreamContext *ctx, if (pos == unit->data_size) { // No data (e.g. a show-existing-frame frame). } else { - frame->data_ref = av_buffer_ref(unit->data_ref); - if (!frame->data_ref) - return AVERROR(ENOMEM); + if (unit->data_ref) { + frame->data_ref = av_buffer_ref(unit->data_ref); + if (!frame->data_ref) + return AVERROR(ENOMEM); + } frame->data = unit->data + pos; frame->data_size = unit->data_size - pos; -- 2.45.2