From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.ffmpeg.org (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id DCF2240D08 for ; Wed, 12 Nov 2025 08:06:12 +0000 (UTC) Authentication-Results: ffbox; dkim=fail (body hash mismatch (got b'1rxxiqZ7azd3UBmXWqkoqLn1Sc6WlrJgCGVrhIcINNU=', expected b'nhI+DJUMH43N3OMa3nukhg+VjSWhX5BHUXvBS2bE5/8=')) header.d=ffmpeg.org header.i=@ffmpeg.org header.a=rsa-sha256 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1762934743; h=mime-version : to : date : message-id : reply-to : subject : list-id : list-archive : list-archive : list-help : list-owner : list-post : list-subscribe : list-unsubscribe : from : cc : content-type : content-transfer-encoding : from; bh=1rxxiqZ7azd3UBmXWqkoqLn1Sc6WlrJgCGVrhIcINNU=; b=sZHP3NDat2TlxugI7gMolaQI76RS36lwDb/DL7DiZl3UHzx5BfHrYwIC85vlWQyBW0kIV 0PiI3NU1IWjwgdaLr3SzM+Wkn3EdzQduXtql+IAgyFaOKxnVoSZ6qh7FWb3fhqyZjwU8h5O tZEmhAZf1XPOIgj0QwrlA8r6Mkc2s5NEm/zw4rpjpKhHLDzHgD7jZEhPW+ofiDFiGaa2oZk wA4LfC7odDGDwxNIa2+aQ/F70yjLbwzo5EkQ79O6L5UnQVC5Dsgsh+wFezFMBL8TMWh6HRr O9bvZm2ZOSM5J9qRKQ42EtcFoP3bljc87qidMLkz21zB8AGH7AKhGNMsGg6w== Received: from [172.19.0.2] (unknown [172.19.0.2]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTP id CFDFB68FD83; Wed, 12 Nov 2025 10:05:43 +0200 (EET) ARC-Seal: i=1; cv=none; a=rsa-sha256; d=ffmpeg.org; s=arc; t=1762934722; b=M7teCxnmj8VPZe9El3j5heUZOznUUeFFNLDkrbt3tajeJS17D2maZCRuETbEG/76UDKf4 wR8ncwzBDAc5U0NJ2noxIgQx+eJVuGZ1DxdddZM4RZGdogIwA4LIRHb7dl754kCogJ1IIlx LPBYYSmhptXsa9vVFqUj5d5aAt5oZFuhi0ydDe1oHgnQTEWPhP7TeAYd6/TFSZdF+TD5FYM cukagcpAMhCpEzBEcCFwE2QCkQz9/ICnPQ3HkG/NlCgkVFGZok1m5dyNd3VwANs0UYbS4xI wJbl3DAJ2cihVSxXI5J6mLxVsmuMMV7C0/KDmTQcrC2DWLMbdUGhvH9bPaxw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ffmpeg.org; s=arc; t=1762934722; h=from : sender : reply-to : subject : date : message-id : to : cc : mime-version : content-type : content-transfer-encoding : content-id : content-description : resent-date : resent-from : resent-sender : resent-to : resent-cc : resent-message-id : in-reply-to : references : list-id : list-help : list-unsubscribe : list-subscribe : list-post : list-owner : list-archive; bh=T1Haei2Zu0bS3zSyrFTaBeDoWjUf7SonNDHUY3imigo=; b=RMqVTFdroko7XN3L25pi4esj/OWceKqgZjsjwPjAWOhfcVC7J6W87QA4WjyzxmLXoiDPh xwjdeq1uzzu8XGPJsqvWJpXGmvDjT8tMaJz4Tos9hbG11jn/l/8Y0OX3qIyllkxciIvRG8/ u0W660CvXI0nP4Km/QkVjq3+ggfYNLXUa3yIfI6jQhN1YO54PYeApZNFo1RjAj0XhxvBU6G vJ+Wqute/w506jiiPSnn/dsnemByTgnFWq5bF6gsbC1c8Kgakv3tIwlpJhxw9VnWjDSAhbb ja7+Zv4vIlX+bSStBstzLwDBZGPaeF/jLlMpvAXBrcpjUvukfNsA8qQo9VnA== ARC-Authentication-Results: i=1; ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none; dmarc=pass header.from=ffmpeg.org policy.dmarc=quarantine Authentication-Results: ffmpeg.org; dkim=pass header.d=ffmpeg.org header.i=@ffmpeg.org; arc=none (Message is not ARC signed); dmarc=pass (Used From Domain Record) header.from=ffmpeg.org policy.dmarc=quarantine DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ffmpeg.org; i=@ffmpeg.org; q=dns/txt; s=mail; t=1762934713; h=content-type : mime-version : content-transfer-encoding : from : to : reply-to : subject : date : from; bh=nhI+DJUMH43N3OMa3nukhg+VjSWhX5BHUXvBS2bE5/8=; b=cDi1thv79LEr/y+KXu9RIbregLYpFTQu+MXzxyp3s8wdzJICk17ocSrmm7lLpOSPcjBI7 4rUpORgXJKGXYI7hs3WKkXUXPlpMkw/rjx9G6jBvRyCLPA4K/lDQpsAhkWiKnCE7Bp23G7M tH2nvjrwf2uUffV41HoN6rxoyT4ms17n/q6keZsduYwWj6C8Ych0mMRcXa0D5WLaME7JB9b Dt4LyN2erwOyG0mGUKSpF7mD/0OPV9RUH+dOdu8neD02/oroNGsBJNkRqFlh6e/EmhjXjYi 0WKUmjoVxhQHenNK4DyCT/ckwSr9P3ZrKhg/OOKJVGEwq06lCxAn5x6aZnMw== Received: from 188d6d40ca7a (code.ffmpeg.org [188.245.149.3]) by ffbox0-bg.ffmpeg.org (Postfix) with ESMTPS id 381D168FC29 for ; Wed, 12 Nov 2025 10:05:13 +0200 (EET) MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Date: Wed, 12 Nov 2025 08:05:12 -0000 Message-ID: <176293471340.25.5668407998857296145@2cb04c0e5124> Message-ID-Hash: PDHBFHKDKJ5JX3RKJNYUSKXIP7DHQAGG X-Message-ID-Hash: PDHBFHKDKJ5JX3RKJNYUSKXIP7DHQAGG X-MailFrom: code@ffmpeg.org X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-ffmpeg-devel.ffmpeg.org-0; header-match-ffmpeg-devel.ffmpeg.org-1; header-match-ffmpeg-devel.ffmpeg.org-2; header-match-ffmpeg-devel.ffmpeg.org-3; emergency; member-moderation X-Mailman-Version: 3.3.10 Precedence: list Reply-To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [PATCH] fftools/tf_mermaid: close subgraph header when there are no inputs. (PR #20898) List-Id: FFmpeg development discussions and patches Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: "Ayose C. via ffmpeg-devel" Cc: "Ayose C." Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Archived-At: List-Archive: List-Post: PR #20898 opened by Ayose C. (ayosec) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20898 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20898.patch ### Problem FFmpeg can be used with no inputs. For example, the command ```bash $ ffmpeg -filter_complex color=blue:d=1 /tmp/blue.mp4 ``` creates a 1-second video with a solid color. When the `-print_graphs_format mermaid` (or `mermaidhtml`) is used on a command like that, the `subgraph` section for `ff-inputfiles` and `ff-decoders` is incomplete: ``` subgraph G1_Inputs["
end class G1_Inputs ff-inputfiles subgraph G1_Decoders["
end class G1_Decoders ff-decoders ``` Opening the generated file in a browser throws this error: ``` Parse error on line 26: ...subgraph G1_Encoders["
"]` fragment to complete the `subgraph` line. ### Cause The fragment to complete the `subgraph` header [is written in `mermaid_print_section_header`](https://code.ffmpeg.org/FFmpeg/FFmpeg/src/commit/418235e98a42681a7f243ba6de8f7e9284a677b5/fftools/textformat/tf_mermaid.c#L303-L312): ```c static void mermaid_print_section_header(AVTextFormatContext *tfc, const void *data) { // ... if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) { // ... if (parent_sec_data.subgraph_start_incomplete) { // ... writer_put_str(tfc, "
\"]\n"); mmc->section_data[tfc->level - 1].subgraph_start_incomplete = 0; } } // ... if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) { // ... writer_printf(tfc, "subgraph %s[\"
", sec_ctx->context_id, section->name); mmc->section_data[tfc->level].subgraph_start_incomplete = 1; ``` The function is invoked from [`print_filter`](https://code.ffmpeg.org/FFmpeg/FFmpeg/src/commit/418235e98a42681a7f243ba6de8f7e9284a677b5/fftools/graph/graphprint.c#L406-L436). It assumes that the `header` function is called at least once before the footer, but this is not the case when there are no inputs: ```c avtext_print_section_header(tfc, NULL, SECTION_ID_FILTER_INPUTS); for (unsigned i = 0; i < filter->nb_inputs; i++) { // ... avtext_print_section_header(tfc, &sec_ctx, SECTION_ID_FILTER_INPUT); // ... } avtext_print_section_footer(tfc); ``` ### Fix The field `subgraph_start_incomplete` tracks if the `subgraph` is line is completed or no. So I moved the code to complete it a function, which is called from the original point (inside the `mermaid_print_section_header`) and from `mermaid_print_section_footer`. ### Test Running the following command: ```bash ffmpeg \ -print_graphs \ -print_graphs_format mermaidhtml \ -print_graphs_file /tmp/after.html -filter_complex color \ -frames:v 1 \ -f null - ``` Before/after the fix shows the expected diff: ```diff --- /tmp/before.html +++ /tmp/after.html @@ -84,11 +84,13 @@ G0_Parsed_color_0 video-G0_Parsed_color_0-out__0_0@== "yuv420p
320x240
1:1
 
 
 " ==> out__0_0 - subgraph G1_Inputs["
end + subgraph G1_Inputs["
"] + end class G1_Inputs ff-inputfiles - subgraph G1_Decoders["
end + subgraph G1_Decoders["
"] + end class G1_Decoders ff-decoders ``` The `after.html` also loads correctly: ![image](/attachments/7509c2cd-6000-45ed-8ea3-3ed1fb7a0230) I didn't find FATE tests related to the mermaid generation, but I did a before/after comparison with multiple filtergraphs, and in all cases the only difference is the fix. >>From f21ddefb50ca169c90ff2e37cea228e7866d285b Mon Sep 17 00:00:00 2001 From: Ayose Date: Wed, 12 Nov 2025 07:21:23 +0000 Subject: [PATCH] fftools/tf_mermaid: close subgraph header when there are no inputs. Ensure that the fragment to close the header (`
\"]`) is written when the function `mermaid_print_section_header` is called only once, which happens when the filtergraph has no inputs. Signed-off-by: Ayose --- fftools/textformat/tf_mermaid.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/fftools/textformat/tf_mermaid.c b/fftools/textformat/tf_mermaid.c index ef730d570b..fdd4ab7e57 100644 --- a/fftools/textformat/tf_mermaid.c +++ b/fftools/textformat/tf_mermaid.c @@ -240,6 +240,21 @@ static void set_str(const char **dst, const char *src) *dst = av_strdup(src); } +static void mermaid_subgraph_complete_start(MermaidContext *mmc, AVTextFormatContext *tfc, int level) { + struct section_data parent_sec_data = mmc->section_data[level]; + AVBPrint *parent_buf = &tfc->section_pbuf[level]; + + if (parent_sec_data.subgraph_start_incomplete) { + + if (parent_buf->len > 0) + writer_printf(tfc, "%s", parent_buf->str); + + writer_put_str(tfc, "
\"]\n"); + + mmc->section_data[level].subgraph_start_incomplete = 0; + } +} + #define MM_INDENT() writer_printf(tfc, "%*c", mmc->indent_level * 2, ' ') static void mermaid_print_section_header(AVTextFormatContext *tfc, const void *data) @@ -296,19 +311,7 @@ static void mermaid_print_section_header(AVTextFormatContext *tfc, const void *d } if (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH) { - - struct section_data parent_sec_data = mmc->section_data[tfc->level - 1]; - AVBPrint *parent_buf = &tfc->section_pbuf[tfc->level - 1]; - - if (parent_sec_data.subgraph_start_incomplete) { - - if (parent_buf->len > 0) - writer_printf(tfc, "%s", parent_buf->str); - - writer_put_str(tfc, "
\"]\n"); - - mmc->section_data[tfc->level - 1].subgraph_start_incomplete = 0; - } + mermaid_subgraph_complete_start(mmc, tfc, tfc->level - 1); } av_freep(&mmc->section_data[tfc->level].section_id); @@ -454,6 +457,8 @@ static void mermaid_print_section_footer(AVTextFormatContext *tfc) } else if ((section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH)) { + mermaid_subgraph_complete_start(mmc, tfc, tfc->level); + MM_INDENT(); writer_put_str(tfc, "end\n"); -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org