Add the graph2dot tools and document it.
authorStefano Sabatini <stefano.sabatini-lala@poste.it>
Thu, 25 Feb 2010 19:55:01 +0000 (19:55 +0000)
committerStefano Sabatini <stefano.sabatini-lala@poste.it>
Thu, 25 Feb 2010 19:55:01 +0000 (19:55 +0000)
Also link avfiltergraph.o and graphparser.o against libavfilter, as it
uses them.

Originally committed as revision 22063 to svn://svn.ffmpeg.org/ffmpeg/trunk

doc/libavfilter.texi
libavfilter/Makefile
tools/graph2dot.c [new file with mode: 0644]

index 5bb5235..32bf10f 100644 (file)
@@ -71,6 +71,34 @@ There exist so-called @var{source filters} that do not have a video
 input, and we expect in the future some @var{sink filters} that will
 not have video output.
 
+@chapter graph2dot
+
+The @file{graph2dot} program included in the FFmpeg @file{tools}
+directory can be used to parse a filter graph description and issue a
+corresponding textual representation in the dot language.
+
+Invoke the command:
+@example
+graph2dot -h
+@end example
+
+to see how to use @file{graph2dot}.
+
+You can then pass the dot description to the @file{dot} program (from
+the graphviz suite of programs) and obtain a graphical representation
+of the filter graph.
+
+For example the sequence of commands:
+@example
+echo @var{GRAPH_DESCRIPTION} | \
+tools/graph2dot -o graph.tmp && \
+dot -Tpng graph.tmp -o graph.png && \
+display graph.png
+@end example
+
+can be used to create and display an image representing the graph
+described by the @var{GRAPH_DESCRIPTION} string.
+
 @chapter Available video filters
 
 When you configure your FFmpeg build, you can disable any of the
index fd95e35..904ccef 100644 (file)
@@ -8,8 +8,10 @@ HEADERS = avfilter.h
 
 OBJS = allfilters.o                                                     \
        avfilter.o                                                       \
+       avfiltergraph.o                                                  \
        defaults.o                                                       \
        formats.o                                                        \
+       graphparser.o                                                    \
        parseutils.o                                                     \
 
 OBJS-$(CONFIG_CROP_FILTER)                   += vf_crop.o
diff --git a/tools/graph2dot.c b/tools/graph2dot.c
new file mode 100644 (file)
index 0000000..57a25a7
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2008-2010 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>             /* getopt */
+
+#undef HAVE_AV_CONFIG_H
+#include "libavutil/pixdesc.h"
+#include "libavfilter/graphparser.h"
+
+static void usage(void)
+{
+    printf("Convert a libavfilter graph to a dot file\n");
+    printf("Usage: graph2dot [OPTIONS]\n");
+    printf("\n"
+           "Options:\n"
+           "-i INFILE         set INFILE as input file, stdin if omitted\n"
+           "-o OUTFILE        set OUTFILE as output file, stdout if omitted\n"
+           "-h                print this help\n");
+}
+
+struct line {
+    char data[256];
+    struct line *next;
+};
+
+static void print_digraph(FILE *outfile, AVFilterGraph *graph)
+{
+    int i, j;
+
+    fprintf(outfile, "digraph G {\n");
+    fprintf(outfile, "node [shape=box]\n");
+    fprintf(outfile, "rankdir=LR\n");
+
+    for (i = 0; i < graph->filter_count; i++) {
+        char filter_ctx_label[128];
+        const AVFilterContext *filter_ctx = graph->filters[i];
+
+        snprintf(filter_ctx_label, sizeof(filter_ctx_label), "%s (%s)",
+                 filter_ctx->name,
+                 filter_ctx->filter->name);
+
+        for (j = 0; j < filter_ctx->output_count; j++) {
+            AVFilterLink *link = filter_ctx->outputs[j];
+            if (link) {
+                char dst_filter_ctx_label[128];
+                const AVFilterContext *dst_filter_ctx = link->dst;
+
+                snprintf(dst_filter_ctx_label, sizeof(dst_filter_ctx_label), "%s (%s)",
+                         dst_filter_ctx->name,
+                         dst_filter_ctx->filter->name);
+
+                fprintf(outfile, "\"%s\" -> \"%s\"", filter_ctx_label, dst_filter_ctx_label);
+                fprintf(outfile, " [ label= \"fmt:%s w:%d h:%d\"];\n",
+                        av_pix_fmt_descriptors[link->format].name, link->w, link->h);
+            }
+        }
+    }
+    fprintf(outfile, "}\n");
+}
+
+int main(int argc, char **argv)
+{
+    const char *outfilename = NULL;
+    const char *infilename = NULL;
+    FILE *outfile = NULL;
+    FILE *infile = NULL;
+    char *graph_string = NULL;
+    AVFilterGraph *graph = av_mallocz(sizeof(AVFilterGraph));
+    char c;
+
+    av_log_set_level(AV_LOG_DEBUG);
+
+    while ((c = getopt(argc, argv, "hi:o:")) != -1) {
+        switch(c) {
+        case 'h':
+            usage();
+            return 0;
+        case 'i':
+            infilename = optarg;
+            break;
+        case 'o':
+            outfilename = optarg;
+            break;
+        case '?':
+            return 1;
+        }
+    }
+
+    if (!infilename || !strcmp(infilename, "-"))
+        infilename = "/dev/stdin";
+    infile = fopen(infilename, "r");
+    if (!infile) {
+        fprintf(stderr, "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
+        return 1;
+    }
+
+    if (!outfilename || !strcmp(outfilename, "-"))
+        outfilename = "/dev/stdout";
+    outfile = fopen(outfilename, "w");
+    if (!outfile) {
+        fprintf(stderr, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno));
+        return 1;
+    }
+
+    /* read from infile and put it in a buffer */
+    {
+        unsigned int count = 0;
+        struct line *line, *last_line, *first_line;
+        char *p;
+        last_line = first_line = av_malloc(sizeof(struct line));
+
+        while (fgets(last_line->data, sizeof(last_line->data), infile)) {
+            struct line *new_line = av_malloc(sizeof(struct line));
+            count += strlen(last_line->data);
+            last_line->next = new_line;
+            last_line = new_line;
+        }
+        last_line->next = NULL;
+
+        graph_string = av_malloc(count + 1);
+        p = graph_string;
+        for (line = first_line; line->next; line = line->next) {
+            unsigned int l = strlen(line->data);
+            memcpy(p, line->data, l);
+            p += l;
+        }
+        *p = '\0';
+    }
+
+    avfilter_register_all();
+
+    if (avfilter_graph_parse(graph, graph_string, NULL, NULL, NULL) < 0) {
+        fprintf(stderr, "Impossible to parse the graph description\n");
+        return 1;
+    }
+
+    if (avfilter_graph_check_validity(graph, NULL) ||
+        avfilter_graph_config_formats(graph, NULL) ||
+        avfilter_graph_config_links  (graph, NULL))
+        return 1;
+
+    print_digraph(outfile, graph);
+    fflush(outfile);
+
+    return 0;
+}