Same concept as av_fast_malloc(). If the buffer passed to it is writable and big enough it will be reused, otherwise a new one will be allocated instead.
Signed-off-by: James Almer <jamr...@gmail.com> --- TODO: Changelog and APIChanges entries, version bump. libavutil/buffer.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libavutil/buffer.h | 42 ++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/libavutil/buffer.c b/libavutil/buffer.c index 8d1aa5fa84..16ce1b82e2 100644 --- a/libavutil/buffer.c +++ b/libavutil/buffer.c @@ -215,6 +215,69 @@ int av_buffer_realloc(AVBufferRef **pbuf, int size) return 0; } +static av_always_inline int buffer_fast_alloc(AVBufferRef **pbuf, int size, int zero_alloc) +{ + AVBufferRef *buf = *pbuf; + AVBuffer *b; + uint8_t *data; + + if (!buf || !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) { + /* Buffer can't be reused, and neither can the entire AVBufferRef. + * Unref the latter and alloc a new one. */ + av_buffer_unref(pbuf); + + buf = av_buffer_alloc(size); + if (!buf) + return AVERROR(ENOMEM); + + if (zero_alloc) + memset(buf->data, 0, size); + + *pbuf = buf; + return 0; + } + b = buf->buffer; + + if (size <= b->size) { + /* Buffer can be reused. Update the size of AVBufferRef but leave the + * AVBuffer untouched. */ + buf->size = FFMAX(0, size); + return 0; + } + + /* Buffer can't be reused, but there's no need to alloc new AVBuffer and + * AVBufferRef structs. Free the existing buffer, allocate a new one, and + * reset AVBuffer and AVBufferRef to default values. */ + b->free(b->opaque, b->data); + b->free = av_buffer_default_free; + b->opaque = NULL; + b->flags = 0; + + data = av_malloc(size); + if (!data) { + av_buffer_unref(pbuf); + return AVERROR(ENOMEM); + } + + if (zero_alloc) + memset(data, 0, size); + + b->data = buf->data = data; + b->size = buf->size = size; + + return 0; +} + +int av_buffer_fast_alloc(AVBufferRef **pbuf, int size) +{ + return buffer_fast_alloc(pbuf, size, 0); +} + +int av_buffer_fast_allocz(AVBufferRef **pbuf, int size) +{ + return buffer_fast_alloc(pbuf, size, 1); +} + AVBufferPool *av_buffer_pool_init2(int size, void *opaque, AVBufferRef* (*alloc)(void *opaque, int size), void (*pool_free)(void *opaque)) diff --git a/libavutil/buffer.h b/libavutil/buffer.h index 73b6bd0b14..1166017d22 100644 --- a/libavutil/buffer.h +++ b/libavutil/buffer.h @@ -197,6 +197,48 @@ int av_buffer_make_writable(AVBufferRef **buf); */ int av_buffer_realloc(AVBufferRef **buf, int size); +/** + * Allocate a buffer, reusing the given one if writable and large enough. + * + * @code{.c} + * AVBufferRef *buf = ...; + * int ret = av_buffer_fast_alloc(&buf, size); + * if (ret < 0) { + * // Allocation failed; buf already freed + * return ret; + * } + * @endcode + * + * @param buf A buffer reference. *buf may be NULL. On success, a new buffer + * reference will be written in its place. On failure, it will be + * unreferenced and set to NULL. + * @param size Required buffer size. + * + * @return 0 on success, a negative AVERROR on failure. + * + * @see av_buffer_realloc() + * @see av_buffer_fast_allocz() + */ +int av_buffer_fast_alloc(AVBufferRef **buf, int size); + +/** + * Allocate and clear a buffer, reusing the given one if writable and large + * enough. + * + * Like av_buffer_fast_alloc(), but all newly allocated space is initially + * cleared. Reused buffer is not cleared. + * + * @param buf A buffer reference. *buf may be NULL. On success, a new buffer + * reference will be written in its place. On failure, it will be + * unreferenced and set to NULL. + * @param size Required buffer size. + * + * @return 0 on success, a negative AVERROR on failure. + * + * @see av_buffer_fast_alloc() + */ +int av_buffer_fast_allocz(AVBufferRef **buf, int size); + /** * @} */ -- 2.16.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel