vsink_buffer: make the buffer cache all the incoming frames
Allow to cache more than one frame (e.g. for filters which return more than one frame when avfilter_request_frame() is called on them), and do not discard previously cached frames when a new one is added.
This commit is contained in:
parent
2e81bb5e92
commit
3560089e12
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
#define LIBAVFILTER_VERSION_MAJOR 2
|
#define LIBAVFILTER_VERSION_MAJOR 2
|
||||||
#define LIBAVFILTER_VERSION_MINOR 29
|
#define LIBAVFILTER_VERSION_MINOR 29
|
||||||
#define LIBAVFILTER_VERSION_MICRO 1
|
#define LIBAVFILTER_VERSION_MICRO 2
|
||||||
|
|
||||||
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
|
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
|
||||||
LIBAVFILTER_VERSION_MINOR, \
|
LIBAVFILTER_VERSION_MINOR, \
|
||||||
|
@ -23,14 +23,17 @@
|
|||||||
* buffer video sink
|
* buffer video sink
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "libavutil/fifo.h"
|
||||||
#include "avfilter.h"
|
#include "avfilter.h"
|
||||||
#include "vsink_buffer.h"
|
#include "vsink_buffer.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
AVFilterBufferRef *picref; ///< cached picref
|
AVFifoBuffer *fifo; ///< FIFO buffer of video frame references
|
||||||
enum PixelFormat *pix_fmts; ///< accepted pixel formats, must be terminated with -1
|
enum PixelFormat *pix_fmts; ///< accepted pixel formats, must be terminated with -1
|
||||||
} BufferSinkContext;
|
} BufferSinkContext;
|
||||||
|
|
||||||
|
#define FIFO_INIT_SIZE 8
|
||||||
|
|
||||||
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
|
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
|
||||||
{
|
{
|
||||||
BufferSinkContext *buf = ctx->priv;
|
BufferSinkContext *buf = ctx->priv;
|
||||||
@ -40,6 +43,12 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
|
|||||||
return AVERROR(EINVAL);
|
return AVERROR(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef *));
|
||||||
|
if (!buf->fifo) {
|
||||||
|
av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
buf->pix_fmts = opaque;
|
buf->pix_fmts = opaque;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -47,19 +56,36 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
|
|||||||
static av_cold void uninit(AVFilterContext *ctx)
|
static av_cold void uninit(AVFilterContext *ctx)
|
||||||
{
|
{
|
||||||
BufferSinkContext *buf = ctx->priv;
|
BufferSinkContext *buf = ctx->priv;
|
||||||
|
AVFilterBufferRef *picref;
|
||||||
|
|
||||||
if (buf->picref)
|
if (buf->fifo) {
|
||||||
avfilter_unref_buffer(buf->picref);
|
while (av_fifo_size(buf->fifo) >= sizeof(AVFilterBufferRef *)) {
|
||||||
buf->picref = NULL;
|
av_fifo_generic_read(buf->fifo, &picref, sizeof(picref), NULL);
|
||||||
|
avfilter_unref_buffer(picref);
|
||||||
|
}
|
||||||
|
av_fifo_free(buf->fifo);
|
||||||
|
buf->fifo = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_frame(AVFilterLink *inlink)
|
static void end_frame(AVFilterLink *inlink)
|
||||||
{
|
{
|
||||||
|
AVFilterContext *ctx = inlink->dst;
|
||||||
BufferSinkContext *buf = inlink->dst->priv;
|
BufferSinkContext *buf = inlink->dst->priv;
|
||||||
|
|
||||||
if (buf->picref) /* drop the last cached frame */
|
if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) {
|
||||||
avfilter_unref_buffer(buf->picref);
|
/* realloc fifo size */
|
||||||
buf->picref = inlink->cur_buf;
|
if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) {
|
||||||
|
av_log(ctx, AV_LOG_ERROR,
|
||||||
|
"Cannot buffer more frames. Consume some available frames "
|
||||||
|
"before adding new ones.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cache frame */
|
||||||
|
av_fifo_generic_write(buf->fifo,
|
||||||
|
&inlink->cur_buf, sizeof(AVFilterBufferRef *), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int query_formats(AVFilterContext *ctx)
|
static int query_formats(AVFilterContext *ctx)
|
||||||
@ -79,17 +105,18 @@ int av_vsink_buffer_get_video_buffer_ref(AVFilterContext *ctx,
|
|||||||
*picref = NULL;
|
*picref = NULL;
|
||||||
|
|
||||||
/* no picref available, fetch it from the filterchain */
|
/* no picref available, fetch it from the filterchain */
|
||||||
if (!buf->picref) {
|
if (!av_fifo_size(buf->fifo)) {
|
||||||
if ((ret = avfilter_request_frame(inlink)) < 0)
|
if ((ret = avfilter_request_frame(inlink)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buf->picref)
|
if (!av_fifo_size(buf->fifo))
|
||||||
return AVERROR(EINVAL);
|
return AVERROR(EINVAL);
|
||||||
|
|
||||||
*picref = buf->picref;
|
if (flags & AV_VSINK_BUF_FLAG_PEEK)
|
||||||
if (!(flags & AV_VSINK_BUF_FLAG_PEEK))
|
*picref = (AVFilterBufferRef *)av_fifo_peek2(buf->fifo, 0);
|
||||||
buf->picref = NULL;
|
else
|
||||||
|
av_fifo_generic_read(buf->fifo, picref, sizeof(*picref), NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user