00001 /* 00002 * Filter graphs to bad ASCII-art 00003 * Copyright (c) 2012 Nicolas George 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include <string.h> 00023 00024 #include "libavutil/pixdesc.h" 00025 #include "avfilter.h" 00026 #include "avfiltergraph.h" 00027 00028 #define BPRINTF(...) \ 00029 cur += snprintf(cur, buf_end - FFMIN(cur, buf_end), __VA_ARGS__) 00030 00031 #define BPAD(c, l) \ 00032 do { \ 00033 if (cur < buf_end) memset(cur, c, FFMIN(l, buf_end - cur)); cur += l; \ 00034 } while (0) 00035 00036 static int snprint_link_prop(char *buf, char *buf_end, AVFilterLink *link) 00037 { 00038 char *cur = buf, *format; 00039 char layout[64]; 00040 00041 switch (link->type) { 00042 case AVMEDIA_TYPE_VIDEO: 00043 format = av_x_if_null(av_get_pix_fmt_name(link->format), "?"); 00044 BPRINTF("[%dx%d %d:%d %s]", link->w, link->h, 00045 link->sample_aspect_ratio.num, 00046 link->sample_aspect_ratio.den, 00047 format); 00048 break; 00049 00050 case AVMEDIA_TYPE_AUDIO: 00051 av_get_channel_layout_string(layout, sizeof(layout), 00052 -1, link->channel_layout); 00053 format = av_x_if_null(av_get_sample_fmt_name(link->format), "?"); 00054 BPRINTF("[%dHz %s:%s:%s]", 00055 (int)link->sample_rate, format, layout, 00056 link->planar ? "planar" : "packed"); 00057 break; 00058 00059 default: 00060 BPRINTF("?"); 00061 break; 00062 } 00063 return cur - buf; 00064 } 00065 00066 static size_t avfilter_graph_dump_to_buf(AVFilterGraph *graph, 00067 char *buf, char *buf_end) 00068 { 00069 char *cur = buf, *e; 00070 unsigned i, j, x; 00071 00072 for (i = 0; i < graph->filter_count; i++) { 00073 AVFilterContext *filter = graph->filters[i]; 00074 unsigned max_src_name = 0, max_dst_name = 0; 00075 unsigned max_in_name = 0, max_out_name = 0; 00076 unsigned max_in_fmt = 0, max_out_fmt = 0; 00077 unsigned width, height, in_indent; 00078 unsigned lname = strlen(filter->name); 00079 unsigned ltype = strlen(filter->filter->name); 00080 00081 for (j = 0; j < filter->input_count; j++) { 00082 AVFilterLink *l = filter->inputs[j]; 00083 unsigned ln = strlen(l->src->name) + 1 + strlen(l->srcpad->name); 00084 max_src_name = FFMAX(max_src_name, ln); 00085 max_in_name = FFMAX(max_in_name, strlen(l->dstpad->name)); 00086 max_in_fmt = FFMAX(max_in_fmt, snprint_link_prop(NULL, NULL, l)); 00087 } 00088 for (j = 0; j < filter->output_count; j++) { 00089 AVFilterLink *l = filter->outputs[j]; 00090 unsigned ln = strlen(l->dst->name) + 1 + strlen(l->dstpad->name); 00091 max_dst_name = FFMAX(max_dst_name, ln); 00092 max_out_name = FFMAX(max_out_name, strlen(l->srcpad->name)); 00093 max_out_fmt = FFMAX(max_out_fmt, snprint_link_prop(NULL, NULL, l)); 00094 } 00095 in_indent = max_src_name + max_in_name + max_in_fmt; 00096 in_indent += in_indent ? 4 : 0; 00097 width = FFMAX(lname + 2, ltype + 4); 00098 height = FFMAX3(2, filter->input_count, filter->output_count); 00099 BPAD(' ', in_indent); 00100 BPRINTF("+"); 00101 BPAD('-', width); 00102 BPRINTF("+\n"); 00103 for (j = 0; j < height; j++) { 00104 unsigned in_no = j - (height - filter->input_count ) / 2; 00105 unsigned out_no = j - (height - filter->output_count) / 2; 00106 00107 /* Input link */ 00108 if (in_no < filter->input_count) { 00109 AVFilterLink *l = filter->inputs[in_no]; 00110 e = cur + max_src_name + 2; 00111 BPRINTF("%s:%s", l->src->name, l->srcpad->name); 00112 BPAD('-', e - cur); 00113 e = cur + max_in_fmt + 2 + 00114 max_in_name - strlen(l->dstpad->name); 00115 cur += snprint_link_prop(cur, buf_end, l); 00116 BPAD('-', e - cur); 00117 BPRINTF("%s", l->dstpad->name); 00118 } else { 00119 BPAD(' ', in_indent); 00120 } 00121 00122 /* Filter */ 00123 BPRINTF("|"); 00124 if (j == (height - 2) / 2) { 00125 x = (width - lname) / 2; 00126 BPRINTF("%*s%-*s", x, "", width - x, filter->name); 00127 } else if (j == (height - 2) / 2 + 1) { 00128 x = (width - ltype - 2) / 2; 00129 BPRINTF("%*s(%s)%*s", x, "", filter->filter->name, 00130 width - ltype - 2 - x, ""); 00131 } else { 00132 BPAD(' ', width); 00133 } 00134 BPRINTF("|"); 00135 00136 /* Output link */ 00137 if (out_no < filter->output_count) { 00138 AVFilterLink *l = filter->outputs[out_no]; 00139 unsigned ln = strlen(l->dst->name) + 1 + 00140 strlen(l->dstpad->name); 00141 e = cur + max_out_name + 2; 00142 BPRINTF("%s", l->srcpad->name); 00143 BPAD('-', e - cur); 00144 e = cur + max_out_fmt + 2 + 00145 max_dst_name - ln; 00146 cur += snprint_link_prop(cur, buf_end, l); 00147 BPAD('-', e - cur); 00148 BPRINTF("%s:%s", l->dst->name, l->dstpad->name); 00149 } 00150 BPRINTF("\n"); 00151 } 00152 BPAD(' ', in_indent); 00153 BPRINTF("+"); 00154 BPAD('-', width); 00155 BPRINTF("+\n"); 00156 BPRINTF("\n"); 00157 } 00158 if (cur < buf_end) 00159 *(cur++) = 0; 00160 return cur - buf; 00161 } 00162 00163 char *avfilter_graph_dump(AVFilterGraph *graph, const char *options) 00164 { 00165 size_t buf_size = avfilter_graph_dump_to_buf(graph, NULL, NULL); 00166 char *buf = av_malloc(buf_size); 00167 if (!buf) 00168 return NULL; 00169 avfilter_graph_dump_to_buf(graph, buf, buf + buf_size); 00170 return buf; 00171 }