@ -23,14 +23,17 @@
* buffer video sink
*/
# include "libavutil/fifo.h"
# include "avfilter.h"
# include "vsink_buffer.h"
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
} BufferSinkContext ;
# define FIFO_INIT_SIZE 8
static av_cold int init ( AVFilterContext * ctx , const char * args , void * opaque )
{
BufferSinkContext * buf = ctx - > priv ;
@ -40,6 +43,12 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
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 ;
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 )
{
BufferSinkContext * buf = ctx - > priv ;
if ( buf - > picref )
avfilter_unref_buffer ( buf - > picref ) ;
buf - > picref = NULL ;
AVFilterBufferRef * picref ;
if ( buf - > fifo ) {
while ( av_fifo_size ( buf - > fifo ) > = sizeof ( AVFilterBufferRef * ) ) {
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 )
{
AVFilterContext * ctx = inlink - > dst ;
BufferSinkContext * buf = inlink - > dst - > priv ;
if ( buf - > picref ) /* drop the last cached frame */
avfilter_unref_buffer ( buf - > picref ) ;
buf - > picref = inlink - > cur_buf ;
if ( av_fifo_space ( buf - > fifo ) < sizeof ( AVFilterBufferRef * ) ) {
/* realloc fifo size */
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 )
@ -79,17 +105,18 @@ int av_vsink_buffer_get_video_buffer_ref(AVFilterContext *ctx,
* picref = NULL ;
/* no picref available, fetch it from the filterchain */
if ( ! buf - > picref ) {
if ( ! av_fifo_size ( buf - > fifo ) ) {
if ( ( ret = avfilter_request_frame ( inlink ) ) < 0 )
return ret ;
}
if ( ! buf - > picref )
if ( ! av_fifo_size ( buf - > fifo ) )
return AVERROR ( EINVAL ) ;
* picref = buf - > picref ;
if ( ! ( flags & AV_VSINK_BUF_FLAG_PEEK ) )
buf - > picref = NULL ;
if ( flags & AV_VSINK_BUF_FLAG_PEEK )
* picref = ( AVFilterBufferRef * ) av_fifo_peek2 ( buf - > fifo , 0 ) ;
else
av_fifo_generic_read ( buf - > fifo , picref , sizeof ( * picref ) , NULL ) ;
return 0 ;
}