[FFmpeg-devel] [PATCH 3/8] avfilter: keep a list of sink links by age.

Nicolas George nicolas.george at normalesup.org
Fri Apr 20 12:31:42 CEST 2012


The data structure is currently a doubly-linked list
kept sorted using a bubble-sort.
It can be changed into a binary heap using
the same fields in the public structures.

Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
---
 libavfilter/avfilter.c      |   32 ++++++++++++++++++++++++++++++++
 libavfilter/avfilter.h      |   18 ++++++++++++++++++
 libavfilter/avfiltergraph.c |   12 +++++++++++-
 libavfilter/avfiltergraph.h |    9 +++++++++
 4 files changed, 70 insertions(+), 1 deletions(-)

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 28c2599..e4e5b97 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -278,6 +278,8 @@ int avfilter_config_links(AVFilterContext *filter)
 
         if (!link) continue;
 
+        link->current_pts = AV_NOPTS_VALUE;
+
         switch (link->init_state) {
         case AVLINK_INIT:
             continue;
@@ -568,6 +570,34 @@ int avfilter_poll_frame(AVFilterLink *link)
     return min;
 }
 
+static void swap_links(AVFilterLink *a, AVFilterLink *b)
+{
+    a->next_by_age[1] = b->next_by_age[1];
+    b->next_by_age[0] = a->next_by_age[0];
+    if (a->next_by_age[1])
+        a->next_by_age[1]->next_by_age[0] = a;
+    if (b->next_by_age[0])
+        b->next_by_age[0]->next_by_age[1] = b;
+    else if (b->graph && b->graph->oldest_sink_link == a)
+        b->graph->oldest_sink_link = b;
+    b->next_by_age[1] = a;
+    a->next_by_age[0] = b;
+}
+
+static void update_link_current_pts(AVFilterLink *link)
+{
+    if (link->cur_buf->pts == AV_NOPTS_VALUE)
+        return;
+    link->current_pts = av_rescale_q(link->cur_buf->pts, link->time_base,
+                                                         AV_TIME_BASE_Q);;
+    while (link->next_by_age[1] &&
+           link->next_by_age[1]->current_pts < link->current_pts)
+        swap_links(link, link->next_by_age[1]);
+    while (link->next_by_age[0] &&
+           link->next_by_age[0]->current_pts > link->current_pts)
+        swap_links(link->next_by_age[0], link);
+}
+
 /* XXX: should we do the duplicating of the picture ref here, instead of
  * forcing the source filter to do it? */
 void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
@@ -608,6 +638,7 @@ void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
     }
 
     start_frame(link, link->cur_buf);
+    update_link_current_pts(link);
 }
 
 void avfilter_end_frame(AVFilterLink *link)
@@ -712,6 +743,7 @@ void avfilter_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
         link->cur_buf = samplesref;
 
     filter_samples(link, link->cur_buf);
+    update_link_current_pts(link);
 }
 
 #define MAX_REGISTERED_AVFILTERS_NB 128
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 5964397..93a70d8 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -696,6 +696,24 @@ struct AVFilterLink {
      */
     struct AVFilterGraph *graph;
 
+    /**
+     * Current timestamp of the link, as defined by the most recent
+     * frame(s), in AV_TIME_BASE units.
+     */
+    int64_t current_pts;
+
+    /**
+     * Private fields
+     *
+     * The following fields are for internal use only.
+     * Their type, offset, number and semantic can change without notice.
+     */
+
+    /**
+     * Pointers to links allowing an access by age.
+     * For internal use, the exact contents may change without notice.
+     */
+    struct AVFilterLink *next_by_age[2];
 };
 
 /**
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index e46ace5..b5a8171 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -377,8 +377,9 @@ int ff_avfilter_graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
 static void ff_avfilter_graph_config_pointers(AVFilterGraph *graph,
                                               AVClass *log_ctx)
 {
-    unsigned i, j;;
+    unsigned i, j;
     AVFilterContext *f;
+    AVFilterLink **tail = &graph->oldest_sink_link, *prev = NULL;
 
     for (i = 0; i < graph->filter_count; i++) {
         f = graph->filters[i];
@@ -386,7 +387,16 @@ static void ff_avfilter_graph_config_pointers(AVFilterGraph *graph,
             f->inputs[j]->graph = graph;
         for (j = 0; j < f->output_count; j++)
             f->outputs[j]->graph = graph;
+        if (!f->output_count) {
+            for (j = 0; j < f->input_count; j++) {
+                f->inputs[j]->next_by_age[0] = prev;
+                *tail = f->inputs[j];
+                prev = f->inputs[j];
+                tail = &prev->next_by_age[1];
+            }
+        }
     }
+    *tail = NULL;
 }
 
 int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
diff --git a/libavfilter/avfiltergraph.h b/libavfilter/avfiltergraph.h
index 2c612b4..ef82da9 100644
--- a/libavfilter/avfiltergraph.h
+++ b/libavfilter/avfiltergraph.h
@@ -33,6 +33,15 @@ typedef struct AVFilterGraph {
     AVFilterContext **filters;
 
     char *scale_sws_opts; ///< sws options to use for the auto-inserted scale filters
+
+    /**
+     * Private fields
+     *
+     * The following fields are for internal use only.
+     * Their type, offset, number and semantic can change without notice.
+     */
+
+    AVFilterLink *oldest_sink_link;
 } AVFilterGraph;
 
 /**
-- 
1.7.2.5



More information about the ffmpeg-devel mailing list