The status field can carry any error code instead of just EOF. Also only update it through a wrapper function and provide a timestamp. Update the few filters that used it directly.tags/n3.0
| @@ -178,9 +178,20 @@ int avfilter_link_get_channels(AVFilterLink *link) | |||||
| return link->channels; | return link->channels; | ||||
| } | } | ||||
| void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts) | |||||
| { | |||||
| ff_avfilter_link_set_out_status(link, status, pts); | |||||
| } | |||||
| void ff_avfilter_link_set_out_status(AVFilterLink *link, int status, int64_t pts) | |||||
| { | |||||
| link->status = status; | |||||
| ff_update_link_current_pts(link, pts); | |||||
| } | |||||
| void avfilter_link_set_closed(AVFilterLink *link, int closed) | void avfilter_link_set_closed(AVFilterLink *link, int closed) | ||||
| { | { | ||||
| link->closed = closed; | |||||
| ff_avfilter_link_set_out_status(link, closed ? AVERROR_EOF : 0, AV_NOPTS_VALUE); | |||||
| } | } | ||||
| int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, | int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, | ||||
| @@ -346,8 +357,8 @@ int ff_request_frame(AVFilterLink *link) | |||||
| int ret = -1; | int ret = -1; | ||||
| FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1); | FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1); | ||||
| if (link->closed) | |||||
| return AVERROR_EOF; | |||||
| if (link->status) | |||||
| return link->status; | |||||
| if (link->srcpad->request_frame) | if (link->srcpad->request_frame) | ||||
| ret = link->srcpad->request_frame(link); | ret = link->srcpad->request_frame(link); | ||||
| else if (link->src->inputs[0]) | else if (link->src->inputs[0]) | ||||
| @@ -358,8 +369,8 @@ int ff_request_frame(AVFilterLink *link) | |||||
| ret = ff_filter_frame_framed(link, pbuf); | ret = ff_filter_frame_framed(link, pbuf); | ||||
| } | } | ||||
| if (ret < 0) { | if (ret < 0) { | ||||
| if (ret == AVERROR_EOF) | |||||
| link->closed = 1; | |||||
| if (ret != AVERROR(EAGAIN) && ret != link->status) | |||||
| ff_avfilter_link_set_in_status(link, ret, AV_NOPTS_VALUE); | |||||
| } | } | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -1005,9 +1016,9 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) | |||||
| AVFilterCommand *cmd= link->dst->command_queue; | AVFilterCommand *cmd= link->dst->command_queue; | ||||
| int64_t pts; | int64_t pts; | ||||
| if (link->closed) { | |||||
| if (link->status) { | |||||
| av_frame_free(&frame); | av_frame_free(&frame); | ||||
| return AVERROR_EOF; | |||||
| return link->status; | |||||
| } | } | ||||
| if (!(filter_frame = dst->filter_frame)) | if (!(filter_frame = dst->filter_frame)) | ||||
| @@ -490,16 +490,16 @@ struct AVFilterLink { | |||||
| int max_samples; | int max_samples; | ||||
| /** | /** | ||||
| * True if the link is closed. | |||||
| * If set, all attempts of start_frame, filter_frame or request_frame | |||||
| * will fail with AVERROR_EOF, and if necessary the reference will be | |||||
| * destroyed. | |||||
| * If request_frame returns AVERROR_EOF, this flag is set on the | |||||
| * Link status. | |||||
| * If not zero, all attempts of start_frame, filter_frame or request_frame | |||||
| * will fail with the corresponding code, and if necessary the reference | |||||
| * will be destroyed. | |||||
| * If request_frame returns an error, the status is set on the | |||||
| * corresponding link. | * corresponding link. | ||||
| * It can be set also be set by either the source or the destination | * It can be set also be set by either the source or the destination | ||||
| * filter. | * filter. | ||||
| */ | */ | ||||
| int closed; | |||||
| int status; | |||||
| /** | /** | ||||
| * Number of channels. | * Number of channels. | ||||
| @@ -134,8 +134,8 @@ int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFr | |||||
| /* no picref available, fetch it from the filterchain */ | /* no picref available, fetch it from the filterchain */ | ||||
| while (!av_fifo_size(buf->fifo)) { | while (!av_fifo_size(buf->fifo)) { | ||||
| if (inlink->closed) | |||||
| return AVERROR_EOF; | |||||
| if (inlink->status) | |||||
| return inlink->status; | |||||
| if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST) | if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST) | ||||
| return AVERROR(EAGAIN); | return AVERROR(EAGAIN); | ||||
| if ((ret = ff_request_frame(inlink)) < 0) | if ((ret = ff_request_frame(inlink)) < 0) | ||||
| @@ -59,7 +59,7 @@ inline static int push_frame(AVFilterContext *ctx) | |||||
| for (i = 0; i < ctx->nb_inputs; i++) { | for (i = 0; i < ctx->nb_inputs; i++) { | ||||
| struct FFBufQueue *q = &s->queues[i]; | struct FFBufQueue *q = &s->queues[i]; | ||||
| if (!q->available && !ctx->inputs[i]->closed) | |||||
| if (!q->available && !ctx->inputs[i]->status) | |||||
| return 0; | return 0; | ||||
| if (q->available) { | if (q->available) { | ||||
| frame = ff_bufqueue_peek(q, 0); | frame = ff_bufqueue_peek(q, 0); | ||||
| @@ -190,7 +190,7 @@ static int request_frame(AVFilterLink *outlink) | |||||
| int i, ret; | int i, ret; | ||||
| for (i = 0; i < ctx->nb_inputs; i++) { | for (i = 0; i < ctx->nb_inputs; i++) { | ||||
| if (!s->queues[i].available && !ctx->inputs[i]->closed) { | |||||
| if (!s->queues[i].available && !ctx->inputs[i]->status) { | |||||
| ret = ff_request_frame(ctx->inputs[i]); | ret = ff_request_frame(ctx->inputs[i]); | ||||
| if (ret != AVERROR_EOF) | if (ret != AVERROR_EOF) | ||||
| return ret; | return ret; | ||||
| @@ -226,6 +226,21 @@ int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg, | |||||
| void ff_update_link_current_pts(AVFilterLink *link, int64_t pts); | void ff_update_link_current_pts(AVFilterLink *link, int64_t pts); | ||||
| /** | |||||
| * Set the status field of a link from the source filter. | |||||
| * The pts should reflect the timestamp of the status change, | |||||
| * in link time base and relative to the frames timeline. | |||||
| * In particular, for AVERROR_EOF, it should reflect the | |||||
| * end time of the last frame. | |||||
| */ | |||||
| void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts); | |||||
| /** | |||||
| * Set the status field of a link from the destination filter. | |||||
| * The pts should probably be left unset (AV_NOPTS_VALUE). | |||||
| */ | |||||
| void ff_avfilter_link_set_out_status(AVFilterLink *link, int status, int64_t pts); | |||||
| void ff_command_queue_pop(AVFilterContext *filter); | void ff_command_queue_pop(AVFilterContext *filter); | ||||
| /* misc trace functions */ | /* misc trace functions */ | ||||
| @@ -77,7 +77,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) | |||||
| for (i = 0; i < ctx->nb_outputs; i++) { | for (i = 0; i < ctx->nb_outputs; i++) { | ||||
| AVFrame *buf_out; | AVFrame *buf_out; | ||||
| if (ctx->outputs[i]->closed) | |||||
| if (ctx->outputs[i]->status) | |||||
| continue; | continue; | ||||
| buf_out = av_frame_clone(frame); | buf_out = av_frame_clone(frame); | ||||
| if (!buf_out) { | if (!buf_out) { | ||||
| @@ -174,7 +174,8 @@ static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) | |||||
| drop = 0; | drop = 0; | ||||
| if (drop) { | if (drop) { | ||||
| s->eof = inlink->closed = 1; | |||||
| s->eof = 1; | |||||
| ff_avfilter_link_set_out_status(inlink, AVERROR_EOF, AV_NOPTS_VALUE); | |||||
| goto drop; | goto drop; | ||||
| } | } | ||||
| } | } | ||||
| @@ -305,7 +306,8 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) | |||||
| } | } | ||||
| if (drop) { | if (drop) { | ||||
| s->eof = inlink->closed = 1; | |||||
| s->eof = 1; | |||||
| ff_avfilter_link_set_out_status(inlink, AVERROR_EOF, AV_NOPTS_VALUE); | |||||
| goto drop; | goto drop; | ||||
| } | } | ||||
| } | } | ||||
| @@ -219,7 +219,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) | |||||
| const int idx = s->map[i]; | const int idx = s->map[i]; | ||||
| AVFrame *out; | AVFrame *out; | ||||
| if (outlink->closed) | |||||
| if (outlink->status) | |||||
| continue; | continue; | ||||
| out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | ||||