Messaages are passed as frames with a negative format code, only to filter that declare supporting them. The only message for now is EOF; this mechanism augments the current mechanism based on request_frame() returning AVERROR_EOF, with the advantage that the EOF message carries a timestamp. The messages are a purely internal API and do not leak to the application.
Signed-off-by: Nicolas George <geo...@nsup.org> --- libavfilter/avfilter.c | 68 ++++++++++++++++++++++++++++++++++++++++++++------ libavfilter/internal.h | 34 +++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 7 deletions(-) diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index 7b11467..fb41e71 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_frame_message(AVFilterLink *link, AVFrame *frame) +{ + AVFrame *pbuf = link->partial_buf; + int ret; + + 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_MESSAGES)) { + 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_FRAME_MSG_EOF: + link->closed = 1; + break; + + case 0: + case FF_FRAME_MSG_NOP: + /* Not implemented yet because not used either for now. + Caveat: if the same message frame 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_frame_message(link, frame); + /* Consistency checks */ if (link->type == AVMEDIA_TYPE_VIDEO) { if (strcmp(link->dst->filter->name, "scale")) { @@ -1162,6 +1205,17 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame) } } +int ff_filter_link_close(AVFilterLink *link, int64_t pts) +{ + AVFrame frame = { }; + + if (link->closed) + return 0; + frame.format = FF_FRAME_MSG_EOF; + frame.pts = pts; + return ff_filter_frame(link, &frame); +} + const AVClass *avfilter_get_class(void) { return &avfilter_class; diff --git a/libavfilter/internal.h b/libavfilter/internal.h index 308b115..de249a4 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 messages. + */ +#define FF_FILTER_FLAG_SUPPORT_MESSAGES (1 << 24) + +/** + * Types of messages that can be passer to a filter. + * Messages are passed as AVFrame structures with a negative format field. + * The framework will take default actions based on the message type. + * The destination filter is allowed to reset the type to inhibit the + * default actions. + */ +enum { + /** + * Do not do anything. + * Can be used by the destination filter to inhibit default handling. + */ + FF_FRAME_MSG_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_FRAME_MSG_EOF = AVERROR_EOF, +}; + +/** + * Close the link by sending the EOF message 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