From b0012de420f20d5731b90af1f2a3e7093f2195d9 Mon Sep 17 00:00:00 2001 From: Nicolas George Date: Sun, 10 Mar 2013 13:33:18 +0100 Subject: [PATCH] lavfi/buffersrc: implement flags. The PUSH flags is necessary for efficient scheduling; otherwise there is no feedback when adding frames to closed paths. The NO_CHECK_FORMAT is a small optimization that does not cost much to implement. The KEEP_REF flag maps to the add/write distinction in the fork's API. --- libavfilter/buffersrc.c | 40 +++++++++++++++++++++++++++------------- libavfilter/buffersrc.h | 25 +++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index 6c6689b4ca..185018dfd9 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -75,14 +75,23 @@ typedef struct { return AVERROR(EINVAL);\ } -int av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags) +int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame) { - return av_buffersrc_add_frame(ctx, frame); + return av_buffersrc_add_frame_flags(ctx, (AVFrame *)frame, + AV_BUFFERSRC_FLAG_KEEP_REF); } -int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame) +int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame) { - AVFrame *copy; + return av_buffersrc_add_frame_flags(ctx, frame, 0); +} + +static int av_buffersrc_add_frame_internal(AVFilterContext *ctx, + AVFrame *frame, int flags); + +int av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags) +{ + AVFrame *copy = NULL; int ret = 0; int64_t layout = frame->channel_layout; @@ -91,22 +100,25 @@ int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame) return AVERROR(EINVAL); } + if (!(flags & AV_BUFFERSRC_FLAG_KEEP_REF) || !frame) + return av_buffersrc_add_frame_internal(ctx, frame, flags); + if (!(copy = av_frame_alloc())) return AVERROR(ENOMEM); ret = av_frame_ref(copy, frame); if (ret >= 0) - ret = av_buffersrc_add_frame(ctx, copy); + ret = av_buffersrc_add_frame_internal(ctx, copy, flags); av_frame_free(©); return ret; } -int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame) +static int av_buffersrc_add_frame_internal(AVFilterContext *ctx, + AVFrame *frame, int flags) { BufferSourceContext *s = ctx->priv; AVFrame *copy; int ret; - int64_t layout; if (!frame) { s->eof = 1; @@ -114,6 +126,8 @@ int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame) } else if (s->eof) return AVERROR(EINVAL); + if (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) { + switch (ctx->outputs[0]->type) { case AVMEDIA_TYPE_VIDEO: CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height, @@ -122,17 +136,13 @@ int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame) case AVMEDIA_TYPE_AUDIO: CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->channel_layout, frame->format); - - layout = frame->channel_layout; - if (layout && av_get_channel_layout_nb_channels(layout) != av_frame_get_channels(frame)) { - av_log(0, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n"); - return AVERROR(EINVAL); - } break; default: return AVERROR(EINVAL); } + } + if (!av_fifo_space(s->fifo) && (ret = av_fifo_realloc2(s->fifo, av_fifo_size(s->fifo) + sizeof(copy))) < 0) @@ -148,6 +158,10 @@ int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame) return ret; } + if ((flags & AV_BUFFERSRC_FLAG_PUSH)) + if ((ret = ctx->output_pads[0].request_frame(ctx->outputs[0])) < 0) + return ret; + return 0; } diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h index 3b9fd5282c..66361b3dab 100644 --- a/libavfilter/buffersrc.h +++ b/libavfilter/buffersrc.h @@ -35,16 +35,25 @@ enum { */ AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT = 1, +#if FF_API_AVFILTERBUFFER /** - * Do not copy buffer data. + * Ignored */ AV_BUFFERSRC_FLAG_NO_COPY = 2, +#endif /** * Immediately push the frame to the output. */ AV_BUFFERSRC_FLAG_PUSH = 4, + /** + * Keep a reference to the frame. + * If the frame if reference-counted, create a new reference; otherwise + * copy the frame data. + */ + AV_BUFFERSRC_FLAG_KEEP_REF = 8, + }; /** @@ -91,6 +100,9 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf); * copied. * * @return 0 on success, a negative AVERROR on error + * + * This function is equivalent to av_buffersrc_add_frame_flags() with the + * AV_BUFFERSRC_FLAG_KEEP_REF flag. */ int av_buffersrc_write_frame(AVFilterContext *s, const AVFrame *frame); @@ -108,11 +120,20 @@ int av_buffersrc_write_frame(AVFilterContext *s, const AVFrame *frame); * @note the difference between this function and av_buffersrc_write_frame() is * that av_buffersrc_write_frame() creates a new reference to the input frame, * while this function takes ownership of the reference passed to it. + * + * This function is equivalent to av_buffersrc_add_frame_flags() without the + * AV_BUFFERSRC_FLAG_KEEP_REF flag. */ int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame); /** - * Add frame data to buffer_src. XXX + * Add a frame to the buffer source. + * + * By default, if the frame is reference-counted, this function will take + * ownership of the reference(s) and reset the frame. This can be controled + * using the flags. + * + * If this function returns an error, the input frame is not touched. * * @param buffer_src pointer to a buffer source context * @param frame a frame, or NULL to mark EOF -- 2.11.0