[FFmpeg-devel] [PoC][PATCH 1/2] avutil/buffer: add av_buffer_create2() to allow AVBufferRef to store complex structures
James Almer
jamrial at gmail.com
Mon Jun 1 19:35:39 EEST 2020
Signed-off-by: James Almer <jamrial at gmail.com>
---
This is an attempt at solving the annoying constrain of only supporting flat
arrays within any given AVBufferRef. It introduces a new function to create
buffers that accepts two new callback functions, one to allocate a new buffer
when a new writable reference needs to be created, and one to copy data to it.
In the default scenario, the alloc and copy callbacks simply call
av_buffer_alloc() and memcpy() respectively, which is the current behavior of
treating the buffer as a flat array. In a more complex scenario, the real
benefit comes from the copy callback, which will let a custom implementation
set up the new buffer how it pleases, including handling pointers within the
complex struct it may be storing.
Patch 2/2 is an example implementation of this.
libavutil/buffer.c | 39 ++++++++++++++++++++++++++++++-----
libavutil/buffer.h | 41 +++++++++++++++++++++++++++++++++++++
libavutil/buffer_internal.h | 10 +++++++++
3 files changed, 85 insertions(+), 5 deletions(-)
diff --git a/libavutil/buffer.c b/libavutil/buffer.c
index 7ff6adc2ec..b048e168e8 100644
--- a/libavutil/buffer.c
+++ b/libavutil/buffer.c
@@ -26,9 +26,12 @@
#include "mem.h"
#include "thread.h"
-AVBufferRef *av_buffer_create(uint8_t *data, int size,
- void (*free)(void *opaque, uint8_t *data),
- void *opaque, int flags)
+AVBufferRef *av_buffer_create2(uint8_t *data, int size,
+ AVBufferRef* (*alloc)(void *opaque, int size),
+ int (*copy)(void *opaque, AVBufferRef *dst,
+ const uint8_t *src, int size),
+ void (*free)(void *opaque, uint8_t *data),
+ void *opaque, int flags)
{
AVBufferRef *ref = NULL;
AVBuffer *buf = NULL;
@@ -39,6 +42,8 @@ AVBufferRef *av_buffer_create(uint8_t *data, int size,
buf->data = data;
buf->size = size;
+ buf->alloc = alloc ? alloc : av_buffer_default_alloc;
+ buf->copy = copy ? copy : av_buffer_default_copy;
buf->free = free ? free : av_buffer_default_free;
buf->opaque = opaque;
@@ -59,11 +64,29 @@ AVBufferRef *av_buffer_create(uint8_t *data, int size,
return ref;
}
+AVBufferRef *av_buffer_create(uint8_t *data, int size,
+ void (*free)(void *opaque, uint8_t *data),
+ void *opaque, int flags)
+{
+ return av_buffer_create2(data, size, NULL, NULL, free, opaque, flags);
+}
+
void av_buffer_default_free(void *opaque, uint8_t *data)
{
av_free(data);
}
+AVBufferRef *av_buffer_default_alloc(void *opaque, int size)
+{
+ return av_buffer_alloc(size);
+}
+
+int av_buffer_default_copy(void *opaque, AVBufferRef *dst, const uint8_t *src, int size)
+{
+ memcpy(dst->data, src, size);
+ return 0;
+}
+
AVBufferRef *av_buffer_alloc(int size)
{
AVBufferRef *ret = NULL;
@@ -151,15 +174,21 @@ int av_buffer_get_ref_count(const AVBufferRef *buf)
int av_buffer_make_writable(AVBufferRef **pbuf)
{
AVBufferRef *newbuf, *buf = *pbuf;
+ AVBuffer *b = buf->buffer;
+ int ret;
if (av_buffer_is_writable(buf))
return 0;
- newbuf = av_buffer_alloc(buf->size);
+ newbuf = b->alloc(b->opaque, buf->size);
if (!newbuf)
return AVERROR(ENOMEM);
- memcpy(newbuf->data, buf->data, buf->size);
+ ret = b->copy(b->opaque, newbuf, buf->data, buf->size);
+ if (ret < 0) {
+ av_buffer_unref(&newbuf);
+ return ret;
+ }
buffer_replace(pbuf, &newbuf);
diff --git a/libavutil/buffer.h b/libavutil/buffer.h
index e0f94314f4..375e04034a 100644
--- a/libavutil/buffer.h
+++ b/libavutil/buffer.h
@@ -131,6 +131,47 @@ AVBufferRef *av_buffer_create(uint8_t *data, int size,
void (*free)(void *opaque, uint8_t *data),
void *opaque, int flags);
+/**
+ * Create an AVBuffer from an existing array.
+ *
+ * If this function is successful, data is owned by the AVBuffer. The caller may
+ * only access data through the returned AVBufferRef and references derived from
+ * it.
+ * If this function fails, data is left untouched.
+ * @param data data array
+ * @param size size of data in bytes
+ * @param alloc a callback for allocating a new buffer when a new writable
+ * reference for this buffer is created
+ * @param copy a callback for copying this buffer's data into the newly
+ * allocated buffer by the alloc callback
+ * @param free a callback for freeing this buffer's data
+ * @param opaque parameter to be got for processing or passed to alloc/copy/free
+ * @param flags a combination of AV_BUFFER_FLAG_*
+ *
+ * @return an AVBufferRef referring to data on success, NULL on failure.
+ */
+AVBufferRef *av_buffer_create2(uint8_t *data, int size,
+ AVBufferRef* (*alloc)(void *opaque, int size),
+ int (*copy)(void *opaque, AVBufferRef *dst,
+ const uint8_t *src, int size),
+ void (*free)(void *opaque, uint8_t *data),
+ void *opaque, int flags);
+
+/**
+ * Default alloc callback, which calls av_buffer_alloc() and returns the
+ * newly allocated buffer.
+ * This function is meant to be passed to av_buffer_create2() or
+ * av_buffer_pool_init2(), not called directly.
+ */
+AVBufferRef *av_buffer_default_alloc(void *opaque, int size);
+
+/**
+ * Default copy callback, which copies the data pointed by src to dst.
+ * This function is meant to be passed to av_buffer_create2(), not called
+ * directly.
+ */
+int av_buffer_default_copy(void *opaque, AVBufferRef *dst, const uint8_t *src, int size);
+
/**
* Default free callback, which calls av_free() on the buffer data.
* This function is meant to be passed to av_buffer_create(), not called
diff --git a/libavutil/buffer_internal.h b/libavutil/buffer_internal.h
index 70d2615a06..27fcb5f015 100644
--- a/libavutil/buffer_internal.h
+++ b/libavutil/buffer_internal.h
@@ -39,6 +39,16 @@ struct AVBuffer {
*/
atomic_uint refcount;
+ /**
+ * a callback to allocate a new writable buffer
+ */
+ AVBufferRef* (*alloc)(void *opaque, int size);
+
+ /**
+ * a callback to copy the data into a newly allocated writable buffer
+ */
+ int (*copy)(void *opaque, AVBufferRef *dst, const uint8_t *src, int size);
+
/**
* a callback for freeing the data
*/
--
2.26.2
More information about the ffmpeg-devel
mailing list