On Fri, Dec 11, 2015 at 1:32 PM, Matthieu Bouron <matthieu.bou...@gmail.com>
wrote:

> From: Matthieu Bouron <matthieu.bou...@stupeflix.com>
>
> ---
>  libavfilter/avfilter.c |  1 +
>  libavfilter/avfilter.h |  5 +++++
>  libavfilter/video.c    | 38 +++++++++++++++++++++++++++-----------
>  3 files changed, 33 insertions(+), 11 deletions(-)
>
> diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
> index c5c3044..bec8f81 100644
> --- a/libavfilter/avfilter.c
> +++ b/libavfilter/avfilter.c
> @@ -168,6 +168,7 @@ void avfilter_link_free(AVFilterLink **link)
>          return;
>
>      av_frame_free(&(*link)->partial_buf);
> +    av_video_frame_pool_uninit(&(*link)->video_frame_pool);
>
>      av_freep(link);
>  }
> diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
> index 7aac3cf..e7d0a65 100644
> --- a/libavfilter/avfilter.h
> +++ b/libavfilter/avfilter.h
> @@ -509,6 +509,11 @@ struct AVFilterLink {
>       * Number of past frames sent through the link.
>       */
>      int64_t frame_count;
> +
> +    /**
> +     * Video frame pool.
> +     */
> +    AVVideoFramePool *video_frame_pool;
>  };
>
>  /**
> diff --git a/libavfilter/video.c b/libavfilter/video.c
> index 0274fc1..5b0b7f9 100644
> --- a/libavfilter/video.c
> +++ b/libavfilter/video.c
> @@ -32,6 +32,8 @@
>  #include "internal.h"
>  #include "video.h"
>
> +#define BUFFER_ALIGN 32
> +
>  AVFrame *ff_null_get_video_buffer(AVFilterLink *link, int w, int h)
>  {
>      return ff_get_video_buffer(link->dst->outputs[0], w, h);
> @@ -42,21 +44,35 @@ AVFrame *ff_null_get_video_buffer(AVFilterLink *link,
> int w, int h)
>   * alloc & free cycle currently implemented. */
>  AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h)
>  {
> -    AVFrame *frame = av_frame_alloc();
> -    int ret;
> +    int pool_width = 0;
> +    int pool_height = 0;
> +    int pool_align = 0;
> +    enum AVPixelFormat pool_format = AV_PIX_FMT_NONE;
>
> -    if (!frame)
> -        return NULL;
> +    if (!link->video_frame_pool) {
> +        link->video_frame_pool =
> av_video_frame_pool_init(av_buffer_allocz, w, h,
> +                                                          link->format,
> BUFFER_ALIGN);
> +        if (!link->video_frame_pool)
> +            return NULL;
> +    } else {
> +        if (av_video_frame_pool_get_config(link->video_frame_pool,
> +                                           &pool_width, &pool_height,
> +                                           &pool_format, &pool_align) <
> 0) {
> +            return NULL;
> +        }
>
> -    frame->width  = w;
> -    frame->height = h;
> -    frame->format = link->format;
> +        if (pool_width != w || pool_height != h ||
> +            pool_format != link->format || pool_align != BUFFER_ALIGN) {
>
> -    ret = av_frame_get_buffer(frame, 32);
> -    if (ret < 0)
> -        av_frame_free(&frame);
> +            av_video_frame_pool_uninit(&link->video_frame_pool);
> +            link->video_frame_pool =
> av_video_frame_pool_init(av_buffer_allocz, w, h,
> +
> link->format, BUFFER_ALIGN);
> +            if (!link->video_frame_pool)
> +                return NULL;
> +        }
> +    }
>
> -    return frame;
> +    return av_video_frame_pool_get(link->video_frame_pool);
>  }
>
>  AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h)
> --
> 2.6.3
>
>
New patch attached. It does not rely anymore on the public AVVideoFramePool
but rather on a private FFVideoFramePool declared inside libavfilter since
I would like this API to cover both audio and video and maybe have the
ability to reconfigure itself (without the need of changing the underlying
pools if the width and height are lower than the original ones for example)
before having it public. The plan is also to factorize this code with the
one in libavcodec/FramePool as much as possible.
From a307a65bfcbde03bce21928024ab53a901cf3620 Mon Sep 17 00:00:00 2001
From: Matthieu Bouron <matthieu.bou...@stupeflix.com>
Date: Fri, 11 Dec 2015 13:32:47 +0100
Subject: [PATCH] lavfi: use a video frame pool for each link of the
 filtergraph

---
 libavfilter/Makefile    |   1 +
 libavfilter/avfilter.c  |   1 +
 libavfilter/avfilter.h  |   5 ++
 libavfilter/framepool.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavfilter/framepool.h |  84 +++++++++++++++++++++
 libavfilter/internal.h  |   1 +
 libavfilter/video.c     |  42 +++++++----
 7 files changed, 309 insertions(+), 14 deletions(-)
 create mode 100644 libavfilter/framepool.c
 create mode 100644 libavfilter/framepool.h

diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index d7a3f61..dea012a 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -17,6 +17,7 @@ OBJS = allfilters.o                                                     \
        drawutils.o                                                      \
        fifo.o                                                           \
        formats.o                                                        \
+       framepool.o                                                      \
        graphdump.o                                                      \
        graphparser.o                                                    \
        opencl_allkernels.o                                              \
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index c5c3044..5d7bc09 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -168,6 +168,7 @@ void avfilter_link_free(AVFilterLink **link)
         return;
 
     av_frame_free(&(*link)->partial_buf);
+    ff_video_frame_pool_uninit((FFVideoFramePool**)&(*link)->video_frame_pool);
 
     av_freep(link);
 }
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 7aac3cf..dca0294 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -509,6 +509,11 @@ struct AVFilterLink {
      * Number of past frames sent through the link.
      */
     int64_t frame_count;
+
+    /**
+     * A pointer to a FFVideoFramePool struct.
+     */
+    void *video_frame_pool;
 };
 
 /**
diff --git a/libavfilter/framepool.c b/libavfilter/framepool.c
new file mode 100644
index 0000000..ff3a4f7
--- /dev/null
+++ b/libavfilter/framepool.c
@@ -0,0 +1,189 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * Copyright (c) 2015 Matthieu Bouron <matthieu.bouron stupeflix.com>
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "framepool.h"
+#include "libavutil/avassert.h"
+#include "libavutil/buffer.h"
+#include "libavutil/frame.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/mem.h"
+#include "libavutil/pixfmt.h"
+
+struct FFVideoFramePool {
+
+    int width;
+    int height;
+    int format;
+    int align;
+    int linesize[4];
+    AVBufferPool *pools[4];
+
+};
+
+FFVideoFramePool *ff_video_frame_pool_init(AVBufferRef* (*alloc)(int size),
+                                           int width,
+                                           int height,
+                                           enum AVPixelFormat format,
+                                           int align)
+{
+    int i, ret;
+    FFVideoFramePool *pool;
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
+
+    if (!desc)
+        return NULL;
+
+    pool = av_mallocz(sizeof(FFVideoFramePool));
+    if (!pool)
+        return NULL;
+
+    pool->width = width;
+    pool->height = height;
+    pool->format = format;
+    pool->align = align;
+
+    if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) {
+        goto fail;
+    }
+
+    if (!pool->linesize[0]) {
+        for(i = 1; i <= align; i += i) {
+            ret = av_image_fill_linesizes(pool->linesize, pool->format,
+                                          FFALIGN(pool->width, i));
+            if (ret < 0) {
+                goto fail;
+            }
+            if (!(pool->linesize[0] & (pool->align - 1)))
+                break;
+        }
+
+        for (i = 0; i < 4 && pool->linesize[i]; i++) {
+            pool->linesize[i] = FFALIGN(pool->linesize[i], pool->align);
+        }
+    }
+
+    for (i = 0; i < 4 && pool->linesize[i]; i++) {
+        int h = FFALIGN(pool->height, 32);
+        if (i == 1 || i == 2)
+            h = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
+
+        pool->pools[i] = av_buffer_pool_init(pool->linesize[i] * h + 16 + 16 - 1,
+                                             alloc);
+        if (!pool->pools[i])
+            goto fail;
+    }
+
+    if (desc->flags & AV_PIX_FMT_FLAG_PAL ||
+        desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) {
+        pool->pools[1] = av_buffer_pool_init(AVPALETTE_SIZE, alloc);
+        if (!pool->pools[1])
+            goto fail;
+    }
+
+    return pool;
+
+fail:
+    ff_video_frame_pool_uninit(&pool);
+    return NULL;
+}
+
+int ff_video_frame_pool_get_config(FFVideoFramePool *pool,
+                                   int *width,
+                                   int *height,
+                                   enum AVPixelFormat *format,
+                                   int *align)
+{
+    if (!pool)
+        return AVERROR(EINVAL);
+
+    *width = pool->width;
+    *height = pool->height;
+    *format = pool->format;
+    *align = pool->align;
+
+    return 0;
+}
+
+
+AVFrame *ff_video_frame_pool_get(FFVideoFramePool *pool)
+{
+    int i;
+    AVFrame *frame;
+    const AVPixFmtDescriptor *desc;
+
+    frame = av_frame_alloc();
+    if (!frame) {
+        return NULL;
+    }
+
+    desc = av_pix_fmt_desc_get(pool->format);
+    if (!desc) {
+        goto fail;
+    }
+
+    frame->width = pool->width;
+    frame->height = pool->height;
+    frame->format = pool->format;
+
+    for (i = 0; i < 4; i++) {
+        frame->linesize[i] = pool->linesize[i];
+        if (!pool->pools[i])
+            break;
+
+        frame->buf[i] = av_buffer_pool_get(pool->pools[i]);
+        if (!frame->buf[i]) {
+            goto fail;
+        }
+
+        frame->data[i] = frame->buf[i]->data;
+    }
+
+    if (desc->flags & AV_PIX_FMT_FLAG_PAL ||
+        desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) {
+        enum AVPixelFormat format =
+            pool->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : pool->format;
+
+        av_assert0(frame->data[1] != NULL);
+        if (avpriv_set_systematic_pal2((uint32_t *)frame->data[1], format) < 0) {
+            goto fail;
+        }
+    }
+
+    frame->extended_data = frame->data;
+
+    return frame;
+fail:
+    av_frame_free(&frame);
+    return NULL;
+}
+
+void ff_video_frame_pool_uninit(FFVideoFramePool **pool)
+{
+    int i;
+
+    if (!pool || !*pool)
+        return;
+
+    for (i = 0; i < 4; i++) {
+        av_buffer_pool_uninit(&(*pool)->pools[i]);
+    }
+
+    av_freep(pool);
+}
diff --git a/libavfilter/framepool.h b/libavfilter/framepool.h
new file mode 100644
index 0000000..bb6bb10
--- /dev/null
+++ b/libavfilter/framepool.h
@@ -0,0 +1,84 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * Copyright (c) 2015 Matthieu Bouron <matthieu.bouron stupeflix.com>
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_FRAME_POOL_H
+#define AVUTIL_FRAME_POOL_H
+
+#include "libavutil/buffer.h"
+#include "libavutil/frame.h"
+
+/**
+ * Video frame pool. This structure is opaque and not meant to be accessed
+ * directly. It is allocated with ff_video_frame_pool_init() and freed with
+ * ff_video_frame_pool_uninit().
+ */
+typedef struct FFVideoFramePool FFVideoFramePool;
+
+/**
+ * Allocate and initialize a video frame pool.
+ *
+ * @param alloc a function that will be used to allocate new frame buffers when
+ * the pool is empty. May be NULL, then the default allocator will be used
+ * (av_buffer_alloc()).
+ * @param width width of each frame in this pool
+ * @param height height of each frame in this pool
+ * @param format format of each frame in this pool
+ * @param align buffers alignement of each frame in this pool
+ * @return newly created video frame pool on success, NULL on error.
+ */
+FFVideoFramePool *ff_video_frame_pool_init(AVBufferRef* (*alloc)(int size),
+                                           int width,
+                                           int height,
+                                           enum AVPixelFormat format,
+                                           int align);
+
+/**
+ * Deallocate the video frame pool. It is safe to call this function while
+ * some of the allocated video frame are still in use.
+ *
+ * @param pool pointer to the video frame pool to be freed. It will be set to NULL.
+ */
+void ff_video_frame_pool_uninit(FFVideoFramePool **pool);
+
+/**
+ * Get the video frame pool configuration.
+ *
+ * @param width width of each frame in this pool
+ * @param height height of each frame in this pool
+ * @param format format of each frame in this pool
+ * @param align buffers alignement of each frame in this pool
+ * @return 0 on success, a negative AVERROR otherwise.
+ */
+int ff_video_frame_pool_get_config(FFVideoFramePool *pool,
+                                   int *width,
+                                   int *height,
+                                   enum AVPixelFormat *format,
+                                   int *align);
+
+/**
+ * Allocate a new AVFrame, reussing old buffers from the pool when available.
+ * This function may be called simultaneously from multiple threads.
+ *
+ * @return a new AVFrame on success, NULL on error.
+ */
+AVFrame *ff_video_frame_pool_get(FFVideoFramePool *pool);
+
+
+#endif /* AVUTIL_FRAME_POOL_H */
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 1cc6bf3..6ae1535 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -28,6 +28,7 @@
 #include "avfilter.h"
 #include "avfiltergraph.h"
 #include "formats.h"
+#include "framepool.h"
 #include "thread.h"
 #include "version.h"
 #include "video.h"
diff --git a/libavfilter/video.c b/libavfilter/video.c
index 0274fc1..2744be6 100644
--- a/libavfilter/video.c
+++ b/libavfilter/video.c
@@ -32,31 +32,45 @@
 #include "internal.h"
 #include "video.h"
 
+#define BUFFER_ALIGN 32
+
+
 AVFrame *ff_null_get_video_buffer(AVFilterLink *link, int w, int h)
 {
     return ff_get_video_buffer(link->dst->outputs[0], w, h);
 }
 
-/* TODO: set the buffer's priv member to a context structure for the whole
- * filter chain.  This will allow for a buffer pool instead of the constant
- * alloc & free cycle currently implemented. */
 AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h)
 {
-    AVFrame *frame = av_frame_alloc();
-    int ret;
+    int pool_width = 0;
+    int pool_height = 0;
+    int pool_align = 0;
+    enum AVPixelFormat pool_format = AV_PIX_FMT_NONE;
 
-    if (!frame)
-        return NULL;
+    if (!link->video_frame_pool) {
+        link->video_frame_pool = ff_video_frame_pool_init(av_buffer_allocz, w, h,
+                                                          link->format, BUFFER_ALIGN);
+        if (!link->video_frame_pool)
+            return NULL;
+    } else {
+        if (ff_video_frame_pool_get_config(link->video_frame_pool,
+                                           &pool_width, &pool_height,
+                                           &pool_format, &pool_align) < 0) {
+            return NULL;
+        }
 
-    frame->width  = w;
-    frame->height = h;
-    frame->format = link->format;
+        if (pool_width != w || pool_height != h ||
+            pool_format != link->format || pool_align != BUFFER_ALIGN) {
 
-    ret = av_frame_get_buffer(frame, 32);
-    if (ret < 0)
-        av_frame_free(&frame);
+            ff_video_frame_pool_uninit((FFVideoFramePool **)&link->video_frame_pool);
+            link->video_frame_pool = ff_video_frame_pool_init(av_buffer_allocz, w, h,
+                                                              link->format, BUFFER_ALIGN);
+            if (!link->video_frame_pool)
+                return NULL;
+        }
+    }
 
-    return frame;
+    return ff_video_frame_pool_get(link->video_frame_pool);
 }
 
 AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h)
-- 
2.6.4

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to