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() . softworkz (14): fftools/textformat: Formatting and whitespace changes fftools/textformat: Apply quality improvements fftools/avtextformat: Re-use BPrint in loop fftools/textformat: Introduce AVTextFormatOptions for avtext_context_open() fftools/textformat: Introduce common header and deduplicate code fftools/textformat: AVTextWriter change writer_printf signature fftools/tf_internal: Use av_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/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 | 13 +- fftools/graph/filelauncher.c | 205 +++++ fftools/graph/graphprint.c | 1147 ++++++++++++++++++++++++++++ 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 | 229 +++--- fftools/textformat/avtextformat.h | 73 +- 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 | 658 ++++++++++++++++ fftools/textformat/tf_mermaid.h | 41 + fftools/textformat/tf_xml.c | 68 +- fftools/textformat/tw_avio.c | 18 +- fftools/textformat/tw_buffer.c | 7 +- fftools/textformat/tw_stdout.c | 8 +- libavfilter/avfilter.c | 9 + libavfilter/avfilter.h | 12 + 37 files changed, 3686 insertions(+), 557 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: 9e1162bdf1454d7ae3737429bcc6bd66e5da303a Published-As: https://github.com/ffstaging/FFmpeg/releases/tag/pr-ffstaging-66%2Fsoftworkz%2Fsubmit_print_execution_graph-v5 Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-66/softworkz/submit_print_execution_graph-v5 Pull-Request: https://github.com/ffstaging/FFmpeg/pull/66 Range-diff vs v4: 1: dbd9193a0d ! 1: 0672fc41e7 fftools/textformat: Formatting and whitespace changes @@ fftools/textformat/avtextformat.c: static const char *textcontext_get_formatter_ }; @@ fftools/textformat/avtextformat.c: void avtext_context_close(AVTextFormatContext **ptctx) - } --int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *formatter, AVTextWriterContext *writer_context, const char *args, + int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *formatter, AVTextWriterContext *writer_context, const char *args, - const struct AVTextFormatSection *sections, int nb_sections, -- int show_value_unit, -- int use_value_prefix, -- int use_byte_value_binary_prefix, -- int use_value_sexagesimal_format, -- int show_optional_fields, -- char *show_data_hash) -+int avtext_context_open(AVTextFormatContext **ptctx, -+ const AVTextFormatter *formatter, -+ AVTextWriterContext *writer_context, -+ const char *args, -+ const AVTextFormatSection *sections, -+ int nb_sections, -+ int show_value_unit, -+ int use_value_prefix, -+ int use_byte_value_binary_prefix, -+ int use_value_sexagesimal_format, -+ int show_optional_fields, -+ char *show_data_hash) - { - AVTextFormatContext *tctx; - int i, ret = 0; ++ const AVTextFormatSection *sections, int nb_sections, + int show_value_unit, + int use_value_prefix, + int use_byte_value_binary_prefix, @@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form av_dict_free(&opts); } 2: 1516e67a5b ! 2: 1e312f4685 fftools/textformat: Quality improvements @@ Metadata Author: softworkz <softwo...@hotmail.com> ## Commit message ## - fftools/textformat: Quality improvements + fftools/textformat: Apply quality improvements + + Perform multiple improvements to increase code robustness. + In particular: + - favor unsigned counters for loops + - add missing checks + - avoid possibly leaks + - move variable declarations to inner scopes when feasible + - provide explicit type-casting when needed Signed-off-by: softworkz <softwo...@hotmail.com> @@ fftools/textformat/avtextformat.c: static const AVClass textcontext_class = { av_bprintf(bp, "%02X", ubuf[i]); } -@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext **ptctx, +@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form AVTextFormatContext *tctx; int i, ret = 0; -- if (!(tctx = av_mallocz(sizeof(AVTextFormatContext)))) { + if (!ptctx || !formatter) + return AVERROR(EINVAL); + -+ if (!((tctx = av_mallocz(sizeof(AVTextFormatContext))))) { + if (!(tctx = av_mallocz(sizeof(AVTextFormatContext)))) { ret = AVERROR(ENOMEM); goto fail; - } -@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext **ptctx, +@@ fftools/textformat/avtextformat.c: int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form av_log(NULL, AV_LOG_ERROR, " %s", n); av_log(NULL, AV_LOG_ERROR, "\n"); } @@ fftools/textformat/avtextformat.c: void avtext_print_section_footer(AVTextFormat - const struct AVTextFormatSection *section = tctx->section[tctx->level]; + const AVTextFormatSection *section; + -+ if (!key || tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS) -+ return; ++ av_assert0(key && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS); + + section = tctx->section[tctx->level]; if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { tctx->formatter->print_integer(tctx, key, val); -@@ fftools/textformat/avtextformat.c: void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t va - - static inline int validate_string(AVTextFormatContext *tctx, char **dstp, const char *src) - { -- const uint8_t *p, *endp; -+ const uint8_t *p, *endp, *srcp = (const uint8_t *)src; - AVBPrint dstbuf; -+ AVBPrint bp; - int invalid_chars_nb = 0, ret = 0; - -+ *dstp = NULL; - av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED); -+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); - -- endp = src + strlen(src); -- for (p = src; *p;) { -- uint32_t code; -+ endp = srcp + strlen(src); -+ for (p = srcp; *p;) { -+ int32_t code; - int invalid = 0; - const uint8_t *p0 = p; - - if (av_utf8_decode(&code, &p, endp, tctx->string_validation_utf8_flags) < 0) { -- AVBPrint bp; -- av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); -- bprint_bytes(&bp, p0, p-p0); -- av_log(tctx, AV_LOG_DEBUG, -- "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src); -+ av_bprint_clear(&bp); -+ bprint_bytes(&bp, p0, p - p0); -+ av_log(tctx, AV_LOG_DEBUG, "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src); - invalid = 1; - } - -@@ fftools/textformat/avtextformat.c: static inline int validate_string(AVTextFormatContext *tctx, char **dstp, const - } - - if (!invalid || tctx->string_validation == AV_TEXTFORMAT_STRING_VALIDATION_IGNORE) -- av_bprint_append_data(&dstbuf, p0, p-p0); -+ av_bprint_append_data(&dstbuf, (const char *)p0, p - p0); - } - - if (invalid_chars_nb && tctx->string_validation == AV_TEXTFORMAT_STRING_VALIDATION_REPLACE) -@@ fftools/textformat/avtextformat.c: static inline int validate_string(AVTextFormatContext *tctx, char **dstp, const - - end: - av_bprint_finalize(&dstbuf, dstp); -+ av_bprint_finalize(&bp, NULL); - return ret; - } - @@ fftools/textformat/avtextformat.c: struct unit_value { const char *unit; }; @@ fftools/textformat/avtextformat.c: void avtext_print_unit_int(AVTextFormatContex + const AVTextFormatSection *section; int ret = 0; -+ if (!key || !val || tctx->level < 0 || tctx->level >= SECTION_MAX_NB_LEVELS) -+ return AVERROR(EINVAL); ++ av_assert0(key && val && tctx->level >= 0 && tctx->level < SECTION_MAX_NB_LEVELS); + + section = tctx->section[tctx->level]; + @@ fftools/textformat/tf_json.c: static const char *json_escape_str(AVBPrint *dst, const char *p; + if (!src) { -+ av_log(log_ctx, AV_LOG_ERROR, "json_escape_str: NULL source string\n"); ++ av_log(log_ctx, AV_LOG_WARNING, "Cannot escape NULL string, returning NULL\n"); + return NULL; + } + @@ fftools/textformat/tf_json.c: static const char *json_escape_str(AVBPrint *dst, av_bprint_chars(dst, *p, 1); } @@ fftools/textformat/tf_json.c: static void json_print_section_header(AVTextFormatContext *wctx, const void *dat - wctx->section[wctx->level-1] : NULL; - - if (wctx->level && wctx->nb_item[wctx->level-1]) + { + JSONContext *json = wctx->priv; + AVBPrint buf; +- const struct AVTextFormatSection *section = wctx->section[wctx->level]; +- const struct AVTextFormatSection *parent_section = wctx->level ? +- wctx->section[wctx->level-1] : NULL; ++ const AVTextFormatSection *section = wctx->section[wctx->level]; ++ const AVTextFormatSection *parent_section = wctx->level ? wctx->section[wctx->level - 1] : NULL; + +- if (wctx->level && wctx->nb_item[wctx->level-1]) + if (wctx->level && wctx->nb_item[wctx->level - 1]) writer_put_str(wctx, ",\n"); if (section->flags & AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER) { +@@ fftools/textformat/tf_json.c: static void json_print_str(AVTextFormatContext *wctx, const char *key, const cha + static void json_print_int(AVTextFormatContext *wctx, const char *key, int64_t value) + { + JSONContext *json = wctx->priv; +- const struct AVTextFormatSection *parent_section = wctx->level ? +- wctx->section[wctx->level-1] : NULL; ++ const AVTextFormatSection *parent_section = wctx->level ? wctx->section[wctx->level - 1] : NULL; + AVBPrint buf; + + if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE)) ## fftools/textformat/tf_xml.c ## @@ @@ fftools/textformat/tf_xml.c #include "avtextformat.h" ## fftools/textformat/tw_avio.c ## +@@ + #include <string.h> + + #include "avtextwriters.h" ++#include "libavutil/avassert.h" + + #include "libavutil/error.h" + @@ fftools/textformat/tw_avio.c: static void io_w8(AVTextWriterContext *wctx, int b) static void io_put_str(AVTextWriterContext *wctx, const char *str) { @@ fftools/textformat/tw_avio.c: const AVTextWriter avtextwriter_avio = { int avtextwriter_create_file(AVTextWriterContext **pwctx, const char *output_filename) { -+ if (!output_filename || !output_filename[0]) ++ 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; @@ fftools/textformat/tw_avio.c: int avtextwriter_create_file(AVTextWriterContext * int avtextwriter_create_avio(AVTextWriterContext **pwctx, AVIOContext *avio_ctx, int close_on_uninit) { -+ if (!pwctx || !avio_ctx) -+ return AVERROR(EINVAL); ++ av_assert0(avio_ctx); + IOWriterContext *ctx; int ret; -: ---------- > 3: c71836fce0 fftools/avtextformat: Re-use BPrint in loop -: ---------- > 4: 26be409371 fftools/textformat: Introduce AVTextFormatOptions for avtext_context_open() 3: 7024548b92 ! 5: 89da2c883e fftools/textformat: Introduce common header and deduplicate code @@ Commit message Signed-off-by: softworkz <softwo...@hotmail.com> - ## fftools/textformat/avtextwriters.h ## -@@ fftools/textformat/avtextwriters.h: typedef struct AVTextWriter { - void (*uninit)(AVTextWriterContext *wctx); - void (*writer_w8)(AVTextWriterContext *wctx, int b); - void (*writer_put_str)(AVTextWriterContext *wctx, const char *str); -- void (*writer_printf)(AVTextWriterContext *wctx, const char *fmt, ...); -+ void (*writer_printf)(AVTextWriterContext *wctx, const char *fmt, va_list vl); - } AVTextWriter; - - typedef struct AVTextWriterContext { - ## fftools/textformat/tf_compact.c ## @@ #include "libavutil/bprint.h" @@ fftools/textformat/tf_json.c: static const char *json_escape_str(AVBPrint *dst, + const AVTextFormatSection *parent_section = tf_get_parent_section(wctx, wctx->level); JSONContext *json = wctx->priv; AVBPrint buf; -- const struct AVTextFormatSection *section = wctx->section[wctx->level]; -- const struct AVTextFormatSection *parent_section = wctx->level ? -- wctx->section[wctx->level-1] : NULL; - -- if (wctx->level && wctx->nb_item[wctx->level-1]) +- const AVTextFormatSection *section = wctx->section[wctx->level]; +- const AVTextFormatSection *parent_section = wctx->level ? wctx->section[wctx->level - 1] : NULL; ++ + if (!section) + return; -+ + if (wctx->level && wctx->nb_item[wctx->level - 1]) writer_put_str(wctx, ",\n"); - @@ fftools/textformat/tf_json.c: static void json_print_section_header(AVTextFormatContext *wctx, const void *dat static void json_print_section_footer(AVTextFormatContext *wctx) @@ fftools/textformat/tf_json.c: static void json_print_str(AVTextFormatContext *wc { + 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; +- const AVTextFormatSection *parent_section = wctx->level ? wctx->section[wctx->level - 1] : NULL; AVBPrint buf; if (wctx->nb_item[wctx->level] || (parent_section && parent_section->flags & AV_TEXTFORMAT_SECTION_FLAG_NUMBERING_BY_TYPE)) @@ fftools/textformat/tf_xml.c: const AVTextFormatter avtextformatter_xml = { .priv_class = &xml_class, }; - - - ## fftools/textformat/tw_avio.c ## -@@ fftools/textformat/tw_avio.c: static void io_put_str(AVTextWriterContext *wctx, const char *str) - avio_write(ctx->avio_context, (const unsigned char *)str, (int)strlen(str)); - } - --static void io_printf(AVTextWriterContext *wctx, const char *fmt, ...) -+static void io_printf(AVTextWriterContext *wctx, const char *fmt, va_list vl) - { - IOWriterContext *ctx = wctx->priv; -- va_list ap; - -- va_start(ap, fmt); -- avio_vprintf(ctx->avio_context, fmt, ap); -- va_end(ap); -+ avio_vprintf(ctx->avio_context, fmt, vl); - } - - - - ## fftools/textformat/tw_buffer.c ## -@@ fftools/textformat/tw_buffer.c: static void buffer_put_str(AVTextWriterContext *wctx, const char *str) - av_bprintf(ctx->buffer, "%s", str); - } - --static void buffer_printf(AVTextWriterContext *wctx, const char *fmt, ...) -+static void buffer_printf(AVTextWriterContext *wctx, const char *fmt, va_list vl) - { - BufferWriterContext *ctx = wctx->priv; - -- va_list vargs; -- va_start(vargs, fmt); -- av_vbprintf(ctx->buffer, fmt, vargs); -- va_end(vargs); -+ av_vbprintf(ctx->buffer, fmt, vl); - } - - - - ## fftools/textformat/tw_stdout.c ## -@@ fftools/textformat/tw_stdout.c: static inline void stdout_put_str(AVTextWriterContext *wctx, const char *str) - printf("%s", str); - } - --static inline void stdout_printf(AVTextWriterContext *wctx, const char *fmt, ...) -+static inline void stdout_printf(AVTextWriterContext *wctx, const char *fmt, va_list vl) - { -- va_list ap; -- -- va_start(ap, fmt); -- vprintf(fmt, ap); -- va_end(ap); -+ vprintf(fmt, vl); - } - - -: ---------- > 6: ecf6f061b2 fftools/textformat: AVTextWriter change writer_printf signature 4: 4f1218b594 ! 7: c190f79565 fftools/tf_internal: Use ac_default_item_name @@ Metadata Author: softworkz <softwo...@hotmail.com> ## Commit message ## - fftools/tf_internal: Use ac_default_item_name + fftools/tf_internal: Use av_default_item_name Signed-off-by: softworkz <softwo...@hotmail.com> 5: c1fea3027a = 8: 1fe4a8fe6c fftools/textformat: Add function avtext_print_integer_flags() 6: 28aeb7180d = 9: ba034ef3b1 fftools/ffmpeg_filter: Move some declaration to new header file 7: d2ad11ac85 = 10: 6e31aa603a avfilter/avfilter: Add avfilter_link_get_hw_frames_ctx() 8: 9fa93efdda = 11: ea2d41b048 fftools/resources: Add resource manager files 9: 45b2a38592 = 12: 4fa179848a fftools/ffmpeg_mux: Make ms_from_ost() inline 10: 0e52640aca ! 13: 62d4cab294 fftools/graphprint: Add execution graph printing @@ fftools/graph/graphprint.c (new) + goto fail; + } + -+ ret = avtext_context_open(&tfc, text_formatter, wctx, w_args, sections, FF_ARRAY_ELEMS(sections), 0, 0, 0, 0, -1, NULL); ++ AVTextFormatOptions tf_options = { .show_optional_fields = -1 }; ++ ret = avtext_context_open(&tfc, text_formatter, wctx, w_args, sections, FF_ARRAY_ELEMS(sections), tf_options, NULL); + if (ret < 0) { + goto fail; + } 11: 07a8d731ee = 14: 35fc23039e fftools/graphprint: Now, make it a Killer-Feature! -- ffmpeg-codebot _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".