1/* 2 * Copyright (c) 2008-2010 Stefano Sabatini 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include <unistd.h> /* getopt */ 22 23#undef HAVE_AV_CONFIG_H 24#include "libavutil/pixdesc.h" 25#include "libavfilter/graphparser.h" 26 27static void usage(void) 28{ 29 printf("Convert a libavfilter graph to a dot file\n"); 30 printf("Usage: graph2dot [OPTIONS]\n"); 31 printf("\n" 32 "Options:\n" 33 "-i INFILE set INFILE as input file, stdin if omitted\n" 34 "-o OUTFILE set OUTFILE as output file, stdout if omitted\n" 35 "-h print this help\n"); 36} 37 38struct line { 39 char data[256]; 40 struct line *next; 41}; 42 43static void print_digraph(FILE *outfile, AVFilterGraph *graph) 44{ 45 int i, j; 46 47 fprintf(outfile, "digraph G {\n"); 48 fprintf(outfile, "node [shape=box]\n"); 49 fprintf(outfile, "rankdir=LR\n"); 50 51 for (i = 0; i < graph->filter_count; i++) { 52 char filter_ctx_label[128]; 53 const AVFilterContext *filter_ctx = graph->filters[i]; 54 55 snprintf(filter_ctx_label, sizeof(filter_ctx_label), "%s (%s)", 56 filter_ctx->name, 57 filter_ctx->filter->name); 58 59 for (j = 0; j < filter_ctx->output_count; j++) { 60 AVFilterLink *link = filter_ctx->outputs[j]; 61 if (link) { 62 char dst_filter_ctx_label[128]; 63 const AVFilterContext *dst_filter_ctx = link->dst; 64 65 snprintf(dst_filter_ctx_label, sizeof(dst_filter_ctx_label), "%s (%s)", 66 dst_filter_ctx->name, 67 dst_filter_ctx->filter->name); 68 69 fprintf(outfile, "\"%s\" -> \"%s\"", filter_ctx_label, dst_filter_ctx_label); 70 fprintf(outfile, " [ label= \"fmt:%s w:%d h:%d\"];\n", 71 av_pix_fmt_descriptors[link->format].name, link->w, link->h); 72 } 73 } 74 } 75 fprintf(outfile, "}\n"); 76} 77 78int main(int argc, char **argv) 79{ 80 const char *outfilename = NULL; 81 const char *infilename = NULL; 82 FILE *outfile = NULL; 83 FILE *infile = NULL; 84 char *graph_string = NULL; 85 AVFilterGraph *graph = av_mallocz(sizeof(AVFilterGraph)); 86 char c; 87 88 av_log_set_level(AV_LOG_DEBUG); 89 90 while ((c = getopt(argc, argv, "hi:o:")) != -1) { 91 switch(c) { 92 case 'h': 93 usage(); 94 return 0; 95 case 'i': 96 infilename = optarg; 97 break; 98 case 'o': 99 outfilename = optarg; 100 break; 101 case '?': 102 return 1; 103 } 104 } 105 106 if (!infilename || !strcmp(infilename, "-")) 107 infilename = "/dev/stdin"; 108 infile = fopen(infilename, "r"); 109 if (!infile) { 110 fprintf(stderr, "Impossible to open input file '%s': %s\n", infilename, strerror(errno)); 111 return 1; 112 } 113 114 if (!outfilename || !strcmp(outfilename, "-")) 115 outfilename = "/dev/stdout"; 116 outfile = fopen(outfilename, "w"); 117 if (!outfile) { 118 fprintf(stderr, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno)); 119 return 1; 120 } 121 122 /* read from infile and put it in a buffer */ 123 { 124 unsigned int count = 0; 125 struct line *line, *last_line, *first_line; 126 char *p; 127 last_line = first_line = av_malloc(sizeof(struct line)); 128 129 while (fgets(last_line->data, sizeof(last_line->data), infile)) { 130 struct line *new_line = av_malloc(sizeof(struct line)); 131 count += strlen(last_line->data); 132 last_line->next = new_line; 133 last_line = new_line; 134 } 135 last_line->next = NULL; 136 137 graph_string = av_malloc(count + 1); 138 p = graph_string; 139 for (line = first_line; line->next; line = line->next) { 140 unsigned int l = strlen(line->data); 141 memcpy(p, line->data, l); 142 p += l; 143 } 144 *p = '\0'; 145 } 146 147 avfilter_register_all(); 148 149 if (avfilter_graph_parse(graph, graph_string, NULL, NULL, NULL) < 0) { 150 fprintf(stderr, "Impossible to parse the graph description\n"); 151 return 1; 152 } 153 154 if (avfilter_graph_check_validity(graph, NULL) || 155 avfilter_graph_config_formats(graph, NULL) || 156 avfilter_graph_config_links (graph, NULL)) 157 return 1; 158 159 print_digraph(outfile, graph); 160 fflush(outfile); 161 162 return 0; 163} 164