Signed-off-by: James Almer <jamr...@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 _______________________________________________ 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".