Re: [FFmpeg-devel] [PATCH] avutil/buffer: add av_buffer_fast_alloc()
On 3/14/2018 12:09 PM, wm4 wrote: > On Wed, 14 Mar 2018 11:59:59 -0300 > James Almer wrote: > >> On 3/14/2018 11:35 AM, wm4 wrote: >>> On Wed, 14 Mar 2018 11:13:52 -0300 >>> James Almer wrote: >>> On 3/14/2018 4:14 AM, wm4 wrote: > On Tue, 13 Mar 2018 20:48:56 -0300 > James Almer 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 >> --- >> 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 >> + * clea
Re: [FFmpeg-devel] [PATCH] avutil/buffer: add av_buffer_fast_alloc()
On Wed, 14 Mar 2018 11:59:59 -0300 James Almer wrote: > On 3/14/2018 11:35 AM, wm4 wrote: > > On Wed, 14 Mar 2018 11:13:52 -0300 > > James Almer wrote: > > > >> On 3/14/2018 4:14 AM, wm4 wrote: > >>> On Tue, 13 Mar 2018 20:48:56 -0300 > >>> James Almer 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 > --- > 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. >
Re: [FFmpeg-devel] [PATCH] avutil/buffer: add av_buffer_fast_alloc()
On 3/14/2018 11:35 AM, wm4 wrote: > On Wed, 14 Mar 2018 11:13:52 -0300 > James Almer wrote: > >> On 3/14/2018 4:14 AM, wm4 wrote: >>> On Tue, 13 Mar 2018 20:48:56 -0300 >>> James Almer 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 --- 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
Re: [FFmpeg-devel] [PATCH] avutil/buffer: add av_buffer_fast_alloc()
On Wed, 14 Mar 2018 11:13:52 -0300 James Almer wrote: > On 3/14/2018 4:14 AM, wm4 wrote: > > On Tue, 13 Mar 2018 20:48:56 -0300 > > James Almer 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 > >> --- > >> 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() > >> + */ > >> +i
Re: [FFmpeg-devel] [PATCH] avutil/buffer: add av_buffer_fast_alloc()
On 3/14/2018 4:14 AM, wm4 wrote: > On Tue, 13 Mar 2018 20:48:56 -0300 > James Almer 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 >> --- >> 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.) There are some d
Re: [FFmpeg-devel] [PATCH] avutil/buffer: add av_buffer_fast_alloc()
On Tue, 13 Mar 2018 20:48:56 -0300 James Almer 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 > --- > 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.) ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] avutil/buffer: add av_buffer_fast_alloc()
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 --- 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