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.
... | ... |
@@ -178,9 +178,20 @@ int avfilter_link_get_channels(AVFilterLink *link) |
178 | 178 |
return link->channels; |
179 | 179 |
} |
180 | 180 |
|
181 |
+void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts) |
|
182 |
+{ |
|
183 |
+ ff_avfilter_link_set_out_status(link, status, pts); |
|
184 |
+} |
|
185 |
+ |
|
186 |
+void ff_avfilter_link_set_out_status(AVFilterLink *link, int status, int64_t pts) |
|
187 |
+{ |
|
188 |
+ link->status = status; |
|
189 |
+ ff_update_link_current_pts(link, pts); |
|
190 |
+} |
|
191 |
+ |
|
181 | 192 |
void avfilter_link_set_closed(AVFilterLink *link, int closed) |
182 | 193 |
{ |
183 |
- link->closed = closed; |
|
194 |
+ ff_avfilter_link_set_out_status(link, closed ? AVERROR_EOF : 0, AV_NOPTS_VALUE); |
|
184 | 195 |
} |
185 | 196 |
|
186 | 197 |
int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, |
... | ... |
@@ -346,8 +357,8 @@ int ff_request_frame(AVFilterLink *link) |
346 | 346 |
int ret = -1; |
347 | 347 |
FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1); |
348 | 348 |
|
349 |
- if (link->closed) |
|
350 |
- return AVERROR_EOF; |
|
349 |
+ if (link->status) |
|
350 |
+ return link->status; |
|
351 | 351 |
if (link->srcpad->request_frame) |
352 | 352 |
ret = link->srcpad->request_frame(link); |
353 | 353 |
else if (link->src->inputs[0]) |
... | ... |
@@ -358,8 +369,8 @@ int ff_request_frame(AVFilterLink *link) |
358 | 358 |
ret = ff_filter_frame_framed(link, pbuf); |
359 | 359 |
} |
360 | 360 |
if (ret < 0) { |
361 |
- if (ret == AVERROR_EOF) |
|
362 |
- link->closed = 1; |
|
361 |
+ if (ret != AVERROR(EAGAIN) && ret != link->status) |
|
362 |
+ ff_avfilter_link_set_in_status(link, ret, AV_NOPTS_VALUE); |
|
363 | 363 |
} |
364 | 364 |
return ret; |
365 | 365 |
} |
... | ... |
@@ -1005,9 +1016,9 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) |
1005 | 1005 |
AVFilterCommand *cmd= link->dst->command_queue; |
1006 | 1006 |
int64_t pts; |
1007 | 1007 |
|
1008 |
- if (link->closed) { |
|
1008 |
+ if (link->status) { |
|
1009 | 1009 |
av_frame_free(&frame); |
1010 |
- return AVERROR_EOF; |
|
1010 |
+ return link->status; |
|
1011 | 1011 |
} |
1012 | 1012 |
|
1013 | 1013 |
if (!(filter_frame = dst->filter_frame)) |
... | ... |
@@ -490,16 +490,16 @@ struct AVFilterLink { |
490 | 490 |
int max_samples; |
491 | 491 |
|
492 | 492 |
/** |
493 |
- * True if the link is closed. |
|
494 |
- * If set, all attempts of start_frame, filter_frame or request_frame |
|
495 |
- * will fail with AVERROR_EOF, and if necessary the reference will be |
|
496 |
- * destroyed. |
|
497 |
- * If request_frame returns AVERROR_EOF, this flag is set on the |
|
493 |
+ * Link status. |
|
494 |
+ * If not zero, all attempts of start_frame, filter_frame or request_frame |
|
495 |
+ * will fail with the corresponding code, and if necessary the reference |
|
496 |
+ * will be destroyed. |
|
497 |
+ * If request_frame returns an error, the status is set on the |
|
498 | 498 |
* corresponding link. |
499 | 499 |
* It can be set also be set by either the source or the destination |
500 | 500 |
* filter. |
501 | 501 |
*/ |
502 |
- int closed; |
|
502 |
+ int status; |
|
503 | 503 |
|
504 | 504 |
/** |
505 | 505 |
* Number of channels. |
... | ... |
@@ -134,8 +134,8 @@ int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFr |
134 | 134 |
|
135 | 135 |
/* no picref available, fetch it from the filterchain */ |
136 | 136 |
while (!av_fifo_size(buf->fifo)) { |
137 |
- if (inlink->closed) |
|
138 |
- return AVERROR_EOF; |
|
137 |
+ if (inlink->status) |
|
138 |
+ return inlink->status; |
|
139 | 139 |
if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST) |
140 | 140 |
return AVERROR(EAGAIN); |
141 | 141 |
if ((ret = ff_request_frame(inlink)) < 0) |
... | ... |
@@ -59,7 +59,7 @@ inline static int push_frame(AVFilterContext *ctx) |
59 | 59 |
for (i = 0; i < ctx->nb_inputs; i++) { |
60 | 60 |
struct FFBufQueue *q = &s->queues[i]; |
61 | 61 |
|
62 |
- if (!q->available && !ctx->inputs[i]->closed) |
|
62 |
+ if (!q->available && !ctx->inputs[i]->status) |
|
63 | 63 |
return 0; |
64 | 64 |
if (q->available) { |
65 | 65 |
frame = ff_bufqueue_peek(q, 0); |
... | ... |
@@ -190,7 +190,7 @@ static int request_frame(AVFilterLink *outlink) |
190 | 190 |
int i, ret; |
191 | 191 |
|
192 | 192 |
for (i = 0; i < ctx->nb_inputs; i++) { |
193 |
- if (!s->queues[i].available && !ctx->inputs[i]->closed) { |
|
193 |
+ if (!s->queues[i].available && !ctx->inputs[i]->status) { |
|
194 | 194 |
ret = ff_request_frame(ctx->inputs[i]); |
195 | 195 |
if (ret != AVERROR_EOF) |
196 | 196 |
return ret; |
... | ... |
@@ -226,6 +226,21 @@ int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg, |
226 | 226 |
|
227 | 227 |
void ff_update_link_current_pts(AVFilterLink *link, int64_t pts); |
228 | 228 |
|
229 |
+/** |
|
230 |
+ * Set the status field of a link from the source filter. |
|
231 |
+ * The pts should reflect the timestamp of the status change, |
|
232 |
+ * in link time base and relative to the frames timeline. |
|
233 |
+ * In particular, for AVERROR_EOF, it should reflect the |
|
234 |
+ * end time of the last frame. |
|
235 |
+ */ |
|
236 |
+void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts); |
|
237 |
+ |
|
238 |
+/** |
|
239 |
+ * Set the status field of a link from the destination filter. |
|
240 |
+ * The pts should probably be left unset (AV_NOPTS_VALUE). |
|
241 |
+ */ |
|
242 |
+void ff_avfilter_link_set_out_status(AVFilterLink *link, int status, int64_t pts); |
|
243 |
+ |
|
229 | 244 |
void ff_command_queue_pop(AVFilterContext *filter); |
230 | 245 |
|
231 | 246 |
/* misc trace functions */ |
... | ... |
@@ -77,7 +77,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) |
77 | 77 |
for (i = 0; i < ctx->nb_outputs; i++) { |
78 | 78 |
AVFrame *buf_out; |
79 | 79 |
|
80 |
- if (ctx->outputs[i]->closed) |
|
80 |
+ if (ctx->outputs[i]->status) |
|
81 | 81 |
continue; |
82 | 82 |
buf_out = av_frame_clone(frame); |
83 | 83 |
if (!buf_out) { |
... | ... |
@@ -174,7 +174,8 @@ static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame) |
174 | 174 |
drop = 0; |
175 | 175 |
|
176 | 176 |
if (drop) { |
177 |
- s->eof = inlink->closed = 1; |
|
177 |
+ s->eof = 1; |
|
178 |
+ ff_avfilter_link_set_out_status(inlink, AVERROR_EOF, AV_NOPTS_VALUE); |
|
178 | 179 |
goto drop; |
179 | 180 |
} |
180 | 181 |
} |
... | ... |
@@ -305,7 +306,8 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame) |
305 | 305 |
} |
306 | 306 |
|
307 | 307 |
if (drop) { |
308 |
- s->eof = inlink->closed = 1; |
|
308 |
+ s->eof = 1; |
|
309 |
+ ff_avfilter_link_set_out_status(inlink, AVERROR_EOF, AV_NOPTS_VALUE); |
|
309 | 310 |
goto drop; |
310 | 311 |
} |
311 | 312 |
} |
... | ... |
@@ -219,7 +219,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) |
219 | 219 |
const int idx = s->map[i]; |
220 | 220 |
AVFrame *out; |
221 | 221 |
|
222 |
- if (outlink->closed) |
|
222 |
+ if (outlink->status) |
|
223 | 223 |
continue; |
224 | 224 |
|
225 | 225 |
out = ff_get_video_buffer(outlink, outlink->w, outlink->h); |