lavfi: use a video frame pool for each link of the filtergraph

This commit is contained in:
Matthieu Bouron 2015-12-11 13:32:47 +01:00
parent 04cc4d0550
commit 0c59d40ae0
7 changed files with 309 additions and 14 deletions

View File

@ -17,6 +17,7 @@ OBJS = allfilters.o \
drawutils.o \
fifo.o \
formats.o \
framepool.o \
graphdump.o \
graphparser.o \
opencl_allkernels.o \

View File

@ -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);
}

View File

@ -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;
};
/**

189
libavfilter/framepool.c Normal file
View File

@ -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);
}

84
libavfilter/framepool.h Normal file
View File

@ -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 */

View File

@ -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"

View File

@ -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)