Unit types are split into three categories, depending on how their content is managed: * POD structure - these require no special treatment. * Structure containing references to refcounted buffers - these can use a common free function when the offsets of all the internal references are known. * More complex structures - these still require ad-hoc treatment.
For each codec we can then maintain a table of descriptors for each unit type, defining the mechanism needed to allocate/free that unit content. This is not required to be used immediately - a new alloc function supports this, but does not replace the old one which works without referring to these tables. --- libavcodec/cbs.c | 62 +++++++++++++++++++++++++++++++++++++++ libavcodec/cbs.h | 16 ++++++++++ libavcodec/cbs_internal.h | 36 +++++++++++++++++++++++ 3 files changed, 114 insertions(+) diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index 0260ba6f67..1963d86133 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -754,3 +754,65 @@ int ff_cbs_delete_unit(CodedBitstreamContext *ctx, return 0; } + +static void cbs_default_free_unit_content(void *opaque, uint8_t *data) +{ + const CodedBitstreamUnitTypeDescriptor *desc = opaque; + if (desc->content_type == CBS_CONTENT_TYPE_INTERNAL_REFS) { + int i; + for (i = 0; i < desc->nb_ref_offsets; i++) { + void **ptr = (void**)(data + desc->ref_offsets[i]); + av_buffer_unref((AVBufferRef**)(ptr + 1)); + *ptr = NULL; + } + } + av_free(data); +} + +static const CodedBitstreamUnitTypeDescriptor + *cbs_find_unit_type_desc(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + const CodedBitstreamUnitTypeDescriptor *desc; + int i; + + if (!ctx->codec->unit_types) + return NULL; + + for (i = 0;; i++) { + desc = &ctx->codec->unit_types[i]; + if (desc->unit_type == CBS_INVALID_UNIT_TYPE) + break; + if (desc->unit_type == unit->type) + return desc; + } + return NULL; +} + +int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + const CodedBitstreamUnitTypeDescriptor *desc; + + av_assert0(!unit->content && !unit->content_ref); + + desc = cbs_find_unit_type_desc(ctx, unit); + if (!desc) + return AVERROR(ENOSYS); + + unit->content = av_mallocz(desc->content_size); + if (!unit->content) + return AVERROR(ENOMEM); + + unit->content_ref = + av_buffer_create(unit->content, desc->content_size, + desc->content_free ? desc->content_free + : cbs_default_free_unit_content, + (void*)desc, 0); + if (!unit->content_ref) { + av_freep(&unit->content); + return AVERROR(ENOMEM); + } + + return 0; +} diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index e8b2d41ecb..8f764905bd 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -54,6 +54,13 @@ struct CodedBitstreamType; */ typedef uint32_t CodedBitstreamUnitType; +/** + * Value which is never valid as a unit type. + * + * This can be used as a sentinel. + */ +#define CBS_INVALID_UNIT_TYPE (UINT32_MAX) + /** * Coded bitstream unit structure. * @@ -337,6 +344,15 @@ int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, size_t size, void (*free)(void *unit, uint8_t *content)); +/** + * Allocate a new internal content buffer matching the type of the unit. + * + * The content will be zeroed. + */ +int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + /** * Allocate a new internal data buffer of the given size in the unit. * diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h index dd4babf092..06a8f9b979 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -25,11 +25,47 @@ #include "put_bits.h" +enum { + // Unit content is a simple structure. + CBS_CONTENT_TYPE_POD, + // Unit content contains some references to other structures, but all + // managed via buffer reference counting. The descriptor defines the + // structure offsets of every buffer reference. + CBS_CONTENT_TYPE_INTERNAL_REFS, + // Unit content is something more complex. The descriptor defines + // special functions to manage the content. + CBS_CONTENT_TYPE_COMPLEX, +}; + +// Maximum number of reference buffer offsets in any one unit. +#define CBS_MAX_REF_OFFSETS 1 + +typedef struct CodedBitstreamUnitTypeDescriptor { + CodedBitstreamUnitType unit_type; + + int content_type; + size_t content_size; + + int nb_ref_offsets; + // The structure must contain two adjacent elements: + // type *field; + // AVBufferRef *field_ref; + // where field points to something in the buffer referred to by + // field_ref. This offset is then set to offsetof(struct, field). + size_t ref_offsets[CBS_MAX_REF_OFFSETS]; + + void (*content_free)(void *opaque, uint8_t *data); +} CodedBitstreamUnitTypeDescriptor; + typedef struct CodedBitstreamType { enum AVCodecID codec_id; size_t priv_data_size; + // List of unit type descriptors for this codec. + // Terminated by a descriptor with type CBS_INVALID_UNIT_TYPE. + const CodedBitstreamUnitTypeDescriptor *unit_types; + // Split frag->data into coded bitstream units, creating the // frag->units array. Fill data but not content on each unit. // The header argument should be set if the fragment came from -- 2.20.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".