[FFmpeg-devel] [PATCH] lavfi: dump debug graph when merging failed.
Nicolas George
george at nsup.org
Thu Nov 28 15:02:43 CET 2013
Signed-off-by: Nicolas George <george at nsup.org>
---
libavfilter/avfiltergraph.c | 4 +-
libavfilter/graphdump.c | 182 ++++++++++++++++++++++++++++++++++++++++++++
libavfilter/internal.h | 5 ++
3 files changed, 190 insertions(+), 1 deletion(-)
Note: this is somewhat redundant with the avfilter_graph_dump() API, but not
so much: must of avfilter_graph_dump()'s code comes from an attempt at
ASCII-art dump, that actually gives quite bad results, while most of this
code deals with format negotiation lists.
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 1fb83c4..a11cdeb 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -1098,8 +1098,10 @@ static int graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
swap_samplerates(graph);
swap_channel_layouts(graph);
- if ((ret = pick_formats(graph)) < 0)
+ if ((ret = pick_formats(graph)) < 0) {
+ ff_dump_graph_debug(graph);
return ret;
+ }
return 0;
}
diff --git a/libavfilter/graphdump.c b/libavfilter/graphdump.c
index 1b59321..6795a2f 100644
--- a/libavfilter/graphdump.c
+++ b/libavfilter/graphdump.c
@@ -26,6 +26,8 @@
#include "libavutil/pixdesc.h"
#include "avfilter.h"
#include "avfiltergraph.h"
+#include "formats.h"
+#include "internal.h"
static int print_link_prop(AVBPrint *buf, AVFilterLink *link)
{
@@ -162,3 +164,183 @@ char *avfilter_graph_dump(AVFilterGraph *graph, const char *options)
av_bprint_finalize(&buf, &dump);
return dump;
}
+
+static int ddump_find_ref(AVBPrint *bp, AVFilterGraph *graph,
+ void *ref, void *self,
+ size_t off_in, size_t off_out)
+{
+ unsigned i, j;
+
+ if (ref == self)
+ return 0;
+ for (i = 0; i < graph->nb_filters; i++) {
+ AVFilterContext *f = graph->filters[i];
+ for (j = 0; j < f->nb_inputs; j++) {
+ if (ref == (char *)f->inputs[j] + off_out) {
+ av_bprintf(bp, "{ same as i%d:%d }", i, j);
+ return 1;
+ }
+ }
+ for (j = 0; j < f->nb_outputs; j++) {
+ if (ref == (char *)f->outputs[j] + off_in) {
+ av_bprintf(bp, "{ same as o%d:%d }", i, j);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static void ddump_pixel_format(AVBPrint *bp, AVFilterGraph *graph,
+ enum AVPixelFormat fmt,
+ AVFilterFormats **fmtsp)
+{
+ AVFilterFormats *fmts = *fmtsp;
+ unsigned i;
+
+ if (fmts) {
+ if (!ddump_find_ref(bp, graph, fmts->refs[0], fmtsp,
+ offsetof(AVFilterLink, in_formats),
+ offsetof(AVFilterLink, out_formats))) {
+ for (i = 0; i < fmts->nb_formats; i++)
+ av_bprintf(bp, " %c %s", i ? '|' : '{',
+ av_get_pix_fmt_name(fmts->formats[i]));
+ av_bprintf(bp, " }");
+ }
+ } else {
+ av_bprintf(bp, "%s", av_get_pix_fmt_name(fmt));
+ }
+}
+
+static void ddump_sample_format(AVBPrint *bp, AVFilterGraph *graph,
+ enum AVSampleFormat fmt,
+ AVFilterFormats **fmtsp)
+{
+ AVFilterFormats *fmts = *fmtsp;
+ unsigned i;
+
+ if (fmts) {
+ if (!ddump_find_ref(bp, graph, fmts->refs[0], fmtsp,
+ offsetof(AVFilterLink, in_formats),
+ offsetof(AVFilterLink, out_formats))) {
+ for (i = 0; i < fmts->nb_formats; i++)
+ av_bprintf(bp, " %c %s", i ? '|' : '{',
+ av_get_sample_fmt_name(fmts->formats[i]));
+ av_bprintf(bp, " }");
+ }
+ } else {
+ av_bprintf(bp, "%s", av_get_sample_fmt_name(fmt));
+ }
+}
+
+static void ddump_sample_freq(AVBPrint *bp, AVFilterGraph *graph,
+ int rate, AVFilterFormats **ratesp)
+{
+ AVFilterFormats *rates = *ratesp;
+ unsigned i;
+
+ if (rates) {
+ if (!ddump_find_ref(bp, graph, rates->refs[0], ratesp,
+ offsetof(AVFilterLink, in_samplerates),
+ offsetof(AVFilterLink, out_samplerates))) {
+ for (i = 0; i < rates->nb_formats; i++)
+ av_bprintf(bp, " %c %d", i ? '|' : '{',
+ rates->formats[i]);
+ av_bprintf(bp, " }");
+ }
+ } else {
+ av_bprintf(bp, "%d Hz", rate);
+ }
+}
+
+static void ddump_channels(AVBPrint *bp, AVFilterGraph *graph,
+ unsigned channels, uint64_t layout,
+ AVFilterChannelLayouts **layoutsp)
+{
+ AVFilterChannelLayouts *layouts = *layoutsp;
+ unsigned i;
+ uint64_t l;
+
+ if (layouts) {
+ if (ddump_find_ref(bp, graph, layouts->refs[0], layoutsp,
+ offsetof(AVFilterLink, in_channel_layouts),
+ offsetof(AVFilterLink, out_channel_layouts))) {
+ /* nothing */
+ } else if (layouts->all_counts) {
+ av_bprintf(bp, "{ all layouts and counts }");
+ } else if (layouts->all_layouts) {
+ av_bprintf(bp, "{ all layouts }");
+ } else {
+ for (i = 0; i < layouts->nb_channel_layouts; i++) {
+ av_bprintf(bp, "%s", i ? " | " : " { ");
+ l = layouts->channel_layouts[i];
+ if (FF_LAYOUT2COUNT(l))
+ av_bprintf(bp, "%dc", FF_LAYOUT2COUNT(l));
+ else
+ av_bprint_channel_layout(bp, 0, l);
+ }
+ av_bprintf(bp, " }");
+ }
+ } else {
+ av_bprint_channel_layout(bp, channels, layout);
+ }
+}
+
+static void ddump_link(AVFilterGraph *graph, unsigned filter_idx,
+ int out, unsigned pad_idx)
+{
+ AVFilterContext *f = graph->filters[filter_idx];
+ AVFilterLink *l = (out ? f->outputs : f->inputs)[pad_idx];
+ AVFilterContext *remote = out ? l->dst : l->src;
+ unsigned remote_idx;
+ AVBPrint bp;
+
+ for (remote_idx = 0; remote_idx < graph->nb_filters; remote_idx++)
+ if (graph->filters[remote_idx] == remote)
+ break;
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprintf(&bp, "%c%d:%d %s", out ? 'o' : 'i', filter_idx, pad_idx,
+ out ? "->" : "<-");
+ if (remote_idx < graph->nb_filters)
+ av_bprintf(&bp, "%c%d:%d", out ? 'i' : 'o', remote_idx,
+ out ? FF_OUTLINK_IDX(l) : FF_INLINK_IDX(l));
+ else
+ av_bprintf(&bp, "?");
+ av_bprintf(&bp, " ");
+ switch (l->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ ddump_pixel_format(&bp, graph, l->format,
+ out ? &l->in_formats : &l->out_formats);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ ddump_sample_format(&bp, graph, l->format,
+ out ? &l->in_formats : &l->out_formats);
+ av_bprintf(&bp, " / ");
+ ddump_sample_freq(&bp, graph, l->sample_rate,
+ out ? &l->in_samplerates : &l->out_samplerates);
+ av_bprintf(&bp, " / ");
+ ddump_channels(&bp, graph, l->channels, l->channel_layout,
+ out ? &l-> in_channel_layouts : &l->out_channel_layouts);
+ break;
+ default:
+ av_bprintf(&bp, " unknown format");
+ break;
+ }
+ av_log(graph, AV_LOG_DEBUG, " %s\n", bp.str);
+ av_bprint_finalize(&bp, NULL);
+}
+
+void ff_dump_graph_debug(AVFilterGraph *graph)
+{
+ unsigned i, j;
+
+ for (i = 0; i < graph->nb_filters; i++) {
+ AVFilterContext *f = graph->filters[i];
+ av_log(graph, AV_LOG_DEBUG, "%d: %s \"%s\"\n", i, f->filter->name, f->name);
+ for (j = 0; j < f->nb_inputs; j++)
+ ddump_link(graph, i, 0, j);
+ for (j = 0; j < f->nb_outputs; j++)
+ ddump_link(graph, i, 1, j);
+ }
+}
+
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 5e19698..a71557b 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -366,4 +366,9 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name);
*/
void ff_filter_graph_remove_filter(AVFilterGraph *graph, AVFilterContext *filter);
+/**
+ * Dump a graph internal properties to debug log.
+ */
+void ff_dump_graph_debug(AVFilterGraph *graph);
+
#endif /* AVFILTER_INTERNAL_H */
--
1.8.4.3
More information about the ffmpeg-devel
mailing list