diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index ecbf57c293..deabf5dde5 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -665,3 +665,62 @@ 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++)
+            av_buffer_unref((AVBufferRef**)(data + desc->ref_offsets[i]));
+    }
+    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 053eccffde..1079f625bf 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.
  *
@@ -312,6 +319,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 53f2e5d187..667c90cb14 100644
--- a/libavcodec/cbs_internal.h
+++ b/libavcodec/cbs_internal.h
@@ -25,11 +25,42 @@
 #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 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;
+    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
