[FFmpeg-devel] [PATCH] lavu/mem: add av_dynarray2_add()

Clément Bœsch ubitux at gmail.com
Mon May 13 13:12:19 CEST 2013


On Mon, May 13, 2013 at 01:02:01PM +0200, Stefano Sabatini wrote:
> On date Saturday 2013-05-11 14:31:53 +0200, Stefano Sabatini encoded:
> > On date Friday 2013-05-10 18:39:07 +0200, Clément Bœsch encoded:
> > > On Fri, May 10, 2013 at 06:30:14PM +0200, Stefano Sabatini wrote:
> > > > On date Friday 2013-05-10 18:16:59 +0200, Clément Bœsch encoded:
> > > > > On Fri, May 10, 2013 at 10:26:13AM +0200, Stefano Sabatini wrote:
> > > > > [...]
> > > > > > Updated. If someone has an idea about a better name
> > > > > > (av_dynarray_alloc_elem() doesn't match very well with
> > > > > > av_dynarray_add()), please tell.
> > > > > > 
> > > > > 
> > > > > Well, they don't work on the same type of array, they are in a sense
> > > > > "incompatible", so I think the names are even too close.
> > > > 
> > > > What about:
> > > > void *av_dynbuf_add(void **tab_ptr, int *nb_ptr, char *buf, size_t buf_size)
> > > > 
> > > > which prepends the content of buf to the dynamic buffer, or extends
> > > > the size in case buf is NULL.
> > > > 
> > > 
> > > Note that we have dyn_buf things in avio API, might be a little
> > > "confusing".
> > > 
> > > > This should be even handier for my specific use case. Consider the
> > > > patch suspended for the moment since I need to experiment a bit with
> > > > it.
> > > 
> > > I think the current code has various useful use-cases (see following
> > > patches in the thread).
> > 
> > Indeed, and I doubt of the utility of my dynbuf_add API, so I'll push
> > av_dynarray_alloc_elem() as is.
> 
> New patch, new name and new interface which should be more flexible
> and possibly less confusing.
> -- 
> FFmpeg = Foolish and Fostering Minimal Pacific Eretic Geisha

> From 909be8fc3d946c9feda57bbd46d40a3eb021b0ee Mon Sep 17 00:00:00 2001
> From: Stefano Sabatini <stefasab at gmail.com>
> Date: Sun, 14 Apr 2013 03:07:54 +0200
> Subject: [PATCH] lavu/mem: add av_dynarray2_add()
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
> 
> Based on a patch by Clément Bœsch.
> 
> See thread:
> From: Clément Bœsch <ubitux at gmail.com>
> Subject: [FFmpeg-devel] [PATCH 1/5] lavu: add av_dynarray_alloc_elem().
> Date: Sun, 14 Apr 2013 03:07:54 +0200
> ---
>  doc/APIchanges      |    3 +++
>  libavutil/mem.c     |   32 ++++++++++++++++++++++++++++++++
>  libavutil/mem.h     |   25 +++++++++++++++++++++++++
>  libavutil/version.h |    2 +-
>  4 files changed, 61 insertions(+), 1 deletion(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 1c5f6d1..4e5e5bd 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -15,6 +15,9 @@ libavutil:     2012-10-22
>  
>  API changes, most recent first:
>  
> +2013-05-13 - xxxxxxx - lavu 52.31.100 - mem.h
> +  Add av_dynarray2_add().
> +
>  2013-05-12 - xxxxxxx - lavfi 3.65.100
>    Add AVFILTER_FLAG_SUPPORT_TIMELINE* filter flags.
>  
> diff --git a/libavutil/mem.c b/libavutil/mem.c
> index 9b22609..295882c 100644
> --- a/libavutil/mem.c
> +++ b/libavutil/mem.c
> @@ -270,6 +270,38 @@ fail:
>      *nb_ptr = 0;
>  }
>  
> +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
> +                       const uint8_t *elem_data)
> +{
> +    int nb = *nb_ptr, nb_alloc;
> +    uint8_t *tab = *tab_ptr;
> +
> +    if ((nb & (nb - 1)) == 0) {
> +        if (nb == 0) {
> +            nb_alloc = 1;
> +        } else {
> +            if (nb > INT_MAX / (2 * elem_size))
> +                goto fail;
> +            nb_alloc = nb * 2;
> +        }
> +        tab = av_realloc(tab, nb_alloc * elem_size);
> +        if (!tab)
> +            goto fail;
> +        *tab_ptr = tab;
> +    }
> +    *nb_ptr = nb + 1;
> +    if (elem_data)
> +        memcpy(tab + nb*elem_size, elem_data, elem_size);
> +    else if (CONFIG_MEMORY_POISONING)
> +        memset(tab + nb*elem_size, FF_MEMORY_POISON, elem_size);
> +    return tab + nb*elem_size;

Note: you could use a temporary pointer for writing tab + nb*elem_size 3
times.

> +
> +fail:
> +    av_freep(tab_ptr);
> +    *nb_ptr = 0;
> +    return NULL;
> +}
> +
>  static void fill16(uint8_t *dst, int len)
>  {
>      uint32_t v = AV_RN16(dst - 2);
> diff --git a/libavutil/mem.h b/libavutil/mem.h
> index 8433ada..233b35b 100644
> --- a/libavutil/mem.h
> +++ b/libavutil/mem.h
> @@ -215,10 +215,35 @@ void av_freep(void *ptr);
>   * @param tab_ptr pointer to the array to grow
>   * @param nb_ptr  pointer to the number of elements in the array
>   * @param elem    element to add
> + * @see av_dynarray2_add()
>   */
>  void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem);
>  
>  /**
> + * Add an element of size elem_size to a dynamic array.
> + *
> + * The array is reallocated when its number of elements reaches powers of 2.
> + * Therefore, the amortized cost of adding an element is constant.
> + *
> + * In case of success, the pointer to the array is updated in order to
> + * point to the new grown array, and the number pointed to by nb_ptr
> + * is incremented.
> + * In case of failure, the array is freed, *tab_ptr is set to NULL and
> + * *nb_ptr is set to 0.
> + *
> + * @param tab_ptr   pointer to the array to grow
> + * @param nb_ptr    pointer to the number of elements in the array
> + * @param elem_size size in bytes of the elements in the array

> + * @param elem_data pointer to the data of the element to add. If NULL, the space of
> + *                  the new added element is not filled.

"pointer to the data of the element to copy in the new allocated space. If
NULL, the new allocated space is left uninitialized."

> + * @return          pointer to the elem_size allocated space at the end of the
> + *                  array, or NULL in case of memory error
> + * @see av_dynarray_add()
> + */
> +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
> +                       const uint8_t *elem_data);
> +
> +/**
>   * Multiply two size_t values checking for overflow.
>   * @return  0 if success, AVERROR(EINVAL) if overflow.
>   */
> diff --git a/libavutil/version.h b/libavutil/version.h
> index 4d87631..f9a7040 100644
> --- a/libavutil/version.h
> +++ b/libavutil/version.h
> @@ -75,7 +75,7 @@
>   */
>  
>  #define LIBAVUTIL_VERSION_MAJOR  52
> -#define LIBAVUTIL_VERSION_MINOR  30
> +#define LIBAVUTIL_VERSION_MINOR  31
>  #define LIBAVUTIL_VERSION_MICRO 100
>  
>  #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \

LGTM otherwise.

> From 93a7ccf0d9c5d391e562303bfe2bb2168934e14c Mon Sep 17 00:00:00 2001
> From: Stefano Sabatini <stefasab at gmail.com>
> Date: Sat, 27 Apr 2013 22:46:49 +0200
> Subject: [PATCH] tools/ffeval: use av_dynarray2_add()
> 
> Simplify, increment robustness.
> ---
>  tools/ffeval.c |   33 +++++++++++++++------------------
>  1 file changed, 15 insertions(+), 18 deletions(-)
> 
> diff --git a/tools/ffeval.c b/tools/ffeval.c
> index 0fab877..49463bb 100644
> --- a/tools/ffeval.c
> +++ b/tools/ffeval.c
> @@ -24,6 +24,7 @@
>  #endif
>  
>  #include "libavutil/eval.h"
> +#include "libavutil/mem.h"
>  
>  #if !HAVE_GETOPT
>  #include "compat/getopt.c"
> @@ -47,20 +48,27 @@ static void usage(void)
>             "-p PROMPT         set output prompt\n");
>  }
>  
> -#define MAX_BLOCK_SIZE SIZE_MAX
> -
>  int main(int argc, char **argv)
>  {
> -    size_t buf_size = 256;
> -    char *buf = av_malloc(buf_size);
> +    int buf_size = 0;
> +    char *buf = NULL;
>      const char *outfilename = NULL, *infilename = NULL;
>      FILE *outfile = NULL, *infile = NULL;
>      const char *prompt = "=> ";
>      int count = 0, echo = 0;
>      int c;
>  
> -    av_max_alloc(MAX_BLOCK_SIZE);
> +#define GROW_ARRAY()                                                    \
> +    do {                                                                \

> +        av_dynarray2_add((void **)&buf, &buf_size, 1, NULL);            \
> +        if (!buf) {                                                     \

if (!av_dynarray2_add...

> +            av_log(NULL, AV_LOG_ERROR,                                  \
> +                   "Memory allocation problem occurred\n");             \
> +            return 1;                                                   \
> +        }                                                               \
> +    } while (0)
>  
> +    GROW_ARRAY();
>      while ((c = getopt(argc, argv, "ehi:o:p:")) != -1) {
>          switch (c) {
>          case 'e':
> @@ -120,19 +128,8 @@ int main(int argc, char **argv)
>              }
>              count = 0;
>          } else {
> -            if (count >= buf_size-1) {
> -                if (buf_size == MAX_BLOCK_SIZE) {
> -                    av_log(NULL, AV_LOG_ERROR, "Memory allocation problem, "
> -                           "max block size '%zd' reached\n", MAX_BLOCK_SIZE);
> -                    return 1;
> -                }
> -                buf_size = FFMIN(buf_size, MAX_BLOCK_SIZE / 2) * 2;
> -                buf = av_realloc_f((void *)buf, buf_size, 1);
> -                if (!buf) {
> -                    av_log(NULL, AV_LOG_ERROR, "Memory allocation problem occurred\n");
> -                    return 1;
> -                }
> -            }
> +            if (count >= buf_size-1)
> +                GROW_ARRAY();
>              buf[count++] = c;
>          }
>      }

Should be OK

-- 
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20130513/e1c9d2ea/attachment.asc>


More information about the ffmpeg-devel mailing list