Browse code

avfiltergraph: add avfilter_graph_request_oldest().

Keep a heap of all sink links ordered by timestamps.

Nicolas George authored on 2012/04/18 18:02:22
Showing 5 changed files
... ...
@@ -278,6 +278,8 @@ int avfilter_config_links(AVFilterContext *filter)
278 278
 
279 279
         if (!link) continue;
280 280
 
281
+        link->current_pts = AV_NOPTS_VALUE;
282
+
281 283
         switch (link->init_state) {
282 284
         case AVLINK_INIT:
283 285
             continue;
... ...
@@ -568,6 +570,15 @@ int avfilter_poll_frame(AVFilterLink *link)
568 568
     return min;
569 569
 }
570 570
 
571
+static void update_link_current_pts(AVFilterLink *link)
572
+{
573
+    if (link->cur_buf->pts == AV_NOPTS_VALUE)
574
+        return;
575
+    link->current_pts =  link->cur_buf->pts; /* TODO use duration */
576
+    if (link->graph && link->age_index >= 0)
577
+        ff_avfilter_graph_update_heap(link->graph, link);
578
+}
579
+
571 580
 /* XXX: should we do the duplicating of the picture ref here, instead of
572 581
  * forcing the source filter to do it? */
573 582
 void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
... ...
@@ -608,6 +619,7 @@ void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
608 608
     }
609 609
 
610 610
     start_frame(link, link->cur_buf);
611
+    update_link_current_pts(link);
611 612
 }
612 613
 
613 614
 void avfilter_end_frame(AVFilterLink *link)
... ...
@@ -712,6 +724,7 @@ void avfilter_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
712 712
         link->cur_buf = samplesref;
713 713
 
714 714
     filter_samples(link, link->cur_buf);
715
+    update_link_current_pts(link);
715 716
 }
716 717
 
717 718
 #define MAX_REGISTERED_AVFILTERS_NB 128
... ...
@@ -696,6 +696,23 @@ struct AVFilterLink {
696 696
      */
697 697
     struct AVFilterGraph *graph;
698 698
 
699
+    /**
700
+     * Current timestamp of the link, as defined by the most recent
701
+     * frame(s), in AV_TIME_BASE units.
702
+     */
703
+    int64_t current_pts;
704
+
705
+    /**
706
+     * Private fields
707
+     *
708
+     * The following fields are for internal use only.
709
+     * Their type, offset, number and semantic can change without notice.
710
+     */
711
+
712
+    /**
713
+     * Index in the age array.
714
+     */
715
+    int age_index;
699 716
 };
700 717
 
701 718
 /**
... ...
@@ -24,6 +24,7 @@
24 24
 #include <string.h>
25 25
 
26 26
 #include "libavutil/audioconvert.h"
27
+#include "libavutil/avassert.h"
27 28
 #include "libavutil/pixdesc.h"
28 29
 #include "avfilter.h"
29 30
 #include "avfiltergraph.h"
... ...
@@ -374,19 +375,46 @@ int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
374 374
     return 0;
375 375
 }
376 376
 
377
-static void ff_avfilter_graph_config_pointers(AVFilterGraph *graph,
378
-                                              AVClass *log_ctx)
377
+static int ff_avfilter_graph_config_pointers(AVFilterGraph *graph,
378
+                                             AVClass *log_ctx)
379 379
 {
380
-    unsigned i, j;;
380
+    unsigned i, j;
381
+    int sink_links_count = 0, n = 0;
381 382
     AVFilterContext *f;
383
+    AVFilterLink **sinks;
382 384
 
383 385
     for (i = 0; i < graph->filter_count; i++) {
384 386
         f = graph->filters[i];
385
-        for (j = 0; j < f->input_count; j++)
386
-            f->inputs[j]->graph = graph;
387
-        for (j = 0; j < f->output_count; j++)
388
-            f->outputs[j]->graph = graph;
387
+        for (j = 0; j < f->input_count; j++) {
388
+            f->inputs[j]->graph     = graph;
389
+            f->inputs[j]->age_index = -1;
390
+        }
391
+        for (j = 0; j < f->output_count; j++) {
392
+            f->outputs[j]->graph    = graph;
393
+            f->outputs[j]->age_index= -1;
394
+        }
395
+        if (!f->output_count) {
396
+            if (f->input_count > INT_MAX - sink_links_count)
397
+                return AVERROR(EINVAL);
398
+            sink_links_count += f->input_count;
399
+        }
389 400
     }
401
+    sinks = av_calloc(sink_links_count, sizeof(*sinks));
402
+    if (!sinks)
403
+        return AVERROR(ENOMEM);
404
+    for (i = 0; i < graph->filter_count; i++) {
405
+        f = graph->filters[i];
406
+        if (!f->output_count) {
407
+            for (j = 0; j < f->input_count; j++) {
408
+                sinks[n] = f->inputs[j];
409
+                f->inputs[j]->age_index = n++;
410
+            }
411
+        }
412
+    }
413
+    av_assert0(n == sink_links_count);
414
+    graph->sink_links       = sinks;
415
+    graph->sink_links_count = sink_links_count;
416
+    return 0;
390 417
 }
391 418
 
392 419
 int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
... ...
@@ -399,7 +427,8 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
399 399
         return ret;
400 400
     if ((ret = ff_avfilter_graph_config_links(graphctx, log_ctx)))
401 401
         return ret;
402
-    ff_avfilter_graph_config_pointers(graphctx, log_ctx);
402
+    if ((ret = ff_avfilter_graph_config_pointers(graphctx, log_ctx)))
403
+        return ret;
403 404
 
404 405
     return 0;
405 406
 }
... ...
@@ -461,3 +490,65 @@ int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const
461 461
 
462 462
     return 0;
463 463
 }
464
+
465
+static void heap_bubble_up(AVFilterGraph *graph,
466
+                           AVFilterLink *link, int index)
467
+{
468
+    AVFilterLink **links = graph->sink_links;
469
+
470
+    while (index) {
471
+        int parent = (index - 1) >> 1;
472
+        if (links[parent]->current_pts >= link->current_pts)
473
+            break;
474
+        links[index] = links[parent];
475
+        links[index]->age_index = index;
476
+        index = parent;
477
+    }
478
+    links[index] = link;
479
+    link->age_index = index;
480
+}
481
+
482
+static void heap_bubble_down(AVFilterGraph *graph,
483
+                             AVFilterLink *link, int index)
484
+{
485
+    AVFilterLink **links = graph->sink_links;
486
+
487
+    while (1) {
488
+        int child = 2 * index + 1;
489
+        if (child >= graph->sink_links_count)
490
+            break;
491
+        if (child + 1 < graph->sink_links_count &&
492
+            links[child + 1]->current_pts < links[child]->current_pts)
493
+            child++;
494
+        if (link->current_pts < links[child]->current_pts)
495
+            break;
496
+        links[index] = links[child];
497
+        links[index]->age_index = index;
498
+        index = child;
499
+    }
500
+    links[index] = link;
501
+    link->age_index = index;
502
+}
503
+
504
+void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link)
505
+{
506
+    heap_bubble_up  (graph, link, link->age_index);
507
+    heap_bubble_down(graph, link, link->age_index);
508
+}
509
+
510
+
511
+int avfilter_graph_request_oldest(AVFilterGraph *graph)
512
+{
513
+    while (graph->sink_links_count) {
514
+        AVFilterLink *oldest = graph->sink_links[0];
515
+        int r = avfilter_request_frame(oldest);
516
+        if (r != AVERROR_EOF)
517
+            return r;
518
+        /* EOF: remove the link from the heap */
519
+        if (oldest->age_index < --graph->sink_links_count)
520
+            heap_bubble_down(graph, graph->sink_links[graph->sink_links_count],
521
+                             oldest->age_index);
522
+        oldest->age_index = -1;
523
+    }
524
+    return AVERROR_EOF;
525
+}
... ...
@@ -33,6 +33,16 @@ typedef struct AVFilterGraph {
33 33
     AVFilterContext **filters;
34 34
 
35 35
     char *scale_sws_opts; ///< sws options to use for the auto-inserted scale filters
36
+
37
+    /**
38
+     * Private fields
39
+     *
40
+     * The following fields are for internal use only.
41
+     * Their type, offset, number and semantic can change without notice.
42
+     */
43
+
44
+    AVFilterLink **sink_links;
45
+    int sink_links_count;
36 46
 } AVFilterGraph;
37 47
 
38 48
 /**
... ...
@@ -221,4 +231,18 @@ int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const
221 221
  */
222 222
 char *avfilter_graph_dump(AVFilterGraph *graph, const char *options);
223 223
 
224
+/**
225
+ * Request a frame on the oldest sink link.
226
+ *
227
+ * If the request returns AVERROR_EOF, try the next.
228
+ *
229
+ * Note that this function is not meant to be the sole scheduling mechanism
230
+ * of a filtergraph, only a convenience function to help drain a filtergraph
231
+ * in a balanced way under normal circumstances.
232
+ *
233
+ * @return  the return value of avfilter_request_frame,
234
+ *          or AVERROR_EOF of all links returned AVERROR_EOF.
235
+ */
236
+int avfilter_graph_request_oldest(AVFilterGraph *graph);
237
+
224 238
 #endif /* AVFILTER_AVFILTERGRAPH_H */
... ...
@@ -65,6 +65,11 @@ int ff_avfilter_graph_config_links(AVFilterGraph *graphctx, AVClass *log_ctx);
65 65
  */
66 66
 int ff_avfilter_graph_config_formats(AVFilterGraph *graphctx, AVClass *log_ctx);
67 67
 
68
+/**
69
+ * Update the position of a link in the age heap.
70
+ */
71
+void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link);
72
+
68 73
 /** default handler for freeing audio/video buffer when there are no references left */
69 74
 void ff_avfilter_default_free_buffer(AVFilterBuffer *buf);
70 75