Metaframes are frames without data, identified by a negative format code, used to carry special conditions. They are sent only to filter that declare supporting them.
The only metaframe for now is EOF; this mechanism augments the current mechanism based on request_frame() returning AVERROR_EOF, with the advantage that the EOF metaframe carries a timestamp. The API has also the advantage to work in push-only mode if all the filters in the chain support metaframes. The metaframes are a purely internal API and do not leak to the application. Signed-off-by: Nicolas George <geo...@nsup.org> --- libavfilter/avfilter.c | 73 +++++++++++++++++++++++++++++++++++++++++++++----- libavfilter/internal.h | 34 +++++++++++++++++++++++ 2 files changed, 100 insertions(+), 7 deletions(-) TODO: find a way of forwarding the EOF, and hopefully the timestamp for filters that do not support metaframes. Possibly triggering a request_frame on filters that have exactly one output would help. diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 7b11467..d3fbe56 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -346,15 +346,16 @@ int ff_request_frame(AVFilterLink *link) ret = link->srcpad->request_frame(link); else if (link->src->inputs[0]) ret = ff_request_frame(link->src->inputs[0]); - if (ret == AVERROR_EOF && link->partial_buf) { - AVFrame *pbuf = link->partial_buf; - link->partial_buf = NULL; - ret = ff_filter_frame_framed(link, pbuf); - } if (ret < 0) { + if (!link->frame_requested) { + av_assert0(ret == AVERROR_EOF); + ret = 0; + } link->frame_requested = 0; - if (ret == AVERROR_EOF) - link->closed = 1; + if (ret == AVERROR_EOF) { + ret = ff_filter_link_close(link, AV_NOPTS_VALUE); + return ret < 0 ? ret : AVERROR_EOF; + } } else { av_assert0(!link->frame_requested || link->flags & FF_LINK_FLAG_REQUEST_LOOP); @@ -1132,10 +1133,52 @@ static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame) return ret; } +static int ff_filter_metaframe(AVFilterLink *link, AVFrame *frame) +{ + AVFrame *pbuf = link->partial_buf; + int ret = 0; + + if (pbuf) { + link->partial_buf = NULL; + if ((ret = ff_filter_frame_framed(link, pbuf)) < 0) + return ret; + } + + if ((link->dst->filter->flags & FF_FILTER_FLAG_SUPPORT_METAFRAMES)) { + ret = link->dstpad->filter_frame ? + link->dstpad->filter_frame(link, frame) : + default_filter_frame(link, frame); + if (ret < 0) + return ret; + } + + switch (frame->format) { + + case FF_METAFRAME_EOF: + link->closed = 1; + break; + + case 0: + case FF_METAFRAME_NOP: + /* Not implemented yet because not used either for now. + Caveat: if the same metaframe is forwarded to the next filter + and the next filter changes the type, the type change must not be + taken into account for the first link. */ + + default: + av_assert0(!"reached"); + } + + return ret; +} + int ff_filter_frame(AVFilterLink *link, AVFrame *frame) { FF_TPRINTF_START(NULL, filter_frame); ff_tlog_link(NULL, link, 1); ff_tlog(NULL, " "); ff_tlog_ref(NULL, frame, 1); + if (frame->format < -1) + return ff_filter_metaframe(link, frame); + /* Consistency checks */ if (link->type == AVMEDIA_TYPE_VIDEO) { if (strcmp(link->dst->filter->name, "scale")) { @@ -1162,6 +1205,22 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame) } } +int ff_filter_link_close(AVFilterLink *link, int64_t pts) +{ + AVFrame *frame; + int ret; + + if (link->closed) + return 0; + if (!(frame = av_frame_alloc())) + return AVERROR(ENOMEM); + frame->format = FF_METAFRAME_EOF; + frame->pts = pts; + ret = ff_filter_frame(link, frame); + av_frame_free(&frame); + return ret; +} + const AVClass *avfilter_get_class(void) { return &avfilter_class; diff --git a/libavfilter/internal.h b/libavfilter/internal.h index 308b115..fbe603a 100644 --- a/libavfilter/internal.h +++ b/libavfilter/internal.h @@ -374,4 +374,38 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name); */ void ff_filter_graph_remove_filter(AVFilterGraph *graph, AVFilterContext *filter); +/** + * The filter can accept metaframes. + * Metaframes are AVFrame structures with a negative format field. + * The framework will take default actions based on the metaframe type. + * The destination filter is allowed to reset the type to inhibit the + * default actions. + */ +#define FF_FILTER_FLAG_SUPPORT_METAFRAMES (1 << 24) + +/** + * Types of metaframes that can be passer to a filter. + */ +enum { + /** + * Do not do anything. + * Can be used by the destination filter to inhibit default handling. + */ + FF_METAFRAME_NOP = -1, + + /** + * The input has reached EOF. + * The pts field holds the timestamp of the end of the stream, + * therefore allowing to compute the duration of the last frame. + * The frame structure still belongs to the framework and must not be + * stored by the destination filter; it also may be incomplete. + */ + FF_METAFRAME_EOF = AVERROR_EOF, +}; + +/** + * Close the link by sending the EOF metaframes to the destination filter. + */ +int ff_filter_link_close(AVFilterLink *link, int64_t pts); + #endif /* AVFILTER_INTERNAL_H */ -- 2.0.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel