| @@ -34,6 +34,9 @@ · 33 unmodified lines |
| 34 | 34 | #include "libavutil/rational.h" |
| 35 | 35 | #include "libavutil/samplefmt.h" |
| 36 | 36 | |
| 37 | +#define FF_INTERNAL_FIELDS 1 |
| 38 | +#include "framequeue.h" |
| 39 | + |
| 37 | 40 | #include "audio.h" |
| 38 | 41 | #include "avfilter.h" |
| 39 | 42 | #include "formats.h" |
| @@ -135,6 +138,10 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, · 95 unmodified lines |
| 135 | 138 | { |
| 136 | 139 | AVFilterLink *link; |
| 137 | 140 | |
| 141 | + av_assert0(src->graph); |
| 142 | + av_assert0(dst->graph); |
| 143 | + av_assert0(src->graph == dst->graph); |
| 144 | + |
| 138 | 145 | if (src->nb_outputs <= srcpad || dst->nb_inputs <= dstpad || |
| 139 | 146 | src->outputs[srcpad] || dst->inputs[dstpad]) |
| 140 | 147 | return AVERROR(EINVAL); |
| @@ -160,6 +167,7 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, · 19 unmodified lines |
| 160 | 167 | link->type = src->output_pads[srcpad].type; |
| 161 | 168 | av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1); |
| 162 | 169 | link->format = -1; |
| 170 | + ff_framequeue_init(&link->fifo, &src->graph->internal->frame_queues); |
| 163 | 171 | |
| 164 | 172 | return 0; |
| 165 | 173 | } |
| @@ -170,6 +178,7 @@ void avfilter_link_free(AVFilterLink **link) · 4 unmodified lines |
| 170 | 178 | return; |
| 171 | 179 | |
| 172 | 180 | av_frame_free(&(*link)->partial_buf); |
| 181 | + ff_framequeue_free(&(*link)->fifo); |
| 173 | 182 | ff_video_frame_pool_uninit((FFVideoFramePool**)&(*link)->video_frame_pool); |
| 174 | 183 | |
| 175 | 184 | av_freep(link); |
| @@ -180,16 +189,46 @@ int avfilter_link_get_channels(AVFilterLink *link) · 4 unmodified lines |
| 180 | 189 | return link->channels; |
| 181 | 190 | } |
| 182 | 191 | |
| 192 | +static void ff_filter_set_ready(AVFilterContext *filter, unsigned priority) |
| 193 | +{ |
| 194 | + filter->ready = FFMAX(filter->ready, priority); |
| 195 | +} |
| 196 | + |
| 197 | +/** |
| 198 | + * Clear frame_blocked_in on all outputs. |
| 199 | + * This is necessary whenever something changes on input. |
| 200 | + */ |
| 201 | +static void filter_unblock(AVFilterContext *filter) |
| 202 | +{ |
| 203 | + unsigned i; |
| 204 | + |
| 205 | + for (i = 0; i < filter->nb_outputs; i++) |
| 206 | + filter->outputs[i]->frame_blocked_in = 0; |
| 207 | +} |
| 208 | + |
| 209 | + |
| 183 | 210 | void ff_avfilter_link_set_in_status(AVFilterLink *link, int status, int64_t pts) |
| 184 | 211 | { |
| 185 | | − ff_avfilter_link_set_out_status(link, status, pts); |
| 212 | + if (link->status_in == status) |
| 213 | + return; |
| 214 | + av_assert0(!link->status_in); |
| 215 | + link->status_in = status; |
| 216 | + link->status_in_pts = pts; |
| 217 | + link->frame_wanted_out = 0; |
| 218 | + link->frame_blocked_in = 0; |
| 219 | + filter_unblock(link->dst); |
| 220 | + ff_filter_set_ready(link->dst, 200); |
| 186 | 221 | } |
| 187 | 222 | |
| 188 | 223 | void ff_avfilter_link_set_out_status(AVFilterLink *link, int status, int64_t pts) |
| 189 | 224 | { |
| 190 | | − link->status = status; |
| 191 | | − link->frame_wanted_in = link->frame_wanted_out = 0; |
| 192 | | − ff_update_link_current_pts(link, pts); |
| 225 | + av_assert0(!link->frame_wanted_out); |
| 226 | + av_assert0(!link->status_out); |
| 227 | + link->status_out = status; |
| 228 | + if (pts != AV_NOPTS_VALUE) |
| 229 | + ff_update_link_current_pts(link, pts); |
| 230 | + filter_unblock(link->dst); |
| 231 | + ff_filter_set_ready(link->src, 200); |
| 193 | 232 | } |
| 194 | 233 | |
| 195 | 234 | void avfilter_link_set_closed(AVFilterLink *link, int closed) |
| @@ -370,10 +409,23 @@ int ff_request_frame(AVFilterLink *link) · 174 unmodified lines |
| 370 | 409 | { |
| 371 | 410 | FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1); |
| 372 | 411 | |
| 373 | | − if (link->status) |
| 374 | | − return link->status; |
| 375 | | − link->frame_wanted_in = 1; |
| 412 | + if (link->status_out) |
| 413 | + return link->status_out; |
| 414 | + if (link->status_in) { |
| 415 | + if (ff_framequeue_queued_frames(&link->fifo)) { |
| 416 | + av_assert1(!link->frame_wanted_out); |
| 417 | + av_assert1(link->dst->ready >= 300); |
| 418 | + return 0; |
| 419 | + } else { |
| 420 | + /* Acknowledge status change. Filters using ff_request_frame() will |
| 421 | + handle the change automatically. Filters can also check the |
| 422 | + status directly but none do yet. */ |
| 423 | + ff_avfilter_link_set_out_status(link, link->status_in, link->status_in_pts); |
| 424 | + return link->status_out; |
| 425 | + } |
| 426 | + } |
| 376 | 427 | link->frame_wanted_out = 1; |
| 428 | + ff_filter_set_ready(link->src, 100); |
| 377 | 429 | return 0; |
| 378 | 430 | } |
| 379 | 431 | |
| @@ -382,22 +434,17 @@ int ff_request_frame_to_filter(AVFilterLink *link) · 2 unmodified lines |
| 382 | 434 | int ret = -1; |
| 383 | 435 | |
| 384 | 436 | FF_TPRINTF_START(NULL, request_frame_to_filter); ff_tlog_link(NULL, link, 1); |
| 385 | | − link->frame_wanted_in = 0; |
| 437 | + /* Assume the filter is blocked, let the method clear it if not */ |
| 438 | + link->frame_blocked_in = 1; |
| 386 | 439 | if (link->srcpad->request_frame) |
| 387 | 440 | ret = link->srcpad->request_frame(link); |
| 388 | 441 | else if (link->src->inputs[0]) |
| 389 | 442 | ret = ff_request_frame(link->src->inputs[0]); |
| 390 | | − if (ret == AVERROR_EOF && link->partial_buf) { |
| 391 | | − AVFrame *pbuf = link->partial_buf; |
| 392 | | − link->partial_buf = NULL; |
| 393 | | − ret = ff_filter_frame_framed(link, pbuf); |
| 394 | | − ff_avfilter_link_set_in_status(link, AVERROR_EOF, AV_NOPTS_VALUE); |
| 395 | | − link->frame_wanted_out = 0; |
| 396 | | − return ret; |
| 397 | | − } |
| 398 | 443 | if (ret < 0) { |
| 399 | | − if (ret != AVERROR(EAGAIN) && ret != link->status) |
| 444 | + if (ret != AVERROR(EAGAIN) && ret != link->status_in) |
| 400 | 445 | ff_avfilter_link_set_in_status(link, ret, AV_NOPTS_VALUE); |
| 446 | + if (ret == AVERROR_EOF) |
| 447 | + ret = 0; |
| 401 | 448 | } |
| 402 | 449 | return ret; |
| 403 | 450 | } |
| @@ -1056,11 +1103,6 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame) · 652 unmodified lines |
| 1056 | 1103 | AVFilterCommand *cmd= link->dst->command_queue; |
| 1057 | 1104 | int64_t pts; |
| 1058 | 1105 | |
| 1059 | | − if (link->status) { |
| 1060 | | − av_frame_free(&frame); |
| 1061 | | − return link->status; |
| 1062 | | − } |
| 1063 | | − |
| 1064 | 1106 | if (!(filter_frame = dst->filter_frame)) |
| 1065 | 1107 | filter_frame = default_filter_frame; |
| 1066 | 1108 | |
| @@ -1142,52 +1184,9 @@ fail: · 75 unmodified lines |
| 1142 | 1184 | return ret; |
| 1143 | 1185 | } |
| 1144 | 1186 | |
| 1145 | | −static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame) |
| 1146 | | −{ |
| 1147 | | − int insamples = frame->nb_samples, inpos = 0, nb_samples; |
| 1148 | | − AVFrame *pbuf = link->partial_buf; |
| 1149 | | − int nb_channels = av_frame_get_channels(frame); |
| 1150 | | − int ret = 0; |
| 1151 | | − |
| 1152 | | − /* Handle framing (min_samples, max_samples) */ |
| 1153 | | − while (insamples) { |
| 1154 | | − if (!pbuf) { |
| 1155 | | − AVRational samples_tb = { 1, link->sample_rate }; |
| 1156 | | − pbuf = ff_get_audio_buffer(link, link->partial_buf_size); |
| 1157 | | − if (!pbuf) { |
| 1158 | | − av_log(link->dst, AV_LOG_WARNING, |
| 1159 | | − "Samples dropped due to memory allocation failure.\n"); |
| 1160 | | − return 0; |
| 1161 | | − } |
| 1162 | | − av_frame_copy_props(pbuf, frame); |
| 1163 | | − pbuf->pts = frame->pts; |
| 1164 | | − if (pbuf->pts != AV_NOPTS_VALUE) |
| 1165 | | − pbuf->pts += av_rescale_q(inpos, samples_tb, link->time_base); |
| 1166 | | − pbuf->nb_samples = 0; |
| 1167 | | − } |
| 1168 | | − nb_samples = FFMIN(insamples, |
| 1169 | | − link->partial_buf_size - pbuf->nb_samples); |
| 1170 | | − av_samples_copy(pbuf->extended_data, frame->extended_data, |
| 1171 | | − pbuf->nb_samples, inpos, |
| 1172 | | − nb_samples, nb_channels, link->format); |
| 1173 | | − inpos += nb_samples; |
| 1174 | | − insamples -= nb_samples; |
| 1175 | | − pbuf->nb_samples += nb_samples; |
| 1176 | | − if (pbuf->nb_samples >= link->min_samples) { |
| 1177 | | − ret = ff_filter_frame_framed(link, pbuf); |
| 1178 | | − pbuf = NULL; |
| 1179 | | − } else { |
| 1180 | | − if (link->frame_wanted_out) |
| 1181 | | − link->frame_wanted_in = 1; |
| 1182 | | − } |
| 1183 | | − } |
| 1184 | | − av_frame_free(&frame); |
| 1185 | | − link->partial_buf = pbuf; |
| 1186 | | − return ret; |
| 1187 | | −} |
| 1188 | | − |
| 1189 | 1187 | int ff_filter_frame(AVFilterLink *link, AVFrame *frame) |
| 1190 | 1188 | { |
| 1189 | + int ret; |
| 1191 | 1190 | FF_TPRINTF_START(NULL, filter_frame); ff_tlog_link(NULL, link, 1); ff_tlog(NULL, " "); ff_tlog_ref(NULL, frame, 1); |
| 1192 | 1191 | |
| 1193 | 1192 | /* Consistency checks */ |
| @@ -1220,23 +1219,329 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame) · 26 unmodified lines |
| 1220 | 1219 | } |
| 1221 | 1220 | } |
| 1222 | 1221 | |
| 1223 | | − link->frame_wanted_out = 0; |
| 1222 | + link->frame_blocked_in = link->frame_wanted_out = 0; |
| 1224 | 1223 | link->frame_count_in++; |
| 1225 | | − /* Go directly to actual filtering if possible */ |
| 1226 | | − if (link->type == AVMEDIA_TYPE_AUDIO && |
| 1227 | | − link->min_samples && |
| 1228 | | − (link->partial_buf || |
| 1229 | | − frame->nb_samples < link->min_samples || |
| 1230 | | − frame->nb_samples > link->max_samples)) { |
| 1231 | | − return ff_filter_frame_needs_framing(link, frame); |
| 1232 | | − } else { |
| 1233 | | − return ff_filter_frame_framed(link, frame); |
| 1224 | + filter_unblock(link->dst); |
| 1225 | + ret = ff_framequeue_add(&link->fifo, frame); |
| 1226 | + if (ret < 0) { |
| 1227 | + av_frame_free(&frame); |
| 1228 | + return ret; |
| 1234 | 1229 | } |
| 1230 | + ff_filter_set_ready(link->dst, 300); |
| 1231 | + return 0; |
| 1232 | + |
| 1235 | 1233 | error: |
| 1236 | 1234 | av_frame_free(&frame); |
| 1237 | 1235 | return AVERROR_PATCHWELCOME; |
| 1238 | 1236 | } |
| 1239 | 1237 | |
| 1238 | +static int samples_ready(AVFilterLink *link) |
| 1239 | +{ |
| 1240 | + return ff_framequeue_queued_frames(&link->fifo) && |
| 1241 | + (ff_framequeue_queued_samples(&link->fifo) >= link->min_samples || |
| 1242 | + link->status_in); |
| 1243 | +} |
| 1244 | + |
| 1245 | +static int take_samples(AVFilterLink *link, unsigned min, unsigned max, |
| 1246 | + AVFrame **rframe) |
| 1247 | +{ |
| 1248 | + AVFrame *frame0, *frame, *buf; |
| 1249 | + unsigned nb_samples, nb_frames, i, p; |
| 1250 | + int ret; |
| 1251 | + |
| 1252 | + /* Note: this function relies on no format changes and must only be |
| 1253 | + called with enough samples. */ |
| 1254 | + av_assert1(samples_ready(link)); |
| 1255 | + frame0 = frame = ff_framequeue_peek(&link->fifo, 0); |
| 1256 | + if (frame->nb_samples >= min && frame->nb_samples < max) { |
| 1257 | + *rframe = ff_framequeue_take(&link->fifo); |
| 1258 | + return 0; |
| 1259 | + } |
| 1260 | + nb_frames = 0; |
| 1261 | + nb_samples = 0; |
| 1262 | + while (1) { |
| 1263 | + if (nb_samples + frame->nb_samples > max) { |
| 1264 | + if (nb_samples < min) |
| 1265 | + nb_samples = max; |
| 1266 | + break; |
| 1267 | + } |
| 1268 | + nb_samples += frame->nb_samples; |
| 1269 | + nb_frames++; |
| 1270 | + if (nb_frames == ff_framequeue_queued_frames(&link->fifo)) |
| 1271 | + break; |
| 1272 | + frame = ff_framequeue_peek(&link->fifo, nb_frames); |
| 1273 | + } |
| 1274 | + |
| 1275 | + buf = ff_get_audio_buffer(link, nb_samples); |
| 1276 | + if (!buf) |
| 1277 | + return AVERROR(ENOMEM); |
| 1278 | + ret = av_frame_copy_props(buf, frame0); |
| 1279 | + if (ret < 0) { |
| 1280 | + av_frame_free(&buf); |
| 1281 | + return ret; |
| 1282 | + } |
| 1283 | + buf->pts = frame0->pts; |
| 1284 | + |
| 1285 | + p = 0; |
| 1286 | + for (i = 0; i < nb_frames; i++) { |
| 1287 | + frame = ff_framequeue_take(&link->fifo); |
| 1288 | + av_samples_copy(buf->extended_data, frame->extended_data, p, 0, |
| 1289 | + frame->nb_samples, link->channels, link->format); |
| 1290 | + p += frame->nb_samples; |
| 1291 | + } |
| 1292 | + if (p < nb_samples) { |
| 1293 | + unsigned n = nb_samples - p; |
| 1294 | + frame = ff_framequeue_peek(&link->fifo, 0); |
| 1295 | + av_samples_copy(buf->extended_data, frame->extended_data, p, 0, n, |
| 1296 | + link->channels, link->format); |
| 1297 | + frame->nb_samples -= n; |
| 1298 | + av_samples_copy(frame->extended_data, frame->extended_data, 0, n, |
| 1299 | + frame->nb_samples, link->channels, link->format); |
| 1300 | + if (frame->pts != AV_NOPTS_VALUE) |
| 1301 | + frame->pts += av_rescale_q(n, av_make_q(1, link->sample_rate), link->time_base); |
| 1302 | + ff_framequeue_update_peeked(&link->fifo, 0); |
| 1303 | + ff_framequeue_skip_samples(&link->fifo, n); |
| 1304 | + } |
| 1305 | + |
| 1306 | + *rframe = buf; |
| 1307 | + return 0; |
| 1308 | +} |
| 1309 | + |
| 1310 | +int ff_filter_frame_to_filter(AVFilterLink *link) |
| 1311 | +{ |
| 1312 | + AVFrame *frame; |
| 1313 | + AVFilterContext *dst = link->dst; |
| 1314 | + int ret; |
| 1315 | + |
| 1316 | + av_assert1(ff_framequeue_queued_frames(&link->fifo)); |
| 1317 | + if (link->min_samples) { |
| 1318 | + int min = link->min_samples; |
| 1319 | + if (link->status_in) |
| 1320 | + min = FFMIN(min, ff_framequeue_queued_samples(&link->fifo)); |
| 1321 | + ret = take_samples(link, min, link->max_samples, &frame); |
| 1322 | + if (ret < 0) |
| 1323 | + return ret; |
| 1324 | + } else { |
| 1325 | + frame = ff_framequeue_take(&link->fifo); |
| 1326 | + } |
| 1327 | + /* The filter will soon have received a new frame, that may allow it to |
| 1328 | + produce one or more: unblock its outputs. */ |
| 1329 | + filter_unblock(dst); |
| 1330 | + ret = ff_filter_frame_framed(link, frame); |
| 1331 | + if (ret < 0 && ret != link->status_out) { |
| 1332 | + ff_avfilter_link_set_out_status(link, ret, AV_NOPTS_VALUE); |
| 1333 | + } else { |
| 1334 | + /* Run once again, to see if several frames were available, or if |
| 1335 | + the input status has also changed, or any other reason. */ |
| 1336 | + ff_filter_set_ready(dst, 300); |
| 1337 | + } |
| 1338 | + return ret; |
| 1339 | +} |
| 1340 | + |
| 1341 | +static int forward_status_change(AVFilterContext *filter, AVFilterLink *in) |
| 1342 | +{ |
| 1343 | + unsigned out = 0, progress = 0; |
| 1344 | + int ret; |
| 1345 | + |
| 1346 | + av_assert0(!in->status_out); |
| 1347 | + if (!filter->nb_outputs) { |
| 1348 | + /* not necessary with the current API and sinks */ |
| 1349 | + return 0; |
| 1350 | + } |
| 1351 | + while (!in->status_out) { |
| 1352 | + if (!filter->outputs[out]->status_in) { |
| 1353 | + progress++; |
| 1354 | + ret = ff_request_frame_to_filter(filter->outputs[out]); |
| 1355 | + if (ret < 0) |
| 1356 | + return ret; |
| 1357 | + } |
| 1358 | + if (++out == filter->nb_outputs) { |
| 1359 | + if (!progress) { |
| 1360 | + /* Every output already closed: input no longer interesting |
| 1361 | + (example: overlay in shortest mode, other input closed). */ |
| 1362 | + ff_avfilter_link_set_out_status(in, in->status_in, in->status_in_pts); |
| 1363 | + return 0; |
| 1364 | + } |
| 1365 | + progress = 0; |
| 1366 | + out = 0; |
| 1367 | + } |
| 1368 | + } |
| 1369 | + ff_filter_set_ready(filter, 200); |
| 1370 | + return 0; |
| 1371 | +} |
| 1372 | + |
| 1373 | +#define FFERROR_NOT_READY FFERRTAG('N','R','D','Y') |
| 1374 | + |
| 1375 | +static int ff_filter_activate_default(AVFilterContext *filter) |
| 1376 | +{ |
| 1377 | + unsigned i; |
| 1378 | + |
| 1379 | + for (i = 0; i < filter->nb_inputs; i++) { |
| 1380 | + if (samples_ready(filter->inputs[i])) { |
| 1381 | + return ff_filter_frame_to_filter(filter->inputs[i]); |
| 1382 | + } |
| 1383 | + } |
| 1384 | + for (i = 0; i < filter->nb_inputs; i++) { |
| 1385 | + if (filter->inputs[i]->status_in && !filter->inputs[i]->status_out) { |
| 1386 | + av_assert1(!ff_framequeue_queued_frames(&filter->inputs[i]->fifo)); |
| 1387 | + return forward_status_change(filter, filter->inputs[i]); |
| 1388 | + } |
| 1389 | + } |
| 1390 | + for (i = 0; i < filter->nb_outputs; i++) { |
| 1391 | + if (filter->outputs[i]->frame_wanted_out && |
| 1392 | + !filter->outputs[i]->frame_blocked_in) { |
| 1393 | + return ff_request_frame_to_filter(filter->outputs[i]); |
| 1394 | + } |
| 1395 | + } |
| 1396 | + return FFERROR_NOT_READY; |
| 1397 | +} |
| 1398 | + |
| 1399 | +/* |
| 1400 | + Filter scheduling and activation |
| 1401 | + |
| 1402 | + When a filter is activated, it must: |
| 1403 | + - if possible, output a frame; |
| 1404 | + - else, if relevant, forward the input status change; |
| 1405 | + - else, check outputs for wanted frames and forward the requests. |
| 1406 | + |
| 1407 | + The following AVFilterLink fields are used for activation: |
| 1408 | + |
| 1409 | + - frame_wanted_out: |
| 1410 | + |
| 1411 | + This field indicates if a frame is needed on this input of the |
| 1412 | + destination filter. A positive value indicates that a frame is needed |
| 1413 | + to process queued frames or internal data or to satisfy the |
| 1414 | + application; a zero value indicates that a frame is not especially |
| 1415 | + needed but could be processed anyway; a negative value indicates that a |
| 1416 | + frame would just be queued. |
| 1417 | + |
| 1418 | + It is set by filters using ff_request_frame() or ff_request_no_frame(), |
| 1419 | + when requested by the application through a specific API or when it is |
| 1420 | + set on one of the outputs. |
| 1421 | + |
| 1422 | + It is cleared when a frame is sent from the source using |
| 1423 | + ff_filter_frame(). |
| 1424 | + |
| 1425 | + It is also cleared when a status change is sent from the source using |
| 1426 | + ff_avfilter_link_set_in_status(). |
| 1427 | + |
| 1428 | + - frame_blocked_in: |
| 1429 | + |
| 1430 | + This field means that the source filter can not generate a frame as is. |
| 1431 | + Its goal is to avoid repeatedly calling the request_frame() method on |
| 1432 | + the same link. |
| 1433 | + |
| 1434 | + It is set by the framework on all outputs of a filter before activating it. |
| 1435 | + |
| 1436 | + It is automatically cleared by ff_filter_frame(). |
| 1437 | + |
| 1438 | + It is also automatically cleared by ff_avfilter_link_set_in_status(). |
| 1439 | + |
| 1440 | + It is also cleared on all outputs (using filter_unblock()) when |
| 1441 | + something happens on an input: processing a frame or changing the |
| 1442 | + status. |
| 1443 | + |
| 1444 | + - fifo: |
| 1445 | + |
| 1446 | + Contains the frames queued on a filter input. If it contains frames and |
| 1447 | + frame_wanted_out is not set, then the filter can be activated. If that |
| 1448 | + result in the filter not able to use these frames, the filter must set |
| 1449 | + frame_wanted_out to ask for more frames. |
| 1450 | + |
| 1451 | + - status_in and status_in_pts: |
| 1452 | + |
| 1453 | + Status (EOF or error code) of the link and timestamp of the status |
| 1454 | + change (in link time base, same as frames) as seen from the input of |
| 1455 | + the link. The status change is considered happening after the frames |
| 1456 | + queued in fifo. |
| 1457 | + |
| 1458 | + It is set by the source filter using ff_avfilter_link_set_in_status(). |
| 1459 | + |
| 1460 | + - status_out: |
| 1461 | + |
| 1462 | + Status of the link as seen from the output of the link. The status |
| 1463 | + change is considered having already happened. |
| 1464 | + |
| 1465 | + It is set by the destination filter using |
| 1466 | + ff_avfilter_link_set_out_status(). |
| 1467 | + |
| 1468 | + Filters are activated according to the ready field, set using the |
| 1469 | + ff_filter_set_ready(). Eventually, a priority queue will be used. |
| 1470 | + ff_filter_set_ready() is called whenever anything could cause progress to |
| 1471 | + be possible. Marking a filter ready when it is not is not a problem, |
| 1472 | + except for the small overhead it causes. |
| 1473 | + |
| 1474 | + Conditions that cause a filter to be marked ready are: |
| 1475 | + |
| 1476 | + - frames added on an input link; |
| 1477 | + |
| 1478 | + - changes in the input or output status of an input link; |
| 1479 | + |
| 1480 | + - requests for a frame on an output link; |
| 1481 | + |
| 1482 | + - after any actual processing using the legacy methods (filter_frame(), |
| 1483 | + and request_frame() to acknowledge status changes), to run once more |
| 1484 | + and check if enough input was present for several frames. |
| 1485 | + |
| 1486 | + Exemples of scenarios to consider: |
| 1487 | + |
| 1488 | + - buffersrc: activate if frame_wanted_out to notify the application; |
| 1489 | + activate when the application adds a frame to push it immediately. |
| 1490 | + |
| 1491 | + - testsrc: activate only if frame_wanted_out to produce and push a frame. |
| 1492 | + |
| 1493 | + - concat (not at stitch points): can process a frame on any output. |
| 1494 | + Activate if frame_wanted_out on output to forward on the corresponding |
| 1495 | + input. Activate when a frame is present on input to process it |
| 1496 | + immediately. |
| 1497 | + |
| 1498 | + - framesync: needs at least one frame on each input; extra frames on the |
| 1499 | + wrong input will accumulate. When a frame is first added on one input, |
| 1500 | + set frame_wanted_out<0 on it to avoid getting more (would trigger |
| 1501 | + testsrc) and frame_wanted_out>0 on the other to allow processing it. |
| 1502 | + |
| 1503 | + Activation of old filters: |
| 1504 | + |
| 1505 | + In order to activate a filter implementing the legacy filter_frame() and |
| 1506 | + request_frame() methods, perform the first possible of the following |
| 1507 | + actions: |
| 1508 | + |
| 1509 | + - If an input has frames in fifo and frame_wanted_out == 0, dequeue a |
| 1510 | + frame and call filter_frame(). |
| 1511 | + |
| 1512 | + Ratinale: filter frames as soon as possible instead of leaving them |
| 1513 | + queued; frame_wanted_out < 0 is not possible since the old API does not |
| 1514 | + set it nor provides any similar feedback; frame_wanted_out > 0 happens |
| 1515 | + when min_samples > 0 and there are not enough samples queued. |
| 1516 | + |
| 1517 | + - If an input has status_in set but not status_out, try to call |
| 1518 | + request_frame() on one of the outputs in the hope that it will trigger |
| 1519 | + request_frame() on the input with status_in and acknowledge it. This is |
| 1520 | + awkward and fragile, filters with several inputs or outputs should be |
| 1521 | + updated to direct activation as soon as possible. |
| 1522 | + |
| 1523 | + - If an output has frame_wanted_out > 0 and not frame_blocked_in, call |
| 1524 | + request_frame(). |
| 1525 | + |
| 1526 | + Rationale: checking frame_blocked_in is necessary to avoid requesting |
| 1527 | + repeatedly on a blocked input if another is not blocked (example: |
| 1528 | + [buffersrc1][testsrc1][buffersrc2][testsrc2]concat=v=2). |
| 1529 | + |
| 1530 | + TODO: respect needs_fifo and remove auto-inserted fifos. |
| 1531 | + |
| 1532 | + */ |
| 1533 | + |
| 1534 | +int ff_filter_activate(AVFilterContext *filter) |
| 1535 | +{ |
| 1536 | + int ret; |
| 1537 | + |
| 1538 | + filter->ready = 0; |
| 1539 | + ret = ff_filter_activate_default(filter); |
| 1540 | + if (ret == FFERROR_NOT_READY) |
| 1541 | + ret = 0; |
| 1542 | + return ret; |
| 1543 | +} |
| 1544 | + |
| 1240 | 1545 | const AVClass *avfilter_get_class(void) |
| 1241 | 1546 | { |
| 1242 | 1547 | return &avfilter_class; |