graph2dot.c 5.85 KB
Newer Older
1 2 3
/*
 * Copyright (c) 2008-2010 Stefano Sabatini
 *
4
 * This file is part of Libav.
5
 *
6
 * Libav is free software; you can redistribute it and/or
7 8 9 10
 * 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.
 *
11
 * Libav is distributed in the hope that it will be useful,
12 13 14 15 16
 * 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
17
 * License along with Libav; if not, write to the Free Software
18 19 20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

21 22
#include "config.h"
#if HAVE_UNISTD_H
23
#include <unistd.h>             /* getopt */
24
#endif
25 26
#include <stdio.h>
#include <string.h>
27

28
#include "libavutil/mem.h"
29
#include "libavutil/pixdesc.h"
30
#include "libavutil/audioconvert.h"
31
#include "libavfilter/avfilter.h"
32

33 34 35 36
#if !HAVE_GETOPT
#include "compat/getopt.c"
#endif

37 38
static void usage(void)
{
39
    printf("Convert a libavfilter graph to a dot file.\n");
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    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;

75 76
                snprintf(dst_filter_ctx_label, sizeof(dst_filter_ctx_label),
                         "%s (%s)",
77 78 79
                         dst_filter_ctx->name,
                         dst_filter_ctx->filter->name);

80 81
                fprintf(outfile, "\"%s\" -> \"%s\"",
                        filter_ctx_label, dst_filter_ctx_label);
82
                if (link->type == AVMEDIA_TYPE_VIDEO) {
83
                    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
84 85
                    fprintf(outfile,
                            " [ label= \"fmt:%s w:%d h:%d tb:%d/%d\" ]",
86
                            desc->name, link->w, link->h, link->time_base.num,
87
                            link->time_base.den);
88 89
                } else if (link->type == AVMEDIA_TYPE_AUDIO) {
                    char buf[255];
90 91 92
                    av_get_channel_layout_string(buf, sizeof(buf), -1,
                                                 link->channel_layout);
                    fprintf(outfile,
93
                            " [ label= \"fmt:%s sr:%d cl:%s\" ]",
94 95 96 97
                            av_get_sample_fmt_name(link->format),
                            link->sample_rate, buf);
                }
                fprintf(outfile, ";\n");
98 99 100 101 102 103 104 105 106
            }
        }
    }
    fprintf(outfile, "}\n");
}

int main(int argc, char **argv)
{
    const char *outfilename = NULL;
107 108 109 110
    const char *infilename  = NULL;
    FILE *outfile           = NULL;
    FILE *infile            = NULL;
    char *graph_string      = NULL;
111 112 113 114 115 116
    AVFilterGraph *graph = av_mallocz(sizeof(AVFilterGraph));
    char c;

    av_log_set_level(AV_LOG_DEBUG);

    while ((c = getopt(argc, argv, "hi:o:")) != -1) {
117
        switch (c) {
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
        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) {
136
        fprintf(stderr, "Failed to open input file '%s': %s\n",
137
                infilename, strerror(errno));
138 139 140 141 142 143 144
        return 1;
    }

    if (!outfilename || !strcmp(outfilename, "-"))
        outfilename = "/dev/stdout";
    outfile = fopen(outfilename, "w");
    if (!outfile) {
145
        fprintf(stderr, "Failed to open output file '%s': %s\n",
146
                outfilename, strerror(errno));
147 148 149 150 151 152 153 154 155 156 157 158 159 160
        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;
161
            last_line       = new_line;
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
        }
        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) {
178
        fprintf(stderr, "Failed to parse the graph description\n");
179 180 181
        return 1;
    }

182
    if (avfilter_graph_config(graph, NULL) < 0)
183 184 185 186 187 188 189
        return 1;

    print_digraph(outfile, graph);
    fflush(outfile);

    return 0;
}