From: Niklas Haas <ffmpeg@haasn.xyz> To: ffmpeg-devel@ffmpeg.org Cc: Niklas Haas <git@haasn.dev> Subject: [FFmpeg-devel] [PATCH v2 3/4] avfilter/graphdump: add complex format Date: Tue, 18 Feb 2025 13:46:02 +0100 Message-ID: <20250218124603.95398-3-ffmpeg@haasn.xyz> (raw) In-Reply-To: <20250218124603.95398-1-ffmpeg@haasn.xyz> From: Niklas Haas <git@haasn.dev> As an example, the following filter graph (taken from FATE): sws_flags=+accurate_rnd+bitexact; split [main][over]; [over] scale=88:72, pad=96:80:4:4 [overf]; [main][overf] overlay=240:16:format=yuv422 Results in this output: Filter graph: [L0] split=thread_type=0x00000000 [L1] [over]; [over] scale=w=88:width=88:h=72:height=72:flags=+accurate_rnd+bitexact:thread_type=0x00000000 [L3]; [L3] pad=width=96:w=96:height=80:h=80:x=4:y=4:thread_type=0x00000000 [overf]; [main] [overf] overlay=x=240:y=16:format=2 [L6]; buffer=width=352:video_size=352x288:height=288:pix_fmt=yuv420p:time_base=1/25:frame_rate=25/1:range=1:thread_type=0x00000000 [L0]; [L6] buffersink=pixel_formats=:colorspaces=:colorranges=:thread_type=0x00000000; [L1] scale=w=iw:width=iw:h=ih:height=ih:flags=+accurate_rnd+bitexact:thread_type=0x00000000 [main]; Filter links: [L0: buffer -> split] yuv420p 352x288 [SAR 0:1] csp:unknown range:tv [L1: split -> scale] yuv420p 352x288 [SAR 0:1] csp:unknown range:tv [over: split -> scale] yuv420p 352x288 [SAR 0:1] csp:unknown range:tv [L3: scale -> pad] yuva422p 88x72 [SAR 0:1] csp:unknown range:tv [overf: pad -> overlay] yuva422p 96x80 [SAR 0:1] csp:unknown range:tv [main: scale -> overlay] yuva422p 352x288 [SAR 0:1] csp:unknown range:tv [L6: overlay -> buffersink] yuva422p 352x288 [SAR 0:1] csp:unknown range:tv This format is intended to be more useful for logging, post-processing or otherwise reusing the dumpled filter graph, since it can be directly ingested again by `-filter_complex`. --- libavfilter/graphdump.c | 124 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/libavfilter/graphdump.c b/libavfilter/graphdump.c index 80cbda50f5..e81ea0c001 100644 --- a/libavfilter/graphdump.c +++ b/libavfilter/graphdump.c @@ -32,6 +32,7 @@ enum { FMT_NONE = 0, FMT_PRETTY, + FMT_COMPLEX, FMT_NB, }; @@ -46,6 +47,7 @@ static const AVOption graph_dump_options[] = { { "format", "set the output format", OFFSET(format), AV_OPT_TYPE_INT, { .i64 = FMT_NONE }, 0, FMT_NB - 1, .unit = "format" }, { "none", "don't produce any output", 0, AV_OPT_TYPE_CONST, {.i64 = FMT_NONE}, .unit = "format" }, { "pretty", "pretty printed ASCII art graph", 0, AV_OPT_TYPE_CONST, {.i64 = FMT_PRETTY}, .unit = "format" }, + { "complex","complex filter graph", 0, AV_OPT_TYPE_CONST, {.i64 = FMT_COMPLEX}, .unit = "format" }, { NULL }, }; @@ -176,6 +178,121 @@ static void dump_pretty(AVBPrint *buf, AVFilterGraph *graph) } } +/* Assign a unique ID to each link by keeping track of them in an array */ +static int get_link_id(AVFilterLink ***links, int *nb_links, AVFilterLink *link) +{ + int ret; + for (int i = 0; i < *nb_links; i++) { + if ((*links)[i] == link) + return i; + } + + ret = av_dynarray_add_nofree(links, nb_links, link); + return ret ? ret : *nb_links - 1; +} + +static const char *get_filter_name(const AVFilterContext *filter) +{ + /* Reuse the filter instance name if present */ + return strchr(filter->name, '@') ? filter->name : filter->filter->name; +} + +static void print_link_label(AVBPrint *buf, AVFilterLink *link, int id) +{ + if (link->srcpad->label) + av_bprintf(buf, "%s", link->srcpad->label); + else if (link->dstpad->label) + av_bprintf(buf, "%s", link->dstpad->label); + else + av_bprintf(buf, "L%d", id); +} + +static int dump_complex(AVBPrint *buf, AVFilterGraph *graph) +{ + /* Keep track of seen filter links to assign a unique ID to each */ + AVFilterLink **links = NULL; + int nb_links = 0; + int ret = AVERROR(ENOMEM); + char *filter_opts = NULL; + + for (int i = 0; i < graph->nb_filters; i++) { + AVFilterContext *filter = graph->filters[i]; + if (i == 0) + av_bprintf(buf, "Filter graph:\n"); + + ret = av_opt_serialize(filter, AV_OPT_FLAG_FILTERING_PARAM, + AV_OPT_SERIALIZE_SKIP_DEFAULTS | + AV_OPT_SERIALIZE_SEARCH_CHILDREN, + &filter_opts, '=', ':'); + if (ret < 0) + goto fail; + + av_bprintf(buf, " "); + for (int j = 0; j < filter->nb_inputs; j++) { + AVFilterLink *link = filter->inputs[j]; + ret = get_link_id(&links, &nb_links, link); + if (ret < 0) + goto fail; + av_bprintf(buf, "["); + print_link_label(buf, link, ret); + av_bprintf(buf, "] "); + } + + av_bprintf(buf, "%s", get_filter_name(filter)); + if (filter_opts && filter_opts[0]) + av_bprintf(buf, "=%s", filter_opts); + av_freep(&filter_opts); + + for (int j = 0; j < filter->nb_outputs; j++) { + AVFilterLink *link = filter->outputs[j]; + ret = get_link_id(&links, &nb_links, link); + if (ret < 0) + goto fail; + av_bprintf(buf, " ["); + print_link_label(buf, link, ret); + av_bprintf(buf, "]"); + } + av_bprintf(buf, ";\n"); + } + + /* Dump a summary of all seen links */ + for (int i = 0; i < nb_links; i++) { + AVFilterLink *link = links[i]; + if (i == 0) + av_bprintf(buf, "Filter links:\n"); + av_bprintf(buf, " ["); + print_link_label(buf, link, i); + av_bprintf(buf, ": %s -> %s] ", get_filter_name(link->src), + get_filter_name(link->dst)); + + switch (link->type) { + case AVMEDIA_TYPE_VIDEO: + av_bprintf(buf, "%s %dx%d [SAR %d:%d] csp:%s range:%s\n", + av_get_pix_fmt_name(link->format), link->w, link->h, + link->sample_aspect_ratio.num, link->sample_aspect_ratio.den, + av_color_space_name(link->colorspace), + av_color_range_name(link->color_range)); + break; + case AVMEDIA_TYPE_AUDIO: + av_bprintf(buf, "%s %dHz ", + av_get_sample_fmt_name(link->format), link->sample_rate); + av_channel_layout_describe_bprint(&link->ch_layout, buf); + av_bprintf(buf, "\n"); + break; + default: + av_bprintf(buf, "unknown\n"); + continue; + } + } + + ret = 0; +fail: + av_free(links); + av_free(filter_opts); + return ret; +} + + char *avfilter_graph_dump(AVFilterGraph *graph, const char *options) { AVBPrint buf; @@ -202,6 +319,13 @@ char *avfilter_graph_dump(AVFilterGraph *graph, const char *options) case FMT_PRETTY: dump_pretty(&buf, graph); break; + case FMT_COMPLEX: + ret = dump_complex(&buf, graph); + if (ret < 0) { + av_bprint_finalize(&buf, NULL); + return NULL; + } + break; } av_bprint_finalize(&buf, &dump); -- 2.47.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2025-02-18 12:46 UTC|newest] Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top 2025-02-18 12:46 [FFmpeg-devel] [PATCH v2 1/4] avfilter/graphdump: implement options parsing Niklas Haas 2025-02-18 12:46 ` [FFmpeg-devel] [PATCH v2 2/4] avfilter/filters: keep track of AVFilterPad labels Niklas Haas 2025-02-18 12:46 ` Niklas Haas [this message] 2025-02-18 12:46 ` [FFmpeg-devel] [PATCH v2 4/4] fftools/ffmpeg_filter: add -dump_filter_graph option Niklas Haas 2025-02-18 16:43 ` epirat07 2025-02-19 17:36 ` Niklas Haas 2025-02-18 12:50 ` [FFmpeg-devel] [PATCH v2 1/4] avfilter/graphdump: implement options parsing Niklas Haas
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20250218124603.95398-3-ffmpeg@haasn.xyz \ --to=ffmpeg@haasn.xyz \ --cc=ffmpeg-devel@ffmpeg.org \ --cc=git@haasn.dev \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git