[FFmpeg-devel] [PATCH] avutil/buffer: add av_buffer_fast_alloc()
wm4
nfxjfg at googlemail.com
Wed Mar 14 09:14:48 EET 2018
On Tue, 13 Mar 2018 20:48:56 -0300
James Almer <jamrial at gmail.com> wrote:
> 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 <jamrial at 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);
> +
> /**
> * @}
> */
Wouldn't it be better to avoid writing a lot of new allocation code
(with possibly subtle problems), and just use av_buffer_realloc() to
handle reallocation? (Possibly it could be moved to an internal
function to avoid the memcpy() required by realloc.)
More information about the ffmpeg-devel
mailing list