[FFmpeg-devel] [PATCH v2 00/10] Execution Graph Printing
ffmpegagent
ffmpegagent at gmail.com
Wed Apr 16 13:12:10 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)
softworkz (10):
fftools/textformat: Formatting and whitespace changes
fftools/textformat: Quality improvements
fftools/textformat: Introduce common header and deduplicate code
fftools/tf_internal: Use ac_default_item_name
fftools/textformat: Add function avtext_print_integer_flags()
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/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 | 18 +
fftools/ffmpeg.c | 4 +
fftools/ffmpeg.h | 4 +
fftools/ffmpeg_filter.c | 195 +----
fftools/ffmpeg_filter.h | 234 ++++++
fftools/ffmpeg_opt.c | 17 +
fftools/graph/filelauncher.c | 204 +++++
fftools/graph/graphprint.c | 1146 ++++++++++++++++++++++++++++
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 | 238 +++---
fftools/textformat/avtextformat.h | 53 +-
fftools/textformat/avtextwriters.h | 11 +-
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 | 56 +-
fftools/textformat/tf_mermaid.c | 655 ++++++++++++++++
fftools/textformat/tf_mermaid.h | 41 +
fftools/textformat/tf_xml.c | 68 +-
fftools/textformat/tw_avio.c | 16 +-
fftools/textformat/tw_buffer.c | 7 +-
fftools/textformat/tw_stdout.c | 8 +-
libavfilter/avfilter.c | 9 +
libavfilter/avfilter.h | 12 +
35 files changed, 3662 insertions(+), 544 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: a888975a3c25760027cd59932f5c1ad04368db8b
Published-As: https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-66%2Fsoftworkz%2Fsubmit_print_execution_graph-v2
Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-66/softworkz/submit_print_execution_graph-v2
Pull-Request: https://github.com/ffstaging/FFmpeg/pull/66
Range-diff vs v1:
1: 3df2018c81 ! 1: b6468d1a30 fftools/textformat: Formatting and whitespace changes
@@ fftools/textformat/avtextformat.c: static const char *textcontext_get_formatter_
{ NULL }
};
-@@ fftools/textformat/avtextformat.c: int avtext_context_close(AVTextFormatContext **ptctx)
+@@ fftools/textformat/avtextformat.c: void avtext_context_close(AVTextFormatContext **ptctx)
}
@@ fftools/textformat/avtextformat.c: int avtext_print_string(AVTextFormatContext *
- const char *key, AVRational q, char sep)
+void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRational q, char sep)
{
- AVBPrint buf;
- av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ char buf[44];
+ snprintf(buf, sizeof(buf), "%d%c%d", q.num, sep, q.den);
@@ fftools/textformat/avtextformat.c: void avtext_print_rational(AVTextFormatContext *tctx,
}
2: 04cce91500 ! 2: 6568269678 fftools/textformat: Quality improvements
@@ fftools/textformat/avtextformat.c: static const AVClass textcontext_class = {
av_bprintf(bp, "%02X", ubuf[i]);
}
-@@ fftools/textformat/avtextformat.c: int avtext_context_close(AVTextFormatContext **ptctx)
-
- av_hash_freep(&tctx->hash);
-
-- av_hash_freep(&tctx->hash);
--
- if (tctx->formatter->uninit)
- tctx->formatter->uninit(tctx);
- for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext **ptctx,
AVTextFormatContext *tctx;
int i, ret = 0;
@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext
+ if (!ptctx || !formatter)
+ return AVERROR(EINVAL);
+
-+ if (!formatter->priv_size && formatter->priv_class)
-+ return AVERROR(EINVAL);
-+
+ if (!((tctx = av_mallocz(sizeof(AVTextFormatContext))))) {
ret = AVERROR(ENOMEM);
goto fail;
}
-
-- if (!(tctx->priv = av_mallocz(formatter->priv_size))) {
-+ if (formatter->priv_size && !((tctx->priv = av_mallocz(formatter->priv_size)))) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext **ptctx,
+ av_log(NULL, AV_LOG_ERROR, " %s", n);
+ av_log(NULL, AV_LOG_ERROR, "\n");
+ }
+- return ret;
++ goto fail;
+ }
/* validate replace string */
{
@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext
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);
++ goto fail;
+ }
+ }
+ }
@@ fftools/textformat/avtextformat.c: static const char unit_bit_per_second_str[] = "bit/s";
void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id)
{
-+ if (!tctx || section_id < 0 || section_id >= tctx->nb_sections)
++ if (section_id < 0 || section_id >= tctx->nb_sections)
+ return;
+
tctx->level++;
@@ fftools/textformat/avtextformat.c: void avtext_print_section_header(AVTextFormat
void avtext_print_section_footer(AVTextFormatContext *tctx)
{
-+ if (!tctx || tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS)
++ if (tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS)
+ return;
+
int section_id = tctx->section[tctx->level]->id;
@@ fftools/textformat/avtextformat.c: void avtext_print_section_footer(AVTextFormat
- const struct AVTextFormatSection *section = tctx->section[tctx->level];
+ const AVTextFormatSection *section;
+
-+ if (!tctx || !key || tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS)
++ if (!key || tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS)
+ return;
+
+ section = tctx->section[tctx->level];
@@ fftools/textformat/avtextformat.c: void avtext_print_integer(AVTextFormatContext
+ AVBPrint bp;
int invalid_chars_nb = 0, ret = 0;
-+ if (!tctx || !dstp || !src)
-+ return AVERROR(EINVAL);
-+
+ *dstp = NULL;
av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
@@ fftools/textformat/avtextformat.c: void avtext_print_unit_int(AVTextFormatContex
+ const AVTextFormatSection *section;
int ret = 0;
-+ if (!tctx || !key || !val || tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS)
++ if (!key || !val || tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS)
+ return AVERROR(EINVAL);
+
+ section = tctx->section[tctx->level];
@@ fftools/textformat/avtextformat.c: void avtext_print_unit_int(AVTextFormatContex
if (tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_NEVER ||
(tctx->show_optional_fields == SHOW_OPTIONAL_FIELDS_AUTO
&& (flags & AV_TEXTFORMAT_PRINT_STRING_OPTIONAL)
-@@ fftools/textformat/avtextformat.c: int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *
- void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRational q, char sep)
- {
- AVBPrint buf;
-- av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
-+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
- av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
- avtext_print_string(tctx, key, buf.str, 0);
- }
@@ fftools/textformat/avtextformat.c: void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRationa
void avtext_print_time(AVTextFormatContext *tctx, const char *key,
int64_t ts, const AVRational *time_base, int is_duration)
@@ fftools/textformat/avtextformat.c: void avtext_print_rational(AVTextFormatContex
} else {
- double d = ts * av_q2d(*time_base);
+ char buf[128];
-+ double d = av_q2d(*time_base) * (double)ts;
++ double d = av_q2d(*time_base) * ts;
struct unit_value uv;
uv.val.d = d;
uv.unit = unit_second_str;
@@ fftools/textformat/avtextformat.c: int avtextwriter_context_open(AVTextWriterCon
+ if (!pwctx || !writer)
+ return AVERROR(EINVAL);
+
-+ if (!writer->priv_size && writer->priv_class)
-+ return AVERROR(EINVAL);
-+
+ if (!((wctx = av_mallocz(sizeof(AVTextWriterContext))))) {
ret = AVERROR(ENOMEM);
goto fail;
@@ 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 = {
- int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename, int close_on_uninit)
+ int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename)
{
+ if (!pwctx || !output_filename || !output_filename[0])
+ return AVERROR(EINVAL);
3: 0bd0ec42f1 ! 3: 9e77a447b8 fftools/textformat: Introduce common header and deduplicate code
@@ fftools/textformat/avtextwriters.h: typedef struct AVTextWriter {
## fftools/textformat/tf_compact.c ##
@@
- #include <string.h>
-
- #include "avtextformat.h"
-+#include "tf_internal.h"
- #include <libavutil/mem.h>
- #include <libavutil/avassert.h>
- #include <libavutil/bprint.h>
-@@
- #include <libavutil/opt.h>
-
-
+ #include "libavutil/bprint.h"
+ #include "libavutil/error.h"
+ #include "libavutil/opt.h"
+-
+-
-#define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
-#define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
-#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
@@ fftools/textformat/tf_compact.c
- .item_name = name##_get_name, \
- .option = name##_options \
-}
--
++#include "tf_internal.h"
- /* Compact output */
+ /* Compact output */
@@ fftools/textformat/tf_compact.c: static av_cold int compact_init(AVTextFormatContext *wctx)
static void compact_print_section_header(AVTextFormatContext *wctx, const void *data)
{
@@ fftools/textformat/tf_compact.c: static void compact_print_section_header(AVText
## fftools/textformat/tf_default.c ##
@@
- #include <string.h>
-
#include "avtextformat.h"
-+#include "tf_internal.h"
- #include <libavutil/mem.h>
- #include <libavutil/avassert.h>
- #include <libavutil/bprint.h>
- #include <libavutil/opt.h>
-
+ #include "libavutil/bprint.h"
+ #include "libavutil/opt.h"
+-
-#define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
-#define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
-#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
@@ fftools/textformat/tf_default.c
- .item_name = name##_get_name, \
- .option = name##_options \
-}
--
++#include "tf_internal.h"
+
/* Default output */
- typedef struct DefaultContext {
@@ fftools/textformat/tf_default.c: static void default_print_section_header(AVTextFormatContext *wctx, const void *
{
DefaultContext *def = wctx->priv;
@@ fftools/textformat/tf_default.c: static void default_print_section_header(AVText
## fftools/textformat/tf_flat.c ##
@@
- #include <string.h>
-
- #include "avtextformat.h"
-+#include "tf_internal.h"
- #include <libavutil/mem.h>
- #include <libavutil/avassert.h>
- #include <libavutil/bprint.h>
-@@
- #include <libavutil/macros.h>
- #include <libavutil/opt.h>
-
+ #include "libavutil/bprint.h"
+ #include "libavutil/error.h"
+ #include "libavutil/opt.h"
+-
-#define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
-#define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
-#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
@@ fftools/textformat/tf_flat.c
- .option = name##_options \
-}
-
--
--/* Flat output */
-+ /* Flat output */
++#include "tf_internal.h"
+
+ /* Flat output */
- typedef struct FlatContext {
- const AVClass *class;
@@ fftools/textformat/tf_flat.c: static void flat_print_section_header(AVTextFormatContext *wctx, const void *dat
{
FlatContext *flat = wctx->priv;
@@ fftools/textformat/tf_flat.c: static void flat_print_section_header(AVTextFormat
## fftools/textformat/tf_ini.c ##
@@
- #include <string.h>
-
- #include "avtextformat.h"
-+#include "tf_internal.h"
- #include <libavutil/mem.h>
- #include <libavutil/avassert.h>
- #include <libavutil/bprint.h>
- #include <libavutil/opt.h>
+ #include "libavutil/bprint.h"
+ #include "libavutil/opt.h"
+-
-#define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
-#define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
-#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
@@ fftools/textformat/tf_ini.c
- .item_name = name##_get_name, \
- .option = name##_options \
-}
--
++#include "tf_internal.h"
+
/* Default output */
- typedef struct DefaultContext {
@@ fftools/textformat/tf_ini.c: static void ini_print_section_header(AVTextFormatContext *wctx, const void *data
{
INIContext *ini = wctx->priv;
@@ fftools/textformat/tf_internal.h (new)
## fftools/textformat/tf_json.c ##
@@
- #include <string.h>
-
#include "avtextformat.h"
-+#include "tf_internal.h"
- #include <libavutil/mem.h>
- #include <libavutil/avassert.h>
- #include <libavutil/bprint.h>
- #include <libavutil/opt.h>
-
+ #include "libavutil/bprint.h"
+ #include "libavutil/opt.h"
+-
-#define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
-#define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
-#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
@@ fftools/textformat/tf_json.c
- .option = name##_options \
-}
-
--
++#include "tf_internal.h"
+
/* JSON output */
- typedef struct JSONContext {
@@ fftools/textformat/tf_json.c: static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx
static void json_print_section_header(AVTextFormatContext *wctx, const void *data)
@@ fftools/textformat/tf_json.c: const AVTextFormatter avtextformatter_json = {
## fftools/textformat/tf_xml.c ##
@@
- #include <string.h>
-
- #include "avtextformat.h"
-+#include "tf_internal.h"
- #include <libavutil/mem.h>
- #include <libavutil/avassert.h>
- #include <libavutil/bprint.h>
-@@
- #include <libavutil/macros.h>
- #include <libavutil/opt.h>
-
+ #include "libavutil/bprint.h"
+ #include "libavutil/error.h"
+ #include "libavutil/opt.h"
+-
-#define writer_w8(wctx_, b_) (wctx_)->writer->writer->writer_w8((wctx_)->writer, b_)
-#define writer_put_str(wctx_, str_) (wctx_)->writer->writer->writer_put_str((wctx_)->writer, str_)
-#define writer_printf(wctx_, fmt_, ...) (wctx_)->writer->writer->writer_printf((wctx_)->writer, fmt_, __VA_ARGS__)
@@ fftools/textformat/tf_xml.c
- .item_name = name##_get_name, \
- .option = name##_options \
-}
--
++#include "tf_internal.h"
+
/* XML output */
- typedef struct XMLContext {
@@ fftools/textformat/tf_xml.c: static av_cold int xml_init(AVTextFormatContext *wctx)
static void xml_print_section_header(AVTextFormatContext *wctx, const void *data)
{
@@ fftools/textformat/tw_avio.c: static void io_put_str(AVTextWriterContext *wctx,
}
+@@ fftools/textformat/tw_avio.c: const AVTextWriter avtextwriter_avio = {
+
+ int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename)
+ {
+- if (!pwctx || !output_filename || !output_filename[0])
++ if (!output_filename || !output_filename[0])
+ return AVERROR(EINVAL);
+
+ IOWriterContext *ctx;
## fftools/textformat/tw_buffer.c ##
@@ fftools/textformat/tw_buffer.c: static void buffer_put_str(AVTextWriterContext *wctx, const char *str)
-: ---------- > 4: a1b358f5c5 fftools/tf_internal: Use ac_default_item_name
4: ce1191411c = 5: 4f6870ed4c fftools/textformat: Add function avtext_print_integer_flags()
5: 5e0f818fd3 = 6: 9c03e66aea fftools/ffmpeg_filter: Move some declaration to new header file
6: 4f3db399c6 = 7: eb54476d00 avfilter/avfilter: Add avfilter_link_get_hw_frames_ctx()
7: 898574385f = 8: dac301adba fftools/resources: Add resource manager files
8: 72aa40edd7 = 9: 128ae47177 fftools/graphprint: Add execution graph printing
9: 3a61edc78d = 10: 0f6fd80b25 fftools/graphprint: Now, make it a Killer-Feature!
--
ffmpeg-codebot
More information about the ffmpeg-devel
mailing list