[FFmpeg-devel] [PATCH v8 00/15] Execution Graph Printing
ffmpegagent
ffmpegagent at gmail.com
Tue Apr 29 03:59:49 EEST 2025
Shortest cover letter for my longest-running FFmpeg patchset:
* Apply
* Build
* Add the "-sg" switch to any FFmpeg command line
* Press 'q' when you don't want to wait
SG = Show Graph
Documentation and examples can be found here:
https://github.com/softworkz/ffmpeg_output_apis/wiki
Version Updates
===============
V2
==
* Rebased on top of Andreas' improvements
* Applied changes from review (thanks, Andreas)
V3
==
* Fixed all "new warnings"
* Fixed out-of-tree building (thanks, Michael)
V4
==
* Resolved merge conflict
* Fixed build on MinGW (missing include due to WIN32_LEAN_AND_MEAN being
defined) (thanks, Michael)
V5
==
* Applied changes as per review from Stefano (thanks!)
* Introduced AVTextFormatOptions struct for options in
avtext_context_open()
V6
==
* Fix "new warning" in 2nd last commit
* Squash patches 04 and 05 (they weren't truely independent)
* Applied changes as per review from Stefano (thanks!)
V7
==
* Bitten by OOT builds once again (thanks, Michael)
V8
==
* New commit Remove void (*print_rational) from AVTextFormatter (unused)
* New commit fftools/textformat: Rename name param to key for API
consistency
* print_int Extend existing function instead of adding print_int_flags
* Fix registered_formatters[] array size
* avtextwriters.h: Remove unused includes
* graphprint.c: Make BPrint inits consistent
* tf_json: Check nesting level for value printing
* And other review suggestions by Stefano (thanks!)
.
softworkz (15):
fftools/textformat: Formatting and whitespace changes
fftools/textformat: Apply quality improvements
fftools/textformat: Remove unused print_rational() pointer from
AVTextFormatter
fftools/textformat: Rename name param to key for API consistency
fftools/avtextformat: Re-use BPrint in loop
fftools/textformat: Introduce AVTextFormatOptions for
avtext_context_open()
fftools/textformat: Introduce common header and deduplicate code
fftools/tf_internal: Use av_default_item_name
fftools/textformat: Add flags param to function avtext_print_integer()
fftools/ffmpeg_filter: Move some declaration to new header file
avfilter/avfilter: Add avfilter_link_get_hw_frames_ctx()
fftools/resources: Add resource manager files
fftools/ffmpeg_mux: Make ms_from_ost() inline
fftools/graphprint: Add execution graph printing
fftools/graphprint: Now, make it a Killer-Feature!
doc/APIchanges | 3 +
doc/ffmpeg.texi | 14 +
ffbuild/common.mak | 28 +-
fftools/Makefile | 22 +-
fftools/ffmpeg.c | 4 +
fftools/ffmpeg.h | 4 +
fftools/ffmpeg_filter.c | 195 +----
fftools/ffmpeg_filter.h | 234 ++++++
fftools/ffmpeg_mux.h | 2 +-
fftools/ffmpeg_opt.c | 17 +
fftools/ffprobe.c | 15 +-
fftools/graph/filelauncher.c | 205 +++++
fftools/graph/graphprint.c | 1148 ++++++++++++++++++++++++++++
fftools/graph/graphprint.h | 62 ++
fftools/resources/.gitignore | 4 +
fftools/resources/Makefile | 27 +
fftools/resources/graph.css | 353 +++++++++
fftools/resources/graph.html | 86 +++
fftools/resources/resman.c | 213 ++++++
fftools/resources/resman.h | 50 ++
fftools/textformat/avtextformat.c | 242 +++---
fftools/textformat/avtextformat.h | 78 +-
fftools/textformat/avtextwriters.h | 16 +-
fftools/textformat/tf_compact.c | 121 +--
fftools/textformat/tf_default.c | 55 +-
fftools/textformat/tf_flat.c | 51 +-
fftools/textformat/tf_ini.c | 62 +-
fftools/textformat/tf_internal.h | 81 ++
fftools/textformat/tf_json.c | 64 +-
fftools/textformat/tf_mermaid.c | 658 ++++++++++++++++
fftools/textformat/tf_mermaid.h | 41 +
fftools/textformat/tf_xml.c | 68 +-
fftools/textformat/tw_avio.c | 18 +-
fftools/textformat/tw_buffer.c | 9 +-
fftools/textformat/tw_stdout.c | 10 +-
libavfilter/avfilter.c | 9 +
libavfilter/avfilter.h | 12 +
37 files changed, 3701 insertions(+), 580 deletions(-)
create mode 100644 fftools/ffmpeg_filter.h
create mode 100644 fftools/graph/filelauncher.c
create mode 100644 fftools/graph/graphprint.c
create mode 100644 fftools/graph/graphprint.h
create mode 100644 fftools/resources/.gitignore
create mode 100644 fftools/resources/Makefile
create mode 100644 fftools/resources/graph.css
create mode 100644 fftools/resources/graph.html
create mode 100644 fftools/resources/resman.c
create mode 100644 fftools/resources/resman.h
create mode 100644 fftools/textformat/tf_internal.h
create mode 100644 fftools/textformat/tf_mermaid.c
create mode 100644 fftools/textformat/tf_mermaid.h
base-commit: 25b0a8e295749a60a238ba0d6fe7a3742937b6bb
Published-As: https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-66%2Fsoftworkz%2Fsubmit_print_execution_graph-v8
Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-66/softworkz/submit_print_execution_graph-v8
Pull-Request: https://github.com/ffstaging/FFmpeg/pull/66
Range-diff vs v7:
1: b4bb8cdcc6 ! 1: ad156d4853 fftools/textformat: Formatting and whitespace changes
@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext *
AVBPrint bp;
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
- bprint_bytes(&bp, p0, p-p0),
-+ bprint_bytes(&bp, p0, p - p0),
- av_log(tctx, AV_LOG_ERROR,
- "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
- bp.str, tctx->string_validation_replacement);
+- av_log(tctx, AV_LOG_ERROR,
+- "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
+- bp.str, tctx->string_validation_replacement);
++ bprint_bytes(&bp, p0, p - p0);
++ av_log(tctx, AV_LOG_ERROR,
++ "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
++ bp.str, tctx->string_validation_replacement);
+ return ret;
+ }
+ }
@@ fftools/textformat/avtextformat.c: fail:
}
@@ fftools/textformat/avtextformat.c: fail:
}
-static const AVTextFormatter *registered_formatters[7+1];
-+static const AVTextFormatter *registered_formatters[10 + 1];
++static const AVTextFormatter *registered_formatters[7 + 1];
+
static void formatters_register_all(void)
{
static int initialized;
## fftools/textformat/avtextformat.h ##
+@@ fftools/textformat/avtextformat.h: typedef struct AVTextFormatSection {
+ #define AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE 16 ///< the items in this array section should be numbered individually by type
+
+ int flags;
+- const int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
++ const int children_ids[SECTION_MAX_NB_CHILDREN + 1]; ///< list of children section IDS, terminated by -1
+ const char *element_name; ///< name of the contained element, if provided
+ const char *unique_name; ///< unique section name, in case the name is ambiguous
+ AVDictionary *entries_to_show;
+- const char *(* get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined
++ const char *(*get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined
+ int show_all_entries;
+ } AVTextFormatSection;
+
@@ fftools/textformat/avtextformat.h: typedef struct AVTextFormatter {
#define SECTION_MAX_NB_SECTIONS 100
2: 1a4044ba23 ! 2: fd59be673d fftools/textformat: Apply quality improvements
@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext *
AVTextFormatContext *tctx;
int i, ret = 0;
-+ if (!ptctx || !formatter)
-+ return AVERROR(EINVAL);
++ av_assert0(ptctx && formatter);
+
if (!(tctx = av_mallocz(sizeof(AVTextFormatContext)))) {
ret = AVERROR(ENOMEM);
@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext *
while (*p) {
const uint8_t *p0 = p;
int32_t code;
- ret = av_utf8_decode(&code, &p, endp, tctx->string_validation_utf8_flags);
- if (ret < 0) {
- AVBPrint bp;
-- av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
-+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
- bprint_bytes(&bp, p0, p - p0),
- av_log(tctx, AV_LOG_ERROR,
- "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
- bp.str, tctx->string_validation_replacement);
-- return ret;
-+ av_bprint_finalize(&bp, NULL);
+@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form
+ "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
+ bp.str, tctx->string_validation_replacement);
+ return ret;
+ goto fail;
}
}
@@ fftools/textformat/avtextformat.c: static const char unit_bit_per_second_str[] =
void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id)
{
-+ if (section_id < 0 || section_id >= tctx->nb_sections)
++ if (section_id < 0 || section_id >= tctx->nb_sections) {
++ av_log(tctx, AV_LOG_ERROR, "Invalid section_id for section_header: %d\n", section_id);
+ return;
++ }
+
tctx->level++;
av_assert0(tctx->level < SECTION_MAX_NB_LEVELS);
@@ fftools/textformat/avtextformat.c: void avtext_print_section_header(AVTextFormat
void avtext_print_section_footer(AVTextFormatContext *tctx)
{
-+ if (tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS)
++ if (tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS) {
++ av_log(tctx, AV_LOG_ERROR, "Invalid level for section_footer: %d\n", tctx->level);
+ return;
++ }
+
int section_id = tctx->section[tctx->level]->id;
int parent_section_id = tctx->level
@@ fftools/textformat/tw_avio.c: static void io_w8(AVTextWriterContext *wctx, int b
}
static void io_printf(AVTextWriterContext *wctx, const char *fmt, ...)
-@@ fftools/textformat/tw_avio.c: const AVTextWriter avtextwriter_avio = {
+@@ fftools/textformat/tw_avio.c: int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_fil
+ IOWriterContext *ctx;
+ int ret;
- int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename)
- {
+ if (!output_filename || !output_filename[0]) {
+ av_log(NULL, AV_LOG_ERROR, "The output_filename cannot be NULL or empty\n");
+ return AVERROR(EINVAL);
+ }
-+
- IOWriterContext *ctx;
- int ret;
--
ret = avtextwriter_context_open(pwctx, &avtextwriter_avio);
if (ret < 0)
- return ret;
-@@ fftools/textformat/tw_avio.c: int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_fil
-
- int avtextwriter_create_avio(AVTextWriterContext **pwctx, AVIOContext *avio_ctx, int close_on_uninit)
- {
-+ av_assert0(avio_ctx);
-+
+@@ fftools/textformat/tw_avio.c: int avtextwriter_create_avio(AVTextWriterContext **pwctx, AVIOContext *avio_ctx,
IOWriterContext *ctx;
int ret;
++ av_assert0(avio_ctx);
++
+ ret = avtextwriter_context_open(pwctx, &avtextwriter_avio);
+ if (ret < 0)
+ return ret;
-: ---------- > 3: 4727f424d3 fftools/textformat: Remove unused print_rational() pointer from AVTextFormatter
-: ---------- > 4: 43d00310c4 fftools/textformat: Rename name param to key for API consistency
3: 5972ecf213 = 5: 606fa7866a fftools/avtextformat: Re-use BPrint in loop
4: 97ab9e0426 = 6: 95ef1f0919 fftools/textformat: Introduce AVTextFormatOptions for avtext_context_open()
5: 6d1cf2b3fd ! 7: dafd10253d fftools/textformat: Introduce common header and deduplicate code
@@ fftools/textformat/tf_json.c: static inline void json_print_item_str(AVTextForma
static void json_print_str(AVTextFormatContext *wctx, const char *key, const char *value)
{
++ const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
+ const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
JSONContext *json = wctx->priv;
- const struct AVTextFormatSection *parent_section = wctx->level ?
- wctx->section[wctx->level-1] : NULL;
++
++ if (!section)
++ return;
if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE))
writer_put_str(wctx, json->item_sep);
@@ fftools/textformat/tf_json.c: static void json_print_str(AVTextFormatContext *wc
static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value)
{
++ const AVTextFormatSection *section = tf_get_section(wctx, wctx->level);
+ const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level);
JSONContext *json = wctx->priv;
- const AVTextFormatSection *parent_section = wctx->level ? wctx->section[wctx->level - 1] : NULL;
AVBPrint buf;
++ if (!section)
++ return;
++
if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE))
+ writer_put_str(wctx, json->item_sep);
+ if (!json->compact)
@@ fftools/textformat/tf_json.c: const AVTextFormatter avtextformatter_json = {
.flags = AV_TEXTFORMAT_FLAG_SUPPORTS_MIXED_ARRAY_CONTENT,
.priv_class = &json_class,
6: fa22ead3ef = 8: a4b1fb9cc0 fftools/tf_internal: Use av_default_item_name
7: 59dfd3ded6 ! 9: a18ccba001 fftools/textformat: Add function avtext_print_integer_flags()
@@ Metadata
Author: softworkz <softworkz at hotmail.com>
## Commit message ##
- fftools/textformat: Add function avtext_print_integer_flags()
+ fftools/textformat: Add flags param to function avtext_print_integer()
- This function works analog to the avtext_print_string() which already
+ Make this function work analog to avtext_print_string() which already
has a flags parameter.
Signed-off-by: softworkz <softworkz at hotmail.com>
+ ## fftools/ffprobe.c ##
+@@ fftools/ffprobe.c: static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
+ avtext_print_string(tfc, k, pbuf.str, 0); \
+ } while (0)
+
+-#define print_int(k, v) avtext_print_integer(tfc, k, v)
++#define print_int(k, v) avtext_print_integer(tfc, k, v, 0)
+ #define print_q(k, v, s) avtext_print_rational(tfc, k, v, s)
+ #define print_str(k, v) avtext_print_string(tfc, k, v, 0)
+ #define print_str_opt(k, v) avtext_print_string(tfc, k, v, AV_TEXTFORMAT_PRINT_STRING_OPTIONAL)
+
## fftools/textformat/avtextformat.c ##
-@@ fftools/textformat/avtextformat.c: void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t va
- }
+@@ fftools/textformat/avtextformat.c: void avtext_print_section_footer(AVTextFormatContext *tctx)
+ tctx->level--;
}
-+void avtext_print_integer_flags(AVTextFormatContext *tctx, const char *key, int64_t val, int flags)
-+{
+-void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val)
++void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val, int flags)
+ {
+ const AVTextFormatSection *section;
+
+ av_assert0(tctx);
+
+ if (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER)
@@ fftools/textformat/avtextformat.c: void avtext_print_integer(AVTextFormatContext
+ && !(tctx->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS))
+ return;
+
-+ avtext_print_integer(tctx, key, val);
-+}
-+
- static inline int validate_string(AVTextFormatContext *tctx, char **dstp, const char *src)
- {
- const uint8_t *p, *endp, *srcp = (const uint8_t *)src;
+ av_assert0(key && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS);
+
+ section = tctx->section[tctx->level];
@@ fftools/textformat/avtextformat.c: int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *
section = tctx->section[tctx->level];
@@ fftools/textformat/avtextformat.c: int avtext_print_string(AVTextFormatContext *
return 0;
if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
+@@ fftools/textformat/avtextformat.c: void avtext_print_ts(AVTextFormatContext *tctx, const char *key, int64_t ts, int
+ if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0))
+ avtext_print_string(tctx, key, "N/A", AV_TEXTFORMAT_PRINT_STRING_OPTIONAL);
+ else
+- avtext_print_integer(tctx, key, ts);
++ avtext_print_integer(tctx, key, ts, 0);
+ }
+
+ void avtext_print_data(AVTextFormatContext *tctx, const char *key,
## fftools/textformat/avtextformat.h ##
-@@ fftools/textformat/avtextformat.h: void avtext_print_section_footer(AVTextFormatContext *tctx);
+@@ fftools/textformat/avtextformat.h: void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, in
- void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val);
+ void avtext_print_section_footer(AVTextFormatContext *tctx);
+
+-void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val);
++void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t val, int flags);
-+void avtext_print_integer_flags(AVTextFormatContext *tctx, const char *key, int64_t val, int flags);
-+
int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags);
- void avtext_print_unit_int(AVTextFormatContext *tctx, const char *key, int value, const char *unit);
8: 55a704faa5 = 10: 456423f436 fftools/ffmpeg_filter: Move some declaration to new header file
9: b6320cab8c = 11: 07c0d5b09b avfilter/avfilter: Add avfilter_link_get_hw_frames_ctx()
10: 48d36d9df0 = 12: 249899886e fftools/resources: Add resource manager files
11: c4c7340c1d = 13: 58c7b1c142 fftools/ffmpeg_mux: Make ms_from_ost() inline
12: 9cc44e3690 ! 14: 3a090c9e60 fftools/graphprint: Add execution graph printing
@@ fftools/graph/graphprint.c (new)
+/* Text Format API Shortcuts */
+#define print_id(k, v) print_sanizied_id(gpc, k, v, 0)
+#define print_id_noprefix(k, v) print_sanizied_id(gpc, k, v, 1)
-+#define print_int(k, v) avtext_print_integer(tfc, k, v)
-+#define print_int_opt(k, v) avtext_print_integer_flags(tfc, k, v, gpc->opt_flags)
++#define print_int(k, v) avtext_print_integer(tfc, k, v, 0)
++#define print_int_opt(k, v) avtext_print_integer(tfc, k, v, gpc->opt_flags)
+#define print_q(k, v, s) avtext_print_rational(tfc, k, v, s)
+#define print_str(k, v) avtext_print_string(tfc, k, v, 0)
+#define print_str_opt(k, v) avtext_print_string(tfc, k, v, gpc->opt_flags)
@@ fftools/graph/graphprint.c (new)
+ AVBPrint buf;
+ AVTextFormatSectionContext sec_ctx = { 0 };
+
-+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
++ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ print_section_header_id(gpc, SECTION_ID_INPUTFILES, "Inputs", 0);
+
@@ fftools/graph/graphprint.c (new)
+
+ avtext_print_section_footer(tfc); // SECTION_ID_STREAMLINKS
+
++ av_bprint_finalize(&buf, NULL);
+ return 0;
+}
+
@@ fftools/graph/graphprint.h (new)
+#endif /* FFTOOLS_GRAPH_GRAPHPRINT_H */
## fftools/textformat/avtextformat.c ##
+@@ fftools/textformat/avtextformat.c: fail:
+ return ret;
+ }
+
+-static const AVTextFormatter *registered_formatters[7 + 1];
++static const AVTextFormatter *registered_formatters[9 + 1];
+
+ static void formatters_register_all(void)
+ {
@@ fftools/textformat/avtextformat.c: static void formatters_register_all(void)
registered_formatters[4] = &avtextformatter_ini;
registered_formatters[5] = &avtextformatter_json;
@@ fftools/textformat/avtextformat.h: typedef struct AVTextFormatSection {
+#define AV_TEXTFORMAT_SECTION_FLAG_IS_SUBGRAPH 256 ///< ...
int flags;
- const int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
+ const int children_ids[SECTION_MAX_NB_CHILDREN + 1]; ///< list of children section IDS, terminated by -1
@@ fftools/textformat/avtextformat.h: typedef struct AVTextFormatSection {
AVDictionary *entries_to_show;
- const char *(* get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined
+ const char *(*get_type)(const void *data); ///< function returning a type if defined, must be defined when SECTION_FLAG_HAS_TYPE is defined
int show_all_entries;
-+ const char *id_key; ///< name of the key to be used as the id
++ const char *id_key; ///< name of the key to be used as the id
+ const char *src_id_key; ///< name of the key to be used as the source id for diagram connections
+ const char *dest_id_key; ///< name of the key to be used as the target id for diagram connections
+ const char *linktype_key; ///< name of the key to be used as the link type for diagram connections (AVTextFormatLinkType)
13: 1cb17c6e3b = 15: 578373f8c2 fftools/graphprint: Now, make it a Killer-Feature!
--
ffmpeg-codebot
More information about the ffmpeg-devel
mailing list