summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefano Sabatini <stefano.sabatini-lala@poste.it>2010-02-25 19:55:01 +0000
committerStefano Sabatini <stefano.sabatini-lala@poste.it>2010-02-25 19:55:01 +0000
commit11ab237e31860435816bc70739dc5a35c3078cc4 (patch)
treed92cad1be1e92947989ab064ed253ff8ef836dcf
parent9c16add67b0692e89feb2707d3159a2924470c4c (diff)
Add the graph2dot tools and document it.
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
-rw-r--r--doc/libavfilter.texi28
-rw-r--r--libavfilter/Makefile2
-rw-r--r--tools/graph2dot.c163
3 files changed, 193 insertions, 0 deletions
diff --git a/doc/libavfilter.texi b/doc/libavfilter.texi
index 5bb5235898..32bf10fd9a 100644
--- a/doc/libavfilter.texi
+++ b/doc/libavfilter.texi
@@ -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
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index fd95e35c80..904cceffd0 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -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
index 0000000000..57a25a73cb
--- /dev/null
+++ b/tools/graph2dot.c
@@ -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;
+}