diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index e071442c31..c1f67fefb9 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -357,18 +357,31 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc)
 #define bit_position(rw)   (get_bits_count(rw))
 #define byte_alignment(rw) (get_bits_count(rw) % 8)
 
+/* The CBS SEI code uses the refstruct API for the allocation
+ * of its child buffers. */
 #define allocate(name, size) do { \
-        name ## _ref = av_buffer_allocz(size + \
+        name  = ff_refstruct_allocz(size + \
                                         AV_INPUT_BUFFER_PADDING_SIZE); \
-        if (!name ## _ref) \
+        if (!name) \
             return AVERROR(ENOMEM); \
-        name = name ## _ref->data; \
     } while (0)
 
 #define FUNC(name) FUNC_SEI(name)
 #include "cbs_sei_syntax_template.c"
 #undef FUNC
 
+#undef allocate
+
+/* The other code uses the refstruct API for the allocation
+ * of its child buffers. */
+#define allocate(name, size) do { \
+        name ## _ref = av_buffer_allocz(size + \
+                                        AV_INPUT_BUFFER_PADDING_SIZE); \
+        if (!name ## _ref) \
+            return AVERROR(ENOMEM); \
+        name = name ## _ref->data; \
+    } while (0)
+
 #define FUNC(name) FUNC_H264(name)
 #include "cbs_h264_syntax_template.c"
 #undef FUNC
diff --git a/libavcodec/cbs_sei.c b/libavcodec/cbs_sei.c
index bd7f6f4938..e28c2f9093 100644
--- a/libavcodec/cbs_sei.c
+++ b/libavcodec/cbs_sei.c
@@ -22,25 +22,25 @@
 #include "cbs_h265.h"
 #include "cbs_h266.h"
 #include "cbs_sei.h"
+#include "refstruct.h"
 
-static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
+static void cbs_free_user_data_registered(FFRefStructOpaque unused, void *obj)
 {
-    SEIRawUserDataRegistered *udr = (SEIRawUserDataRegistered*)data;
-    av_buffer_unref(&udr->data_ref);
-    av_free(udr);
+    SEIRawUserDataRegistered *udr = obj;
+    ff_refstruct_unref(&udr->data);
 }
 
-static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
+static void cbs_free_user_data_unregistered(FFRefStructOpaque unused, void *obj)
 {
-    SEIRawUserDataUnregistered *udu = (SEIRawUserDataUnregistered*)data;
-    av_buffer_unref(&udu->data_ref);
-    av_free(udu);
+    SEIRawUserDataUnregistered *udu = obj;
+    ff_refstruct_unref(&udu->data);
 }
 
 int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
                                      const SEIMessageTypeDescriptor *desc)
 {
-    void (*free_func)(void*, uint8_t*);
+    void (*free_func)(FFRefStructOpaque, void*);
+    unsigned flags = 0;
 
     av_assert0(message->payload     == NULL &&
                message->payload_ref == NULL);
@@ -50,24 +50,16 @@ int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
         free_func = &cbs_free_user_data_registered;
     else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
         free_func = &cbs_free_user_data_unregistered;
-    else
+    else {
         free_func = NULL;
-
-    if (free_func) {
-        message->payload = av_mallocz(desc->size);
-        if (!message->payload)
-            return AVERROR(ENOMEM);
-        message->payload_ref =
-            av_buffer_create(message->payload, desc->size,
-                             free_func, NULL, 0);
-    } else {
-        message->payload_ref = av_buffer_alloc(desc->size);
+        flags = FF_REFSTRUCT_FLAG_NO_ZEROING;
     }
-    if (!message->payload_ref) {
-        av_freep(&message->payload);
+
+    message->payload_ref = ff_refstruct_alloc_ext(desc->size, flags,
+                                                  NULL, free_func);
+    if (!message->payload_ref)
         return AVERROR(ENOMEM);
-    }
-    message->payload = message->payload_ref->data;
+    message->payload = message->payload_ref;
 
     return 0;
 }
@@ -101,8 +93,8 @@ void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
 {
     for (int i = 0; i < list->nb_messages; i++) {
         SEIRawMessage *message = &list->messages[i];
-        av_buffer_unref(&message->payload_ref);
-        av_buffer_unref(&message->extension_data_ref);
+        ff_refstruct_unref(&message->payload_ref);
+        ff_refstruct_unref(&message->extension_data);
     }
     av_free(list->messages);
 }
@@ -278,13 +270,12 @@ int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
                            int prefix,
                            uint32_t     payload_type,
                            void        *payload_data,
-                           AVBufferRef *payload_buf)
+                           void        *payload_ref)
 {
     const SEIMessageTypeDescriptor *desc;
     CodedBitstreamUnit *unit;
     SEIRawMessageList *list;
     SEIRawMessage *message;
-    AVBufferRef *payload_ref;
     int err;
 
     desc = ff_cbs_sei_find_type(ctx, payload_type);
@@ -306,12 +297,10 @@ int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
     if (err < 0)
         return err;
 
-    if (payload_buf) {
-        payload_ref = av_buffer_ref(payload_buf);
-        if (!payload_ref)
-            return AVERROR(ENOMEM);
-    } else {
-        payload_ref = NULL;
+    if (payload_ref) {
+        /* The following just increments payload_ref's refcount,
+         * so that payload_ref is now owned by us. */
+        payload_ref = ff_refstruct_ref(payload_ref);
     }
 
     message = &list->messages[list->nb_messages - 1];
@@ -364,8 +353,8 @@ static void cbs_sei_delete_message(SEIRawMessageList *list,
     av_assert0(0 <= position && position < list->nb_messages);
 
     message = &list->messages[position];
-    av_buffer_unref(&message->payload_ref);
-    av_buffer_unref(&message->extension_data_ref);
+    ff_refstruct_unref(&message->payload_ref);
+    ff_refstruct_unref(&message->extension_data);
 
     --list->nb_messages;
 
diff --git a/libavcodec/cbs_sei.h b/libavcodec/cbs_sei.h
index 1c327a4689..4511c506cc 100644
--- a/libavcodec/cbs_sei.h
+++ b/libavcodec/cbs_sei.h
@@ -22,8 +22,6 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include "libavutil/buffer.h"
-
 #include "cbs.h"
 #include "sei.h"
 
@@ -35,15 +33,13 @@ typedef struct SEIRawFillerPayload {
 typedef struct SEIRawUserDataRegistered {
     uint8_t      itu_t_t35_country_code;
     uint8_t      itu_t_t35_country_code_extension_byte;
-    uint8_t     *data;
-    AVBufferRef *data_ref;
+    uint8_t     *data; ///< RefStruct reference
     size_t       data_length;
 } SEIRawUserDataRegistered;
 
 typedef struct SEIRawUserDataUnregistered {
     uint8_t      uuid_iso_iec_11578[16];
-    uint8_t     *data;
-    AVBufferRef *data_ref;
+    uint8_t     *data; ///< RefStruct reference
     size_t       data_length;
 } SEIRawUserDataUnregistered;
 
@@ -75,9 +71,8 @@ typedef struct SEIRawMessage {
     uint32_t     payload_type;
     uint32_t     payload_size;
     void        *payload;
-    AVBufferRef *payload_ref;
-    uint8_t     *extension_data;
-    AVBufferRef *extension_data_ref;
+    void        *payload_ref;    ///< RefStruct reference
+    uint8_t     *extension_data; ///< RefStruct reference
     size_t       extension_bit_length;
 } SEIRawMessage;
 
@@ -174,15 +169,16 @@ void ff_cbs_sei_free_message_list(SEIRawMessageList *list);
  * Will add to an existing SEI NAL unit, or create a new one for the
  * message if there is no suitable existing one.
  *
- * Takes a new reference to payload_buf, if set.  If payload_buf is
- * NULL then the new message will not be reference counted.
+ * If set, payload_ref must be a RefStruct reference backing payload_data.
+ * This function creates a new reference to payload_ref in this case.
+ * If payload_ref is NULL, the new message will not be reference counted.
  */
 int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
                            CodedBitstreamFragment *au,
                            int prefix,
                            uint32_t     payload_type,
                            void        *payload_data,
-                           AVBufferRef *payload_buf);
+                           void        *payload_ref);
 
 /**
  * Iterate over messages with the given payload type in an access unit.
diff --git a/libavcodec/cbs_sei_syntax_template.c b/libavcodec/cbs_sei_syntax_template.c
index 6a7cc36dda..62dd1dabaa 100644
--- a/libavcodec/cbs_sei_syntax_template.c
+++ b/libavcodec/cbs_sei_syntax_template.c
@@ -234,7 +234,12 @@ static int FUNC(message)(CodedBitstreamContext *ctx, RWContext *rw,
     } else {
         uint8_t *data;
 
+#ifdef READ
+        allocate(current->payload_ref, current->payload_size);
+        current->payload = current->payload_ref;
+#else
         allocate(current->payload, current->payload_size);
+#endif
         data = current->payload;
 
         for (i = 0; i < current->payload_size; i++)
