yading@10: /* yading@10: * Filter graphs to bad ASCII-art yading@10: * Copyright (c) 2012 Nicolas George yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include yading@10: yading@10: #include "libavutil/channel_layout.h" yading@10: #include "libavutil/bprint.h" yading@10: #include "libavutil/pixdesc.h" yading@10: #include "avfilter.h" yading@10: #include "avfiltergraph.h" yading@10: yading@10: static int print_link_prop(AVBPrint *buf, AVFilterLink *link) yading@10: { yading@10: char *format; yading@10: char layout[64]; yading@10: yading@10: if (!buf) yading@10: buf = &(AVBPrint){ 0 }; /* dummy buffer */ yading@10: switch (link->type) { yading@10: case AVMEDIA_TYPE_VIDEO: yading@10: format = av_x_if_null(av_get_pix_fmt_name(link->format), "?"); yading@10: av_bprintf(buf, "[%dx%d %d:%d %s]", link->w, link->h, yading@10: link->sample_aspect_ratio.num, yading@10: link->sample_aspect_ratio.den, yading@10: format); yading@10: break; yading@10: yading@10: case AVMEDIA_TYPE_AUDIO: yading@10: av_get_channel_layout_string(layout, sizeof(layout), yading@10: link->channels, link->channel_layout); yading@10: format = av_x_if_null(av_get_sample_fmt_name(link->format), "?"); yading@10: av_bprintf(buf, "[%dHz %s:%s]", yading@10: (int)link->sample_rate, format, layout); yading@10: break; yading@10: yading@10: default: yading@10: av_bprintf(buf, "?"); yading@10: break; yading@10: } yading@10: return buf->len; yading@10: } yading@10: yading@10: static void avfilter_graph_dump_to_buf(AVBPrint *buf, AVFilterGraph *graph) yading@10: { yading@10: unsigned i, j, x, e; yading@10: yading@10: for (i = 0; i < graph->nb_filters; i++) { yading@10: AVFilterContext *filter = graph->filters[i]; yading@10: unsigned max_src_name = 0, max_dst_name = 0; yading@10: unsigned max_in_name = 0, max_out_name = 0; yading@10: unsigned max_in_fmt = 0, max_out_fmt = 0; yading@10: unsigned width, height, in_indent; yading@10: unsigned lname = strlen(filter->name); yading@10: unsigned ltype = strlen(filter->filter->name); yading@10: yading@10: for (j = 0; j < filter->input_count; j++) { yading@10: AVFilterLink *l = filter->inputs[j]; yading@10: unsigned ln = strlen(l->src->name) + 1 + strlen(l->srcpad->name); yading@10: max_src_name = FFMAX(max_src_name, ln); yading@10: max_in_name = FFMAX(max_in_name, strlen(l->dstpad->name)); yading@10: max_in_fmt = FFMAX(max_in_fmt, print_link_prop(NULL, l)); yading@10: } yading@10: for (j = 0; j < filter->output_count; j++) { yading@10: AVFilterLink *l = filter->outputs[j]; yading@10: unsigned ln = strlen(l->dst->name) + 1 + strlen(l->dstpad->name); yading@10: max_dst_name = FFMAX(max_dst_name, ln); yading@10: max_out_name = FFMAX(max_out_name, strlen(l->srcpad->name)); yading@10: max_out_fmt = FFMAX(max_out_fmt, print_link_prop(NULL, l)); yading@10: } yading@10: in_indent = max_src_name + max_in_name + max_in_fmt; yading@10: in_indent += in_indent ? 4 : 0; yading@10: width = FFMAX(lname + 2, ltype + 4); yading@10: height = FFMAX3(2, filter->input_count, filter->output_count); yading@10: av_bprint_chars(buf, ' ', in_indent); yading@10: av_bprintf(buf, "+"); yading@10: av_bprint_chars(buf, '-', width); yading@10: av_bprintf(buf, "+\n"); yading@10: for (j = 0; j < height; j++) { yading@10: unsigned in_no = j - (height - filter->input_count ) / 2; yading@10: unsigned out_no = j - (height - filter->output_count) / 2; yading@10: yading@10: /* Input link */ yading@10: if (in_no < filter->input_count) { yading@10: AVFilterLink *l = filter->inputs[in_no]; yading@10: e = buf->len + max_src_name + 2; yading@10: av_bprintf(buf, "%s:%s", l->src->name, l->srcpad->name); yading@10: av_bprint_chars(buf, '-', e - buf->len); yading@10: e = buf->len + max_in_fmt + 2 + yading@10: max_in_name - strlen(l->dstpad->name); yading@10: print_link_prop(buf, l); yading@10: av_bprint_chars(buf, '-', e - buf->len); yading@10: av_bprintf(buf, "%s", l->dstpad->name); yading@10: } else { yading@10: av_bprint_chars(buf, ' ', in_indent); yading@10: } yading@10: yading@10: /* Filter */ yading@10: av_bprintf(buf, "|"); yading@10: if (j == (height - 2) / 2) { yading@10: x = (width - lname) / 2; yading@10: av_bprintf(buf, "%*s%-*s", x, "", width - x, filter->name); yading@10: } else if (j == (height - 2) / 2 + 1) { yading@10: x = (width - ltype - 2) / 2; yading@10: av_bprintf(buf, "%*s(%s)%*s", x, "", filter->filter->name, yading@10: width - ltype - 2 - x, ""); yading@10: } else { yading@10: av_bprint_chars(buf, ' ', width); yading@10: } yading@10: av_bprintf(buf, "|"); yading@10: yading@10: /* Output link */ yading@10: if (out_no < filter->output_count) { yading@10: AVFilterLink *l = filter->outputs[out_no]; yading@10: unsigned ln = strlen(l->dst->name) + 1 + yading@10: strlen(l->dstpad->name); yading@10: e = buf->len + max_out_name + 2; yading@10: av_bprintf(buf, "%s", l->srcpad->name); yading@10: av_bprint_chars(buf, '-', e - buf->len); yading@10: e = buf->len + max_out_fmt + 2 + yading@10: max_dst_name - ln; yading@10: print_link_prop(buf, l); yading@10: av_bprint_chars(buf, '-', e - buf->len); yading@10: av_bprintf(buf, "%s:%s", l->dst->name, l->dstpad->name); yading@10: } yading@10: av_bprintf(buf, "\n"); yading@10: } yading@10: av_bprint_chars(buf, ' ', in_indent); yading@10: av_bprintf(buf, "+"); yading@10: av_bprint_chars(buf, '-', width); yading@10: av_bprintf(buf, "+\n"); yading@10: av_bprintf(buf, "\n"); yading@10: } yading@10: } yading@10: yading@10: char *avfilter_graph_dump(AVFilterGraph *graph, const char *options) yading@10: { yading@10: AVBPrint buf; yading@10: char *dump; yading@10: yading@10: av_bprint_init(&buf, 0, 0); yading@10: avfilter_graph_dump_to_buf(&buf, graph); yading@10: av_bprint_init(&buf, buf.len + 1, buf.len + 1); yading@10: avfilter_graph_dump_to_buf(&buf, graph); yading@10: av_bprint_finalize(&buf, &dump); yading@10: return dump; yading@10: }