mirror of
https://github.com/xenia-project/FFmpeg.git
synced 2024-11-27 13:30:45 +00:00
lavfi: use a video frame pool for each link of the filtergraph
This commit is contained in:
parent
04cc4d0550
commit
0c59d40ae0
@ -17,6 +17,7 @@ OBJS = allfilters.o \
|
||||
drawutils.o \
|
||||
fifo.o \
|
||||
formats.o \
|
||||
framepool.o \
|
||||
graphdump.o \
|
||||
graphparser.o \
|
||||
opencl_allkernels.o \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
189
libavfilter/framepool.c
Normal 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
84
libavfilter/framepool.h
Normal 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 */
|
@ -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"
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user