From patchwork Fri May 22 23:54:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lance Wang X-Patchwork-Id: 19811 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 36E2B44B9D6 for ; Sat, 23 May 2020 03:23:04 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0DC956898AE; Sat, 23 May 2020 03:23:04 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-oi1-f195.google.com (mail-oi1-f195.google.com [209.85.167.195]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id B198F6881F1 for ; Sat, 23 May 2020 03:22:56 +0300 (EEST) Received: by mail-oi1-f195.google.com with SMTP id y85so10761413oie.11 for ; Fri, 22 May 2020 17:22:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=G6TDjoUNnPDJHxm4nIi5W8ZERJT1qG0c2p1iLSHCOfU=; b=T64UxxwTvGfR4hy5imjPsNU9o7ZKgHnGebZod+XXalmgDDsAF9uuWsGbLYYOfpKbXA zzoVk7PECFijIuXE2LB+XdBvYPHQDU+TePtut7jCP8mOTRxcwpBeXP6xSayHHOyfThWQ DZ8+gs9fX6WCcJwMSjyB/nfrLYmns/DmCNwcZhlC6MIbjSo5mVLbhOS413B1ZVjJS8ky 1AblhkioGw3Vd8s/Go+PWs+JuYm9bAmuEx6nvox41N2tmURsI4EaYY6onAGSeRGpYp8q c2bTqMOJyf4ANnjzdCKpofTVYc5zCfjDX1Is83K8jDSQnECyoT+n0HGNiW7nxPWrGmb9 zqsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=G6TDjoUNnPDJHxm4nIi5W8ZERJT1qG0c2p1iLSHCOfU=; b=Pot2D3xPXYgm5o0xS5LxIYcStvWCNabDaU7Y6JWlIC7uAUTq4n75ytCnFaA3DGR/Z0 z0wsGuMlRUbizFqK+qVY6CQ1L/ai1ZfrJ9dLAqRJNz2yJ6fWVrIFBHra0hj5uGMg74UR 7kGlafF2R6ek1m/dULy8YEU/RoY5JOgO/l4GX57+tGoayD4rzmqKa8AEQdf0arcl7iOW JAGbpxY63/fLEGtwDNh5Sxndru0zANJs9Z//hcM0sPkLWFdUD5jJD4r2arzntIVUAGJe +2+PG+5UDFiSiSruO4Afuu5eck/Ubj/5bluhmRP1SjDkBh22dIsyH2AmPr7mWsa0YjjG rwqA== X-Gm-Message-State: AOAM5339VVPeI0630VUuB1BTU21G7/kO7WjyB2jjp+wlz6anLBVNuz8p nBvvDctH3vcT1rKaJD2o7NWic0p4 X-Google-Smtp-Source: ABdhPJzJr1eQfZKHU3ZM3rg9+loIU/Z6AEVqGWlhXV8Hv6O+g36V8xHTmG1w/dFzMrospaEkHIIVNg== X-Received: by 2002:a17:90a:f0c7:: with SMTP id fa7mr7372316pjb.39.1590191680059; Fri, 22 May 2020 16:54:40 -0700 (PDT) Received: from vpn2.localdomain ([161.117.202.209]) by smtp.gmail.com with ESMTPSA id t20sm7611708pjo.13.2020.05.22.16.54.38 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 22 May 2020 16:54:39 -0700 (PDT) From: lance.lmwang@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Sat, 23 May 2020 07:54:32 +0800 Message-Id: <1590191673-2181-1-git-send-email-lance.lmwang@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1589900073-4183-1-git-send-email-lance.lmwang@gmail.com> References: <1589900073-4183-1-git-send-email-lance.lmwang@gmail.com> Subject: [FFmpeg-devel] [PATCH v4 1/2] fftools: add options to dump filter graph X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Limin Wang MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Limin Wang Signed-off-by: Limin Wang --- doc/ffmpeg.texi | 15 ++++++++++++ fftools/ffmpeg.h | 2 ++ fftools/ffmpeg_filter.c | 20 ++++++++++++++++ fftools/ffmpeg_opt.c | 20 ++++++++++++++++ libavfilter/graphdump.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+) diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index ed437bb..699991f 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -735,6 +735,21 @@ Technical note -- attachments are implemented as codec extradata, so this option can actually be used to extract extradata from any stream, not just attachments. +@item -dump_filtergraph @var{filename} (@emph{global}) +Set the output file name of filter graph for dump. + +It is "ASCII" format by default. for Graphviz DOT output format, +you can convert it to png by GraphViz tool: +@example +dot -Tpng dump_fg_filename -o dump_graph.png +@end example + +@item -dump_filtergraph_format @var{format} (@emph{global}) +Set the output format of filter graph for dump. Support format: "DOT", "ASCII". + +DOT is the text file format of the suite GraphViz, ASCII is the text file format +of ASCII style. + @item -noautorotate Disable automatically rotating video based on file metadata. diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 38205a1..55f115b 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -606,6 +606,8 @@ extern AVIOContext *progress_avio; extern float max_error_rate; extern char *videotoolbox_pixfmt; +extern char* dump_fg_filename; +extern char* dump_fg_format; extern int filter_nbthreads; extern int filter_complex_nbthreads; extern int vstats_version; diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 8b5b157..485fc73 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -1106,6 +1106,26 @@ int configure_filtergraph(FilterGraph *fg) if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0) goto fail; + if (dump_fg_filename) { + char *dump = avfilter_graph_dump(fg->graph, dump_fg_format); + FILE *fg_file = fopen(dump_fg_filename, "w"); + + if (!dump) { + ret = AVERROR(ENOMEM); + goto fail; + } + if (fg_file) { + fputs(dump, fg_file); + fflush(fg_file); + fclose(fg_file); + } else { + ret = AVERROR(EINVAL); + av_free(dump); + goto fail; + } + av_free(dump); + } + /* limit the lists of allowed formats to the ones selected, to * make sure they stay the same if the filtergraph is reconfigured later */ for (i = 0; i < fg->nb_outputs; i++) { diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 60bb437..bdd8957 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -143,6 +143,8 @@ HWDevice *filter_hw_device; char *vstats_filename; char *sdp_filename; +char *dump_fg_filename; +char *dump_fg_format; float audio_drift_threshold = 0.1; float dts_delta_threshold = 10; @@ -2930,6 +2932,20 @@ static int opt_vstats(void *optctx, const char *opt, const char *arg) return opt_vstats_file(NULL, opt, filename); } +static int opt_fg_filename(void *optctx, const char *opt, const char *arg) +{ + av_free (dump_fg_filename); + dump_fg_filename = av_strdup (arg); + return 0; +} + +static int opt_fg_format(void *optctx, const char *opt, const char *arg) +{ + av_free (dump_fg_format); + dump_fg_format = av_strdup (arg); + return 0; +} + static int opt_video_frames(void *optctx, const char *opt, const char *arg) { OptionsContext *o = optctx; @@ -3548,6 +3564,10 @@ const OptionDef options[] = { { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) }, "extract an attachment into a file", "filename" }, + { "dump_filtergraph",HAS_ARG | OPT_EXPERT, { .func_arg = opt_fg_filename }, + "the output filename of filter graph for dump", "filename" }, + { "dump_filtergraph_format", HAS_ARG | OPT_EXPERT, { .func_arg = opt_fg_format }, + "the format of filter graph for dump, support DOT or ASCII"}, { "stream_loop", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_INPUT | OPT_OFFSET, { .off = OFFSET(loop) }, "set number of times input stream shall be looped", "loop count" }, { "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts }, diff --git a/libavfilter/graphdump.c b/libavfilter/graphdump.c index 79ef1a7..b15f498 100644 --- a/libavfilter/graphdump.c +++ b/libavfilter/graphdump.c @@ -151,15 +151,78 @@ static void avfilter_graph_dump_to_buf(AVBPrint *buf, AVFilterGraph *graph) } } +static void avfilter_graph2dot_to_buf(AVBPrint *buf, AVFilterGraph *graph) +{ + int i, j; + + av_bprintf(buf, "digraph G {\n"); + av_bprintf(buf, "node [shape=box]\n"); + av_bprintf(buf, "rankdir=LR\n"); + + for (i = 0; i < graph->nb_filters; i++) { + char filter_ctx_label[128]; + const AVFilterContext *filter_ctx = graph->filters[i]; + + snprintf(filter_ctx_label, sizeof(filter_ctx_label), "%s\\n(%s)", + filter_ctx->name, + filter_ctx->filter->name); + + for (j = 0; j < filter_ctx->nb_outputs; j++) { + AVFilterLink *link = filter_ctx->outputs[j]; + if (link) { + char dst_filter_ctx_label[128]; + const AVFilterContext *dst_filter_ctx = link->dst; + + snprintf(dst_filter_ctx_label, sizeof(dst_filter_ctx_label), + "%s\\n(%s)", + dst_filter_ctx->name, + dst_filter_ctx->filter->name); + + av_bprintf(buf, "\"%s\" -> \"%s\" [ label= \"inpad:%s -> outpad:%s\\n", + filter_ctx_label, dst_filter_ctx_label, + avfilter_pad_get_name(link->srcpad, 0), + avfilter_pad_get_name(link->dstpad, 0)); + + if (link->type == AVMEDIA_TYPE_VIDEO) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); + av_bprintf(buf, + "fmt:%s w:%d h:%d tb:%d/%d", + desc->name, + link->w, link->h, + link->time_base.num, link->time_base.den); + } else if (link->type == AVMEDIA_TYPE_AUDIO) { + char audio_buf[255]; + av_get_channel_layout_string(audio_buf, sizeof(audio_buf), -1, + link->channel_layout); + av_bprintf(buf, + "fmt:%s sr:%d cl:%s tb:%d/%d", + av_get_sample_fmt_name(link->format), + link->sample_rate, audio_buf, + link->time_base.num, link->time_base.den); + } + av_bprintf(buf, "\" ];\n"); + } + } + } + av_bprintf(buf, "}\n"); +} + char *avfilter_graph_dump(AVFilterGraph *graph, const char *options) { AVBPrint buf; char *dump = NULL; + if (options && !strcmp(options, "DOT")) { + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + avfilter_graph2dot_to_buf(&buf, graph); + av_bprint_finalize(&buf, &dump); + } else { av_bprint_init(&buf, 0, AV_BPRINT_SIZE_COUNT_ONLY); avfilter_graph_dump_to_buf(&buf, graph); av_bprint_init(&buf, buf.len + 1, buf.len + 1); avfilter_graph_dump_to_buf(&buf, graph); av_bprint_finalize(&buf, &dump); + } + return dump; }