diff mbox

[FFmpeg-devel,v3,03/18] cbs: Describe allocate/free methods in tabular form

Message ID 20191002230453.6462-3-sw@jkqxz.net
State Superseded
Headers show

Commit Message

Mark Thompson Oct. 2, 2019, 11:04 p.m. UTC
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 set of
equivalent unit types, 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.
---
I switched to a fixed-size array of unit types in each descriptor to handle the case where multiple types need the same handling.  I wonder whether that might be better as a pointer, using a compound literal array in each entry - any opinion on that?


 libavcodec/cbs.c          | 63 +++++++++++++++++++++++++++++++++++++++
 libavcodec/cbs.h          |  9 ++++++
 libavcodec/cbs_internal.h | 42 ++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)
diff mbox

Patch

diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index 1a43cd2694..57f0c2257a 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -753,3 +753,66 @@  void ff_cbs_delete_unit(CodedBitstreamContext *ctx,
                 frag->units + position + 1,
                 (frag->nb_units - position) * sizeof(*frag->units));
 }
+
+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));
+        }
+    }
+    av_free(data);
+}
+
+static const CodedBitstreamUnitTypeDescriptor
+    *cbs_find_unit_type_desc(CodedBitstreamContext *ctx,
+                             CodedBitstreamUnit *unit)
+{
+    const CodedBitstreamUnitTypeDescriptor *desc;
+    int i, j;
+
+    if (!ctx->codec->unit_types)
+        return NULL;
+
+    for (i = 0;; i++) {
+        desc = &ctx->codec->unit_types[i];
+        if (desc->nb_unit_types == 0)
+            break;
+        for (j = 0; j < desc->nb_unit_types; j++) {
+            if (desc->unit_types[j] == 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 be986df4e4..42896042c1 100644
--- a/libavcodec/cbs.h
+++ b/libavcodec/cbs.h
@@ -345,6 +345,15 @@  int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx,
                               size_t size,
                               void (*free)(void *opaque, 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..7ed8ea0049 100644
--- a/libavcodec/cbs_internal.h
+++ b/libavcodec/cbs_internal.h
@@ -25,11 +25,53 @@ 
 #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,
+};
+
+enum {
+      // Maximum number of unit types described by the same unit type
+      // descriptor.
+      CBS_MAX_UNIT_TYPES = 16,
+      // Maximum number of reference buffer offsets in any one unit.
+      CBS_MAX_REF_OFFSETS = 1,
+};
+
+typedef struct CodedBitstreamUnitTypeDescriptor {
+    int                       nb_unit_types;
+    const CodedBitstreamUnitType unit_types[CBS_MAX_UNIT_TYPES];
+
+    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 nb_unit_types equal to zero.
+    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