Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint
@ 2025-06-01  3:27 Andreas Rheinhardt
  2025-06-01  4:19 ` softworkz .
  2025-06-01 11:25 ` Andreas Rheinhardt
  0 siblings, 2 replies; 7+ messages in thread
From: Andreas Rheinhardt @ 2025-06-01  3:27 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

[-- Attachment #1: Type: text/plain, Size: 29 bytes --]

Patches attached.

- Andreas

[-- Attachment #2: 0001-fftools-graph-graphprint-Fix-races-when-initializing.patch --]
[-- Type: text/x-patch, Size: 2365 bytes --]

From f33af4ef4913f37458b89f19ec7fb71ae4b39978 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Fri, 30 May 2025 16:02:08 +0200
Subject: [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing
 graphprint

Setting print_graphs_format (in case no -print_graphs_format
option was specified) is racy, as is using av_strtok()
to split it. Both have been removed.

Notice that using av_strtok() was destructive: In the absence
of races the options would only have been applied for the
first initialization.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/graph/graphprint.c | 17 ++---------------
 1 file changed, 2 insertions(+), 15 deletions(-)

diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c
index 852a8f6c0c..b67de3d8c1 100644
--- a/fftools/graph/graphprint.c
+++ b/fftools/graph/graphprint.c
@@ -875,8 +875,6 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
     AVTextFormatContext *tfc = NULL;
     AVTextWriterContext *wctx = NULL;
     GraphPrintContext *gpc = NULL;
-    char *w_args = NULL;
-    char *w_name;
     int ret;
 
     init_sections();
@@ -884,19 +882,7 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
 
     av_bprint_init(target_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
 
-    if (!print_graphs_format)
-        print_graphs_format = av_strdup("json");
-    if (!print_graphs_format) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
-    }
-
-    w_name = av_strtok(print_graphs_format, "=", &w_args);
-    if (!w_name) {
-        av_log(NULL, AV_LOG_ERROR, "No name specified for the filter graph output format\n");
-        ret = AVERROR(EINVAL);
-        goto fail;
-    }
+    const char *w_name = print_graphs_format ? print_graphs_format : "json";
 
     text_formatter = avtext_get_formatter_by_name(w_name);
     if (!text_formatter) {
@@ -913,6 +899,7 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
     }
 
     AVTextFormatOptions tf_options = { .show_optional_fields = -1 };
+    const char *w_args = print_graphs_format ? strchr(print_graphs_format, '=') : NULL;
     ret = avtext_context_open(&tfc, text_formatter, wctx, w_args, sections, FF_ARRAY_ELEMS(sections), tf_options, NULL);
     if (ret < 0) {
         goto fail;
-- 
2.45.2


[-- Attachment #3: 0002-fftools-textformat-avtextformat-Separate-mutable-and.patch --]
[-- Type: text/x-patch, Size: 10914 bytes --]

From 73fa1b52fab230b5755797d5ecb3e293ba89997f Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 00:13:54 +0200
Subject: [PATCH 02/11] fftools/textformat/avtextformat: Separate mutable and
 immutable data

Only two fields of AVTextFormatSection are ever modified:
entries_to_show and show_all_entries (they are only used
by ffprobe; the graph printing code always prints everything).
These fields do not belong into AVTextFormatSection, they are
more ffprobe-internal (and if the graph printing code ever
made use of them, these fields could very well be
per GraphPrintContext).

This commit therefore moves them out of AVTextFormatSection
and adds a callback to AVTextFormatContext to decide which
elements to discard. This also allows to make the AVTextFormatSections
const.

This also fixes a race when initializing the sections
for graphprint.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/ffprobe.c                 | 38 +++++++++++++++++++++++--------
 fftools/graph/graphprint.c        |  9 +-------
 fftools/textformat/avtextformat.c |  9 +++-----
 fftools/textformat/avtextformat.h | 13 +++++++++--
 4 files changed, 44 insertions(+), 25 deletions(-)

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index 80ce38e73b..77a0ea67bf 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -246,7 +246,7 @@ static const char *get_stream_group_type(const void *data)
     return av_x_if_null(avformat_stream_group_name(stg->type), "unknown");
 }
 
-static struct AVTextFormatSection sections[] = {
+static const AVTextFormatSection sections[] = {
     [SECTION_ID_CHAPTERS] =           { SECTION_ID_CHAPTERS, "chapters", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
     [SECTION_ID_CHAPTER] =            { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
     [SECTION_ID_CHAPTER_TAGS] =       { SECTION_ID_CHAPTER_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
@@ -318,6 +318,13 @@ static struct AVTextFormatSection sections[] = {
     [SECTION_ID_SUBTITLE] =           { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
 };
 
+typedef struct EntrySelection {
+    int show_all_entries;
+    AVDictionary *entries_to_show;
+} EntrySelection;
+
+static EntrySelection selected_entries[FF_ARRAY_ELEMS(sections)] = { 0 };
+
 static const OptionDef *options;
 
 /* FFprobe context */
@@ -352,6 +359,14 @@ typedef struct LogBuffer {
 static LogBuffer *log_buffer;
 static int log_buffer_size;
 
+static int is_key_selected_callback(AVTextFormatContext *tctx, const char *key)
+{
+    const AVTextFormatSection *section = tctx->section[tctx->level];
+    const EntrySelection *selection = &selected_entries[section - sections];
+
+    return selection->show_all_entries || av_dict_get(selection->entries_to_show, key, NULL, 0);
+}
+
 static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
 {
     AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
@@ -2655,14 +2670,15 @@ static int opt_format(void *optctx, const char *opt, const char *arg)
 static inline void mark_section_show_entries(SectionID section_id,
                                              int show_all_entries, AVDictionary *entries)
 {
-    struct AVTextFormatSection *section = &sections[section_id];
+    EntrySelection *selection = &selected_entries[section_id];
 
-    section->show_all_entries = show_all_entries;
+    selection->show_all_entries = show_all_entries;
     if (show_all_entries) {
+        const AVTextFormatSection *section = &sections[section_id];
         for (const int *id = section->children_ids; *id != -1; id++)
             mark_section_show_entries(*id, show_all_entries, entries);
     } else {
-        av_dict_copy(&section->entries_to_show, entries, 0);
+        av_dict_copy(&selection->entries_to_show, entries, 0);
     }
 }
 
@@ -3053,9 +3069,12 @@ static const OptionDef real_options[] = {
 
 static inline int check_section_show_entries(int section_id)
 {
-    struct AVTextFormatSection *section = &sections[section_id];
-    if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
+    const EntrySelection *selection = &selected_entries[section_id];
+
+    if (selection->show_all_entries || selection->entries_to_show)
         return 1;
+
+    const AVTextFormatSection *section = &sections[section_id];
     for (const int *id = section->children_ids; *id != -1; id++)
         if (check_section_show_entries(*id))
             return 1;
@@ -3074,7 +3093,7 @@ int main(int argc, char **argv)
     AVTextWriterContext *wctx;
     char *buf;
     char *f_name = NULL, *f_args = NULL;
-    int ret, input_ret, i;
+    int ret, input_ret;
 
     init_dynload();
 
@@ -3168,6 +3187,7 @@ int main(int argc, char **argv)
         goto end;
 
     AVTextFormatOptions tf_options = {
+        .is_key_selected              = is_key_selected_callback,
         .show_optional_fields = show_optional_fields,
         .show_value_unit = show_value_unit,
         .use_value_prefix = use_value_prefix,
@@ -3224,8 +3244,8 @@ end:
     av_freep(&read_intervals);
 
     uninit_opts();
-    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
-        av_dict_free(&(sections[i].entries_to_show));
+    for (size_t i = 0; i < FF_ARRAY_ELEMS(selected_entries); ++i)
+        av_dict_free(&selected_entries[i].entries_to_show);
 
     avformat_network_deinit();
 
diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c
index b67de3d8c1..cb444ecbd2 100644
--- a/fftools/graph/graphprint.c
+++ b/fftools/graph/graphprint.c
@@ -74,7 +74,7 @@ typedef enum {
     SECTION_ID_ENCODER,
 } SectionID;
 
-static struct AVTextFormatSection sections[] = {
+static const AVTextFormatSection sections[] = {
     [SECTION_ID_ROOT]            = { SECTION_ID_ROOT, "root", AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER, { SECTION_ID_FILTERGRAPHS, SECTION_ID_INPUTFILES, SECTION_ID_OUTPUTFILES, SECTION_ID_DECODERS, SECTION_ID_ENCODERS, SECTION_ID_STREAMLINKS, -1 } },
 
     [SECTION_ID_FILTERGRAPHS]    = { SECTION_ID_FILTERGRAPHS, "graphs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTERGRAPH, -1 } },
@@ -470,12 +470,6 @@ static void print_filter(GraphPrintContext *gpc, const AVFilterContext *filter,
     avtext_print_section_footer(tfc); // SECTION_ID_FILTER
 }
 
-static void init_sections(void)
-{
-    for (unsigned i = 0; i < FF_ARRAY_ELEMS(sections); i++)
-        sections[i].show_all_entries = 1;
-}
-
 static void print_filtergraph_single(GraphPrintContext *gpc, FilterGraph *fg, AVFilterGraph *graph)
 {
     AVTextFormatContext *tfc = gpc->tfc;
@@ -877,7 +871,6 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
     GraphPrintContext *gpc = NULL;
     int ret;
 
-    init_sections();
     *pgpc = NULL;
 
     av_bprint_init(target_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index bb90e66918..86512333e4 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -150,6 +150,7 @@ int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form
         goto fail;
     }
 
+    tctx->is_key_selected = options.is_key_selected;
     tctx->show_value_unit = options.show_value_unit;
     tctx->use_value_prefix = options.use_value_prefix;
     tctx->use_byte_value_binary_prefix = options.use_byte_value_binary_prefix;
@@ -293,8 +294,6 @@ void avtext_print_section_footer(AVTextFormatContext *tctx)
 
 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)
@@ -307,9 +306,7 @@ void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t va
 
     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)) {
+    if (!tctx->is_key_selected || tctx->is_key_selected(tctx, key)) {
         tctx->formatter->print_integer(tctx, key, val);
         tctx->nb_item[tctx->level]++;
     }
@@ -464,7 +461,7 @@ int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *
         && !(tctx->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS))
         return 0;
 
-    if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
+    if (!tctx->is_key_selected || tctx->is_key_selected(tctx, key)) {
         if (flags & AV_TEXTFORMAT_PRINT_STRING_VALIDATE) {
             char *key1 = NULL, *val1 = NULL;
             ret = validate_string(tctx, &key1, key);
diff --git a/fftools/textformat/avtextformat.h b/fftools/textformat/avtextformat.h
index cf23d93871..bd8c5d742f 100644
--- a/fftools/textformat/avtextformat.h
+++ b/fftools/textformat/avtextformat.h
@@ -57,9 +57,7 @@ typedef struct AVTextFormatSection {
     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
-    int show_all_entries;
     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
@@ -131,6 +129,16 @@ struct AVTextFormatContext {
     AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
                                                   ///  used by various formatters
 
+    /**
+     * Callback to discard certain elements based upon the key used.
+     * It is called before any element with a key is printed.
+     * If this callback is unset, all elements are printed.
+     *
+     * @retval 1 if the element is supposed to be printed
+     * @retval 0 if the element is supposed to be discarded
+     */
+    int (*is_key_selected)(struct AVTextFormatContext *tctx, const char *key);
+
     int show_optional_fields;
     int show_value_unit;
     int use_value_prefix;
@@ -145,6 +153,7 @@ struct AVTextFormatContext {
 };
 
 typedef struct AVTextFormatOptions {
+    int (*is_key_selected)(struct AVTextFormatContext *tctx, const char *key);
     int show_optional_fields;
     int show_value_unit;
     int use_value_prefix;
-- 
2.45.2


[-- Attachment #4: 0003-fftools-textformat-avtextformat-Avoid-relocations.patch --]
[-- Type: text/x-patch, Size: 878 bytes --]

From dec9b4def2cc85355731ff4050843e08ad0d9907 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 03:33:00 +0200
Subject: [PATCH 03/11] fftools/textformat/avtextformat: Avoid relocations

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/textformat/avtextformat.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index 86512333e4..6c826802f5 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -43,8 +43,8 @@
 static const struct {
     double bin_val;
     double dec_val;
-    const char *bin_str;
-    const char *dec_str;
+    char bin_str[4];
+    char dec_str[4];
 } si_prefixes[] = {
     { 1.0, 1.0, "", "" },
     { 1.024e3, 1e3, "Ki", "K" },
-- 
2.45.2


[-- Attachment #5: 0004-fftools-resources-resman-Don-t-alloc-ResourceManager.patch --]
[-- Type: text/x-patch, Size: 2409 bytes --]

From 0f7626b2b4289644882de9c56ed9b13530aa7f50 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:15:58 +0200
Subject: [PATCH 04/11] fftools/resources/resman: Don't alloc ResourceManager,
 fix race

The resman_ctx pointer was accessed outside of its guarding
mutex.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/resources/resman.c | 37 +++----------------------------------
 1 file changed, 3 insertions(+), 34 deletions(-)

diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c
index a9e21626fa..15285a719b 100644
--- a/fftools/resources/resman.c
+++ b/fftools/resources/resman.c
@@ -61,7 +61,7 @@ typedef struct ResourceManagerContext {
 
 static AVMutex mutex = AV_MUTEX_INITIALIZER;
 
-ResourceManagerContext *resman_ctx = NULL;
+ResourceManagerContext resman_ctx = { .class = &resman_class };
 
 
 #if CONFIG_RESOURCE_COMPRESSION
@@ -118,39 +118,11 @@ static int decompress_gzip(ResourceManagerContext *ctx, uint8_t *in, unsigned in
 }
 #endif
 
-static ResourceManagerContext *get_resman_context(void)
-{
-    ResourceManagerContext *res = resman_ctx;
-
-    ff_mutex_lock(&mutex);
-
-    if (res)
-        goto end;
-
-    res = av_mallocz(sizeof(ResourceManagerContext));
-    if (!res) {
-        av_log(NULL, AV_LOG_ERROR, "Failed to allocate resource manager context\n");
-        goto end;
-    }
-
-    res->class = &resman_class;
-    resman_ctx = res;
-
-end:
-    ff_mutex_unlock(&mutex);
-    return res;
-}
-
-
 void ff_resman_uninit(void)
 {
     ff_mutex_lock(&mutex);
 
-    if (resman_ctx) {
-        if (resman_ctx->resource_dic)
-            av_dict_free(&resman_ctx->resource_dic);
-        av_freep(&resman_ctx);
-    }
+    av_dict_free(&resman_ctx.resource_dic);
 
     ff_mutex_unlock(&mutex);
 }
@@ -158,14 +130,11 @@ void ff_resman_uninit(void)
 
 char *ff_resman_get_string(FFResourceId resource_id)
 {
-    ResourceManagerContext *ctx               = get_resman_context();
+    ResourceManagerContext *ctx = &resman_ctx;
     FFResourceDefinition resource_definition = { 0 };
     AVDictionaryEntry *dic_entry;
     char *res = NULL;
 
-    if (!ctx)
-        return NULL;
-
     for (unsigned i = 0; i < FF_ARRAY_ELEMS(resource_definitions); ++i) {
         FFResourceDefinition def = resource_definitions[i];
         if (def.resource_id == resource_id) {
-- 
2.45.2


[-- Attachment #6: 0005-fftools-resources-resman-Use-assert-for-always-false.patch --]
[-- Type: text/x-patch, Size: 921 bytes --]

From a0c064dfec0d4be6dc24c39d1e5757c5587f4528 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:20:32 +0200
Subject: [PATCH 05/11] fftools/resources/resman: Use assert for always-false
 condition

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/resources/resman.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c
index 15285a719b..02a2a19e1b 100644
--- a/fftools/resources/resman.c
+++ b/fftools/resources/resman.c
@@ -143,10 +143,7 @@ char *ff_resman_get_string(FFResourceId resource_id)
         }
     }
 
-    if (!resource_definition.name) {
-        av_log(ctx, AV_LOG_ERROR, "Unable to find resource with ID %d\n", resource_id);
-        return NULL;
-    }
+    av_assert1(resource_definition.name);
 
     ff_mutex_lock(&mutex);
 
-- 
2.45.2


[-- Attachment #7: 0006-fftools-resources-resman-Remove-unused-AVClass.patch --]
[-- Type: text/x-patch, Size: 1152 bytes --]

From 26aab012d1e4725e87e0fbc3cfcff004e2e04a90 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:24:01 +0200
Subject: [PATCH 06/11] fftools/resources/resman: Remove unused AVClass

If a logging context is needed, the caller should provide one
instead.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/resources/resman.c | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c
index 02a2a19e1b..cc65b25027 100644
--- a/fftools/resources/resman.c
+++ b/fftools/resources/resman.c
@@ -50,18 +50,13 @@ static const FFResourceDefinition resource_definitions[] = {
 };
 
 
-static const AVClass resman_class = {
-    .class_name = "ResourceManager",
-};
-
 typedef struct ResourceManagerContext {
-    const AVClass *class;
     AVDictionary *resource_dic;
 } ResourceManagerContext;
 
 static AVMutex mutex = AV_MUTEX_INITIALIZER;
 
-ResourceManagerContext resman_ctx = { .class = &resman_class };
+ResourceManagerContext resman_ctx = { NULL };
 
 
 #if CONFIG_RESOURCE_COMPRESSION
-- 
2.45.2


[-- Attachment #8: 0007-fftools-textformat-avtextformat-Fix-races-when-initi.patch --]
[-- Type: text/x-patch, Size: 2043 bytes --]

From faf4f6da6ffbd7e44faa49847778e08db889b249 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:28:12 +0200
Subject: [PATCH 07/11] fftools/textformat/avtextformat: Fix races when
 initializing formatters

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/textformat/avtextformat.c | 33 +++++++++++--------------------
 1 file changed, 12 insertions(+), 21 deletions(-)

diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index 6c826802f5..88bed6b18a 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -678,31 +678,22 @@ fail:
     return ret;
 }
 
-static const AVTextFormatter *registered_formatters[9 + 1];
-
-static void formatters_register_all(void)
+static const AVTextFormatter *const registered_formatters[] =
 {
-    static int initialized;
-
-    if (initialized)
-        return;
-    initialized = 1;
-
-    registered_formatters[0] = &avtextformatter_default;
-    registered_formatters[1] = &avtextformatter_compact;
-    registered_formatters[2] = &avtextformatter_csv;
-    registered_formatters[3] = &avtextformatter_flat;
-    registered_formatters[4] = &avtextformatter_ini;
-    registered_formatters[5] = &avtextformatter_json;
-    registered_formatters[6] = &avtextformatter_xml;
-    registered_formatters[7] = &avtextformatter_mermaid;
-    registered_formatters[8] = &avtextformatter_mermaidhtml;
-}
+    &avtextformatter_default,
+    &avtextformatter_compact,
+    &avtextformatter_csv,
+    &avtextformatter_flat,
+    &avtextformatter_ini,
+    &avtextformatter_json,
+    &avtextformatter_xml,
+    &avtextformatter_mermaid,
+    &avtextformatter_mermaidhtml,
+    NULL
+};
 
 const AVTextFormatter *avtext_get_formatter_by_name(const char *name)
 {
-    formatters_register_all();
-
     for (int i = 0; registered_formatters[i]; i++)
         if (!strcmp(registered_formatters[i]->name, name))
             return registered_formatters[i];
-- 
2.45.2


[-- Attachment #9: 0008-fftools-ffprobe-Factor-writing-common-side-data-type.patch --]
[-- Type: text/x-patch, Size: 7831 bytes --]

From 3b1b3153f201951b76eb4125ded9b5ad0d6b25fe Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:54:45 +0200
Subject: [PATCH 08/11] fftools/ffprobe: Factor writing common side data types
 out

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/ffprobe.c | 95 +++++++++++++++++++++--------------------------
 1 file changed, 43 insertions(+), 52 deletions(-)

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index 77a0ea67bf..c150772e70 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -472,6 +472,43 @@ static inline int show_tags(AVTextFormatContext *tfc, AVDictionary *tags, int se
     return ret;
 }
 
+static void print_displaymatrix(AVTextFormatContext *tfc, const int32_t matrix[9])
+{
+    double rotation = av_display_rotation_get(matrix);
+    if (isnan(rotation))
+        rotation = 0;
+    avtext_print_integers(tfc, "displaymatrix", (void*)matrix, 9, " %11d", 3, 4, 1);
+    print_int("rotation", rotation);
+}
+
+static void print_mastering_display_metadata(AVTextFormatContext *tfc,
+                                             const AVMasteringDisplayMetadata *metadata)
+{
+    if (metadata->has_primaries) {
+        print_q("red_x", metadata->display_primaries[0][0], '/');
+        print_q("red_y", metadata->display_primaries[0][1], '/');
+        print_q("green_x", metadata->display_primaries[1][0], '/');
+        print_q("green_y", metadata->display_primaries[1][1], '/');
+        print_q("blue_x", metadata->display_primaries[2][0], '/');
+        print_q("blue_y", metadata->display_primaries[2][1], '/');
+
+        print_q("white_point_x", metadata->white_point[0], '/');
+        print_q("white_point_y", metadata->white_point[1], '/');
+    }
+
+    if (metadata->has_luminance) {
+        print_q("min_luminance", metadata->min_luminance, '/');
+        print_q("max_luminance", metadata->max_luminance, '/');
+    }
+}
+
+static void print_context_light_level(AVTextFormatContext *tfc,
+                                      const AVContentLightMetadata *metadata)
+{
+    print_int("max_content", metadata->MaxCLL);
+    print_int("max_average", metadata->MaxFALL);
+}
+
 static void print_dovi_metadata(AVTextFormatContext *tfc, const AVDOVIMetadata *dovi)
 {
     if (!dovi)
@@ -949,11 +986,7 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
         avtext_print_section_header(tfc, sd, id_data);
         print_str("side_data_type", name ? name : "unknown");
         if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
-            double rotation = av_display_rotation_get((int32_t *)sd->data);
-            if (isnan(rotation))
-                rotation = 0;
-            avtext_print_integers(tfc, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
-            print_int("rotation", rotation);
+            print_displaymatrix(tfc, (const int32_t*)sd->data);
         } else if (sd->type == AV_PKT_DATA_STEREO3D) {
             const AVStereo3D *stereo = (AVStereo3D *)sd->data;
             print_str("type", av_stereo3d_type_name(stereo->type));
@@ -987,28 +1020,9 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
             print_int("skip_reason",     AV_RL8(sd->data + 8));
             print_int("discard_reason",  AV_RL8(sd->data + 9));
         } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
-            AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
-
-            if (metadata->has_primaries) {
-                print_q("red_x", metadata->display_primaries[0][0], '/');
-                print_q("red_y", metadata->display_primaries[0][1], '/');
-                print_q("green_x", metadata->display_primaries[1][0], '/');
-                print_q("green_y", metadata->display_primaries[1][1], '/');
-                print_q("blue_x", metadata->display_primaries[2][0], '/');
-                print_q("blue_y", metadata->display_primaries[2][1], '/');
-
-                print_q("white_point_x", metadata->white_point[0], '/');
-                print_q("white_point_y", metadata->white_point[1], '/');
-            }
-
-            if (metadata->has_luminance) {
-                print_q("min_luminance", metadata->min_luminance, '/');
-                print_q("max_luminance", metadata->max_luminance, '/');
-            }
+            print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data);
         } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
-            AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
-            print_int("max_content", metadata->MaxCLL);
-            print_int("max_average", metadata->MaxFALL);
+            print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
         } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
             print_ambient_viewing_environment(
                 tfc, (const AVAmbientViewingEnvironment *)sd->data);
@@ -1294,11 +1308,7 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
         name = av_frame_side_data_name(sd->type);
         print_str("side_data_type", name ? name : "unknown");
         if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
-            double rotation = av_display_rotation_get((int32_t *)sd->data);
-            if (isnan(rotation))
-                rotation = 0;
-            avtext_print_integers(tfc, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
-            print_int("rotation", rotation);
+            print_displaymatrix(tfc, (const int32_t*)sd->data);
         } else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) {
             print_int("active_format", *sd->data);
         } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
@@ -1318,31 +1328,12 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
             }
             avtext_print_section_footer(tfc);
         } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
-            AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
-
-            if (metadata->has_primaries) {
-                print_q("red_x", metadata->display_primaries[0][0], '/');
-                print_q("red_y", metadata->display_primaries[0][1], '/');
-                print_q("green_x", metadata->display_primaries[1][0], '/');
-                print_q("green_y", metadata->display_primaries[1][1], '/');
-                print_q("blue_x", metadata->display_primaries[2][0], '/');
-                print_q("blue_y", metadata->display_primaries[2][1], '/');
-
-                print_q("white_point_x", metadata->white_point[0], '/');
-                print_q("white_point_y", metadata->white_point[1], '/');
-            }
-
-            if (metadata->has_luminance) {
-                print_q("min_luminance", metadata->min_luminance, '/');
-                print_q("max_luminance", metadata->max_luminance, '/');
-            }
+            print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data);
         } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {
             AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
             print_dynamic_hdr10_plus(tfc, metadata);
         } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
-            AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
-            print_int("max_content", metadata->MaxCLL);
-            print_int("max_average", metadata->MaxFALL);
+            print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
         } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
             const AVDictionaryEntry *tag = av_dict_get(sd->metadata, "name", NULL, AV_DICT_MATCH_CASE);
             if (tag)
-- 
2.45.2


[-- Attachment #10: 0009-fftools-ffprobe-Fix-indentation.patch --]
[-- Type: text/x-patch, Size: 11992 bytes --]

From 4e92413b4870421de5d14a1cd9452e3d8fc372c2 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:59:27 +0200
Subject: [PATCH 09/11] fftools/ffprobe: Fix indentation

Forgotten after d76b0c4a3530005ce59ec1dcaefcb8dd03c4e0ce.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/ffprobe.c | 184 +++++++++++++++++++++++-----------------------
 1 file changed, 92 insertions(+), 92 deletions(-)

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index c150772e70..ab52adbf15 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -981,98 +981,98 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
                                 const AVPacketSideData *sd,
                                 SectionID id_data)
 {
-        const char *name = av_packet_side_data_name(sd->type);
-
-        avtext_print_section_header(tfc, sd, id_data);
-        print_str("side_data_type", name ? name : "unknown");
-        if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
-            print_displaymatrix(tfc, (const int32_t*)sd->data);
-        } else if (sd->type == AV_PKT_DATA_STEREO3D) {
-            const AVStereo3D *stereo = (AVStereo3D *)sd->data;
-            print_str("type", av_stereo3d_type_name(stereo->type));
-            print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
-            print_str("view", av_stereo3d_view_name(stereo->view));
-            print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye));
-            print_int("baseline", stereo->baseline);
-            print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/');
-            print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/');
-        } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
-            const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
-            print_str("projection", av_spherical_projection_name(spherical->projection));
-            if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
-                print_int("padding", spherical->padding);
-            } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
-                size_t l, t, r, b;
-                av_spherical_tile_bounds(spherical, par->width, par->height,
-                                         &l, &t, &r, &b);
-                print_int("bound_left", l);
-                print_int("bound_top", t);
-                print_int("bound_right", r);
-                print_int("bound_bottom", b);
-            }
-
-            print_int("yaw", (double) spherical->yaw / (1 << 16));
-            print_int("pitch", (double) spherical->pitch / (1 << 16));
-            print_int("roll", (double) spherical->roll / (1 << 16));
-        } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
-            print_int("skip_samples",    AV_RL32(sd->data));
-            print_int("discard_padding", AV_RL32(sd->data + 4));
-            print_int("skip_reason",     AV_RL8(sd->data + 8));
-            print_int("discard_reason",  AV_RL8(sd->data + 9));
-        } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
-            print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data);
-        } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
-            print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
-        } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
-            print_ambient_viewing_environment(
-                tfc, (const AVAmbientViewingEnvironment *)sd->data);
-        } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) {
-            AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
-            print_dynamic_hdr10_plus(tfc, metadata);
-        } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
-            AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data;
-            const char *comp = "unknown";
-            print_int("dv_version_major", dovi->dv_version_major);
-            print_int("dv_version_minor", dovi->dv_version_minor);
-            print_int("dv_profile", dovi->dv_profile);
-            print_int("dv_level", dovi->dv_level);
-            print_int("rpu_present_flag", dovi->rpu_present_flag);
-            print_int("el_present_flag", dovi->el_present_flag);
-            print_int("bl_present_flag", dovi->bl_present_flag);
-            print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
-            switch (dovi->dv_md_compression)
-            {
-                case AV_DOVI_COMPRESSION_NONE:     comp = "none";     break;
-                case AV_DOVI_COMPRESSION_LIMITED:  comp = "limited";  break;
-                case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break;
-                case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break;
-            }
-            print_str("dv_md_compression", comp);
-        } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) {
-            enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data;
-            print_int("service_type", *t);
-        } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) {
-            print_int("id", *sd->data);
-        } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) {
-            const AVCPBProperties *prop = (AVCPBProperties *)sd->data;
-            print_int("max_bitrate", prop->max_bitrate);
-            print_int("min_bitrate", prop->min_bitrate);
-            print_int("avg_bitrate", prop->avg_bitrate);
-            print_int("buffer_size", prop->buffer_size);
-            print_int("vbv_delay",   prop->vbv_delay);
-        } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER ||
-                   sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) {
-            if (do_show_data)
-                avtext_print_data(tfc, "data", sd->data, sd->size);
-            avtext_print_data_hash(tfc, "data_hash", sd->data, sd->size);
-        } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) {
-            print_int("crop_top",    AV_RL32(sd->data));
-            print_int("crop_bottom", AV_RL32(sd->data + 4));
-            print_int("crop_left",   AV_RL32(sd->data + 8));
-            print_int("crop_right",  AV_RL32(sd->data + 12));
-        } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {
-            print_int("active_format", *sd->data);
-        }
+    const char *name = av_packet_side_data_name(sd->type);
+
+    avtext_print_section_header(tfc, sd, id_data);
+    print_str("side_data_type", name ? name : "unknown");
+    if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
+        print_displaymatrix(tfc, (const int32_t*)sd->data);
+    } else if (sd->type == AV_PKT_DATA_STEREO3D) {
+        const AVStereo3D *stereo = (AVStereo3D *)sd->data;
+        print_str("type", av_stereo3d_type_name(stereo->type));
+        print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
+        print_str("view", av_stereo3d_view_name(stereo->view));
+        print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye));
+        print_int("baseline", stereo->baseline);
+        print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/');
+        print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/');
+    } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
+        const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
+        print_str("projection", av_spherical_projection_name(spherical->projection));
+        if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
+            print_int("padding", spherical->padding);
+        } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
+            size_t l, t, r, b;
+            av_spherical_tile_bounds(spherical, par->width, par->height,
+                                     &l, &t, &r, &b);
+            print_int("bound_left", l);
+            print_int("bound_top", t);
+            print_int("bound_right", r);
+            print_int("bound_bottom", b);
+        }
+
+        print_int("yaw", (double) spherical->yaw / (1 << 16));
+        print_int("pitch", (double) spherical->pitch / (1 << 16));
+        print_int("roll", (double) spherical->roll / (1 << 16));
+    } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
+        print_int("skip_samples",    AV_RL32(sd->data));
+        print_int("discard_padding", AV_RL32(sd->data + 4));
+        print_int("skip_reason",     AV_RL8(sd->data + 8));
+        print_int("discard_reason",  AV_RL8(sd->data + 9));
+    } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
+        print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data);
+    } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
+        print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
+    } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
+        print_ambient_viewing_environment(
+            tfc, (const AVAmbientViewingEnvironment *)sd->data);
+    } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) {
+        AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
+        print_dynamic_hdr10_plus(tfc, metadata);
+    } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
+        AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data;
+        const char *comp = "unknown";
+        print_int("dv_version_major", dovi->dv_version_major);
+        print_int("dv_version_minor", dovi->dv_version_minor);
+        print_int("dv_profile", dovi->dv_profile);
+        print_int("dv_level", dovi->dv_level);
+        print_int("rpu_present_flag", dovi->rpu_present_flag);
+        print_int("el_present_flag", dovi->el_present_flag);
+        print_int("bl_present_flag", dovi->bl_present_flag);
+        print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
+        switch (dovi->dv_md_compression)
+        {
+            case AV_DOVI_COMPRESSION_NONE:     comp = "none";     break;
+            case AV_DOVI_COMPRESSION_LIMITED:  comp = "limited";  break;
+            case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break;
+            case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break;
+        }
+        print_str("dv_md_compression", comp);
+    } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) {
+        enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data;
+        print_int("service_type", *t);
+    } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) {
+        print_int("id", *sd->data);
+    } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) {
+        const AVCPBProperties *prop = (AVCPBProperties *)sd->data;
+        print_int("max_bitrate", prop->max_bitrate);
+        print_int("min_bitrate", prop->min_bitrate);
+        print_int("avg_bitrate", prop->avg_bitrate);
+        print_int("buffer_size", prop->buffer_size);
+        print_int("vbv_delay",   prop->vbv_delay);
+    } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER ||
+               sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) {
+        if (do_show_data)
+            avtext_print_data(tfc, "data", sd->data, sd->size);
+        avtext_print_data_hash(tfc, "data_hash", sd->data, sd->size);
+    } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) {
+        print_int("crop_top",    AV_RL32(sd->data));
+        print_int("crop_bottom", AV_RL32(sd->data + 4));
+        print_int("crop_left",   AV_RL32(sd->data + 8));
+        print_int("crop_right",  AV_RL32(sd->data + 12));
+    } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {
+        print_int("active_format", *sd->data);
+    }
 }
 
 static void print_private_data(AVTextFormatContext *tfc, void *priv_data)
-- 
2.45.2


[-- Attachment #11: 0010-fftools-textformat-avtextformat-Move-avtext_print_in.patch --]
[-- Type: text/x-patch, Size: 4904 bytes --]

From 647f8dc7d526780b7002a78767b0f027f9674b45 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 05:09:32 +0200
Subject: [PATCH 10/11] fftools/textformat/avtextformat: Move
 avtext_print_integers to ffprobe.c

This is its only user and because this function is so specialised
it is very likely to stay that way. So move it back to ffprobe.c
(where it already was before d7a3f68feae0b1c3718f9d2671c6d41c60a40680).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/ffprobe.c                 | 27 ++++++++++++++++++++++++++-
 fftools/textformat/avtextformat.c | 30 ------------------------------
 fftools/textformat/avtextformat.h |  3 ---
 3 files changed, 26 insertions(+), 34 deletions(-)

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index ab52adbf15..9552f31f1e 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -446,6 +446,31 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
 #define print_duration_ts(k, v)       avtext_print_ts(tfc, k, v, 1)
 #define print_val(k, v, u)      avtext_print_unit_int(tfc, k, v, u)
 
+static void print_integers(AVTextFormatContext *tfc, const char *key,
+                           const void *data, int size, const char *format,
+                           int columns, int bytes, int offset_add)
+{
+    AVBPrint bp;
+    unsigned offset = 0;
+
+    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
+    av_bprint_chars(&bp, '\n', 1);
+    while (size) {
+        av_bprintf(&bp, "%08x: ", offset);
+        int l = FFMIN(size, columns);
+        for (int i = 0; i < l; i++) {
+            if      (bytes == 1) av_bprintf(&bp, format, *(const uint8_t*)data);
+            else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
+            else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
+            data = (const char*)data + bytes;
+            size--;
+        }
+        av_bprint_chars(&bp, '\n', 1);
+        offset += offset_add;
+    }
+    avtext_print_string(tfc, key, bp.str, 0);
+}
+
 #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n)                        \
 {                                                                       \
     ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr)));           \
@@ -477,7 +502,7 @@ static void print_displaymatrix(AVTextFormatContext *tfc, const int32_t matrix[9
     double rotation = av_display_rotation_get(matrix);
     if (isnan(rotation))
         rotation = 0;
-    avtext_print_integers(tfc, "displaymatrix", (void*)matrix, 9, " %11d", 3, 4, 1);
+    print_integers(tfc, "displaymatrix", matrix, 9, " %11d", 3, 4, 1);
     print_int("rotation", rotation);
 }
 
diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index 88bed6b18a..18cf528140 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -562,36 +562,6 @@ void avtext_print_data_hash(AVTextFormatContext *tctx, const char *key,
     avtext_print_string(tctx, key, buf, 0);
 }
 
-void avtext_print_integers(AVTextFormatContext *tctx, const char *key,
-                           uint8_t *data, int size, const char *format,
-                           int columns, int bytes, int offset_add)
-{
-    AVBPrint bp;
-    unsigned offset = 0;
-    int l, i;
-
-    if (!key || !data || !format || columns <= 0 || bytes <= 0)
-        return;
-
-    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
-    av_bprintf(&bp, "\n");
-    while (size) {
-        av_bprintf(&bp, "%08x: ", offset);
-        l = FFMIN(size, columns);
-        for (i = 0; i < l; i++) {
-            if      (bytes == 1) av_bprintf(&bp, format, *data);
-            else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
-            else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
-            data += bytes;
-            size--;
-        }
-        av_bprintf(&bp, "\n");
-        offset += offset_add;
-    }
-    avtext_print_string(tctx, key, bp.str, 0);
-    av_bprint_finalize(&bp, NULL);
-}
-
 static const char *writercontext_get_writer_name(void *p)
 {
     AVTextWriterContext *wctx = p;
diff --git a/fftools/textformat/avtextformat.h b/fftools/textformat/avtextformat.h
index bd8c5d742f..4354181df4 100644
--- a/fftools/textformat/avtextformat.h
+++ b/fftools/textformat/avtextformat.h
@@ -190,9 +190,6 @@ void avtext_print_data(AVTextFormatContext *tctx, const char *key, const uint8_t
 
 void avtext_print_data_hash(AVTextFormatContext *tctx, const char *key, const uint8_t *data, int size);
 
-void avtext_print_integers(AVTextFormatContext *tctx, const char *key, uint8_t *data, int size,
-                           const char *format, int columns, int bytes, int offset_add);
-
 const AVTextFormatter *avtext_get_formatter_by_name(const char *name);
 
 extern const AVTextFormatter avtextformatter_default;
-- 
2.45.2


[-- Attachment #12: 0011-fftools-graph-graphprint-Remove-redundant-avio_flush.patch --]
[-- Type: text/x-patch, Size: 1076 bytes --]

From 322edd2386a83ee244c676c6e48dbe4f062ec461 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 05:14:23 +0200
Subject: [PATCH 11/11] fftools/graph/graphprint: Remove redundant avio_flush()

The AVIOContext will be automatically flushed upon closure.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/graph/graphprint.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c
index cb444ecbd2..66d809a75a 100644
--- a/fftools/graph/graphprint.c
+++ b/fftools/graph/graphprint.c
@@ -1065,7 +1065,6 @@ static int print_filtergraphs_priv(FilterGraph **graphs, int nb_graphs, InputFil
             }
 
             avio_write(avio, (const unsigned char *)target_buf.str, FFMIN(target_buf.len, target_buf.size - 1));
-            avio_flush(avio);
 
             if ((ret = avio_closep(&avio)) < 0)
                 av_log(NULL, AV_LOG_ERROR, "Error closing graph output file, loss of information possible: %s\n", av_err2str(ret));
-- 
2.45.2


[-- Attachment #13: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint
  2025-06-01  3:27 [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint Andreas Rheinhardt
@ 2025-06-01  4:19 ` softworkz .
  2025-06-01 10:39   ` Andreas Rheinhardt
  2025-06-01 11:25 ` Andreas Rheinhardt
  1 sibling, 1 reply; 7+ messages in thread
From: softworkz . @ 2025-06-01  4:19 UTC (permalink / raw)
  To: FFmpeg development discussions and patches; +Cc: Stefano Sabatini



> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of Andreas
> Rheinhardt
> Sent: Sonntag, 1. Juni 2025 05:27
> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
> Subject: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when
> initializing graphprint
> 
> Patches attached.
> 
> - Andreas


Hi Andreas,

thanks for the patches - most looking good from a glance.

I have a few questions:

- Why do you want to remove the ResourceManager AVClass?
  It wasn't unused. Now the prefix is gone for log entries in 
  decompress_gzip()
  Actually, all av_log() calls should include the resman_ctx
  Seems this has been forgotten (well..by me)
  
- For the registered_formatters initialization:
  I used to have initialization order issues when I had tried
  with static initialization. That's the reason for those functions
  Probably you've done it differently as it seems to work so far 

- In resman.c:64 - should the resman_ctx be static?


Thanks
sw
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint
  2025-06-01  4:19 ` softworkz .
@ 2025-06-01 10:39   ` Andreas Rheinhardt
  2025-06-01 21:41     ` softworkz .
  0 siblings, 1 reply; 7+ messages in thread
From: Andreas Rheinhardt @ 2025-06-01 10:39 UTC (permalink / raw)
  To: ffmpeg-devel

softworkz .:
> 
> 
>> -----Original Message-----
>> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of Andreas
>> Rheinhardt
>> Sent: Sonntag, 1. Juni 2025 05:27
>> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
>> Subject: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when
>> initializing graphprint
>>
>> Patches attached.
>>
>> - Andreas
> 
> 
> Hi Andreas,,
> 
> thanks for the patches - most looking good from a glance.
> 
> I have a few questions:
> 
> - Why do you want to remove the ResourceManager AVClass?

Because I think callers should provide their own logcontext, instead of
adding yet another AVClass that is likely never used.

>   It wasn't unused. Now the prefix is gone for log entries in 
>   decompress_gzip()

True, this patch is just wrong (in case of decompression errors,
av_log() will treat ResourceManagerContext as a logging context,
although it is no more; this would lead to segfaults if AVDictionary is
already set, i.e. when initializing the second resource).

>   Actually, all av_log() calls should include the resman_ctx
>   Seems this has been forgotten (well..by me)
>   
> - For the registered_formatters initialization:
>   I used to have initialization order issues when I had tried
>   with static initialization. That's the reason for those functions
>   Probably you've done it differently as it seems to work so far 

What issues?

> 
> - In resman.c:64 - should the resman_ctx be static?

Yes, of course. Will change it in the patch.

Also notice that patch #1 needs to be fixed, too (it failed when actual
options were passed). Will send an updated version soon.

- Andreas

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint
  2025-06-01  3:27 [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint Andreas Rheinhardt
  2025-06-01  4:19 ` softworkz .
@ 2025-06-01 11:25 ` Andreas Rheinhardt
  1 sibling, 0 replies; 7+ messages in thread
From: Andreas Rheinhardt @ 2025-06-01 11:25 UTC (permalink / raw)
  To: ffmpeg-devel

[-- Attachment #1: Type: text/plain, Size: 82 bytes --]

Andreas Rheinhardt:
> Patches attached.
> 
> - Andreas
> 
v2 attached.

- Andreas

[-- Attachment #2: v2-0001-fftools-graph-graphprint-Fix-races-when-initializ.patch --]
[-- Type: text/x-patch, Size: 3188 bytes --]

From f9ca71e0ef66830ba9a9a04f9f44d76abe352a0f Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Fri, 30 May 2025 16:02:08 +0200
Subject: [PATCH v2 01/11] fftools/graph/graphprint: Fix races when
 initializing graphprint

Setting print_graphs_format (in case no -print_graphs_format
option was specified) is racy, as is using av_strtok()
to split it. Both have been removed.

Notice that using av_strtok() was destructive: In the absence
of races the options would only have been applied for the
first initialization.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/graph/graphprint.c        | 19 ++++---------------
 fftools/textformat/avtextformat.c |  7 +++++--
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c
index 852a8f6c0c..f87ccfa0e7 100644
--- a/fftools/graph/graphprint.c
+++ b/fftools/graph/graphprint.c
@@ -875,8 +875,6 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
     AVTextFormatContext *tfc = NULL;
     AVTextWriterContext *wctx = NULL;
     GraphPrintContext *gpc = NULL;
-    char *w_args = NULL;
-    char *w_name;
     int ret;
 
     init_sections();
@@ -884,19 +882,7 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
 
     av_bprint_init(target_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
 
-    if (!print_graphs_format)
-        print_graphs_format = av_strdup("json");
-    if (!print_graphs_format) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
-    }
-
-    w_name = av_strtok(print_graphs_format, "=", &w_args);
-    if (!w_name) {
-        av_log(NULL, AV_LOG_ERROR, "No name specified for the filter graph output format\n");
-        ret = AVERROR(EINVAL);
-        goto fail;
-    }
+    const char *w_name = print_graphs_format ? print_graphs_format : "json";
 
     text_formatter = avtext_get_formatter_by_name(w_name);
     if (!text_formatter) {
@@ -913,6 +899,9 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
     }
 
     AVTextFormatOptions tf_options = { .show_optional_fields = -1 };
+    const char *w_args = print_graphs_format ? strchr(print_graphs_format, '=') : NULL;
+    if (w_args)
+        ++w_args; // consume '='
     ret = avtext_context_open(&tfc, text_formatter, wctx, w_args, sections, FF_ARRAY_ELEMS(sections), tf_options, NULL);
     if (ret < 0) {
         goto fail;
diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index bb90e66918..e8e43c3c37 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -706,9 +706,12 @@ const AVTextFormatter *avtext_get_formatter_by_name(const char *name)
 {
     formatters_register_all();
 
-    for (int i = 0; registered_formatters[i]; i++)
-        if (!strcmp(registered_formatters[i]->name, name))
+    for (int i = 0; registered_formatters[i]; i++) {
+        const char *end;
+        if (av_strstart(name, registered_formatters[i]->name, &end) &&
+            (*end == '\0' || *end == '='))
             return registered_formatters[i];
+    }
 
     return NULL;
 }
-- 
2.45.2


[-- Attachment #3: v2-0002-fftools-textformat-avtextformat-Separate-mutable-.patch --]
[-- Type: text/x-patch, Size: 10917 bytes --]

From eecebb8da4094472ddda35bfcef3e9337e9ce92f Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 00:13:54 +0200
Subject: [PATCH v2 02/11] fftools/textformat/avtextformat: Separate mutable
 and immutable data

Only two fields of AVTextFormatSection are ever modified:
entries_to_show and show_all_entries (they are only used
by ffprobe; the graph printing code always prints everything).
These fields do not belong into AVTextFormatSection, they are
more ffprobe-internal (and if the graph printing code ever
made use of them, these fields could very well be
per GraphPrintContext).

This commit therefore moves them out of AVTextFormatSection
and adds a callback to AVTextFormatContext to decide which
elements to discard. This also allows to make the AVTextFormatSections
const.

This also fixes a race when initializing the sections
for graphprint.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/ffprobe.c                 | 38 +++++++++++++++++++++++--------
 fftools/graph/graphprint.c        |  9 +-------
 fftools/textformat/avtextformat.c |  9 +++-----
 fftools/textformat/avtextformat.h | 13 +++++++++--
 4 files changed, 44 insertions(+), 25 deletions(-)

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index 80ce38e73b..77a0ea67bf 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -246,7 +246,7 @@ static const char *get_stream_group_type(const void *data)
     return av_x_if_null(avformat_stream_group_name(stg->type), "unknown");
 }
 
-static struct AVTextFormatSection sections[] = {
+static const AVTextFormatSection sections[] = {
     [SECTION_ID_CHAPTERS] =           { SECTION_ID_CHAPTERS, "chapters", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
     [SECTION_ID_CHAPTER] =            { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
     [SECTION_ID_CHAPTER_TAGS] =       { SECTION_ID_CHAPTER_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
@@ -318,6 +318,13 @@ static struct AVTextFormatSection sections[] = {
     [SECTION_ID_SUBTITLE] =           { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
 };
 
+typedef struct EntrySelection {
+    int show_all_entries;
+    AVDictionary *entries_to_show;
+} EntrySelection;
+
+static EntrySelection selected_entries[FF_ARRAY_ELEMS(sections)] = { 0 };
+
 static const OptionDef *options;
 
 /* FFprobe context */
@@ -352,6 +359,14 @@ typedef struct LogBuffer {
 static LogBuffer *log_buffer;
 static int log_buffer_size;
 
+static int is_key_selected_callback(AVTextFormatContext *tctx, const char *key)
+{
+    const AVTextFormatSection *section = tctx->section[tctx->level];
+    const EntrySelection *selection = &selected_entries[section - sections];
+
+    return selection->show_all_entries || av_dict_get(selection->entries_to_show, key, NULL, 0);
+}
+
 static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
 {
     AVClass* avc = ptr ? *(AVClass **) ptr : NULL;
@@ -2655,14 +2670,15 @@ static int opt_format(void *optctx, const char *opt, const char *arg)
 static inline void mark_section_show_entries(SectionID section_id,
                                              int show_all_entries, AVDictionary *entries)
 {
-    struct AVTextFormatSection *section = &sections[section_id];
+    EntrySelection *selection = &selected_entries[section_id];
 
-    section->show_all_entries = show_all_entries;
+    selection->show_all_entries = show_all_entries;
     if (show_all_entries) {
+        const AVTextFormatSection *section = &sections[section_id];
         for (const int *id = section->children_ids; *id != -1; id++)
             mark_section_show_entries(*id, show_all_entries, entries);
     } else {
-        av_dict_copy(&section->entries_to_show, entries, 0);
+        av_dict_copy(&selection->entries_to_show, entries, 0);
     }
 }
 
@@ -3053,9 +3069,12 @@ static const OptionDef real_options[] = {
 
 static inline int check_section_show_entries(int section_id)
 {
-    struct AVTextFormatSection *section = &sections[section_id];
-    if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
+    const EntrySelection *selection = &selected_entries[section_id];
+
+    if (selection->show_all_entries || selection->entries_to_show)
         return 1;
+
+    const AVTextFormatSection *section = &sections[section_id];
     for (const int *id = section->children_ids; *id != -1; id++)
         if (check_section_show_entries(*id))
             return 1;
@@ -3074,7 +3093,7 @@ int main(int argc, char **argv)
     AVTextWriterContext *wctx;
     char *buf;
     char *f_name = NULL, *f_args = NULL;
-    int ret, input_ret, i;
+    int ret, input_ret;
 
     init_dynload();
 
@@ -3168,6 +3187,7 @@ int main(int argc, char **argv)
         goto end;
 
     AVTextFormatOptions tf_options = {
+        .is_key_selected              = is_key_selected_callback,
         .show_optional_fields = show_optional_fields,
         .show_value_unit = show_value_unit,
         .use_value_prefix = use_value_prefix,
@@ -3224,8 +3244,8 @@ end:
     av_freep(&read_intervals);
 
     uninit_opts();
-    for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
-        av_dict_free(&(sections[i].entries_to_show));
+    for (size_t i = 0; i < FF_ARRAY_ELEMS(selected_entries); ++i)
+        av_dict_free(&selected_entries[i].entries_to_show);
 
     avformat_network_deinit();
 
diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c
index f87ccfa0e7..71dd421245 100644
--- a/fftools/graph/graphprint.c
+++ b/fftools/graph/graphprint.c
@@ -74,7 +74,7 @@ typedef enum {
     SECTION_ID_ENCODER,
 } SectionID;
 
-static struct AVTextFormatSection sections[] = {
+static const AVTextFormatSection sections[] = {
     [SECTION_ID_ROOT]            = { SECTION_ID_ROOT, "root", AV_TEXTFORMAT_SECTION_FLAG_IS_WRAPPER, { SECTION_ID_FILTERGRAPHS, SECTION_ID_INPUTFILES, SECTION_ID_OUTPUTFILES, SECTION_ID_DECODERS, SECTION_ID_ENCODERS, SECTION_ID_STREAMLINKS, -1 } },
 
     [SECTION_ID_FILTERGRAPHS]    = { SECTION_ID_FILTERGRAPHS, "graphs", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_FILTERGRAPH, -1 } },
@@ -470,12 +470,6 @@ static void print_filter(GraphPrintContext *gpc, const AVFilterContext *filter,
     avtext_print_section_footer(tfc); // SECTION_ID_FILTER
 }
 
-static void init_sections(void)
-{
-    for (unsigned i = 0; i < FF_ARRAY_ELEMS(sections); i++)
-        sections[i].show_all_entries = 1;
-}
-
 static void print_filtergraph_single(GraphPrintContext *gpc, FilterGraph *fg, AVFilterGraph *graph)
 {
     AVTextFormatContext *tfc = gpc->tfc;
@@ -877,7 +871,6 @@ static int init_graphprint(GraphPrintContext **pgpc, AVBPrint *target_buf)
     GraphPrintContext *gpc = NULL;
     int ret;
 
-    init_sections();
     *pgpc = NULL;
 
     av_bprint_init(target_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index e8e43c3c37..8a87b9ee2c 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -150,6 +150,7 @@ int avtext_context_open(AVTextFormatContext **ptctx, const AVTextFormatter *form
         goto fail;
     }
 
+    tctx->is_key_selected = options.is_key_selected;
     tctx->show_value_unit = options.show_value_unit;
     tctx->use_value_prefix = options.use_value_prefix;
     tctx->use_byte_value_binary_prefix = options.use_byte_value_binary_prefix;
@@ -293,8 +294,6 @@ void avtext_print_section_footer(AVTextFormatContext *tctx)
 
 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)
@@ -307,9 +306,7 @@ void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t va
 
     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)) {
+    if (!tctx->is_key_selected || tctx->is_key_selected(tctx, key)) {
         tctx->formatter->print_integer(tctx, key, val);
         tctx->nb_item[tctx->level]++;
     }
@@ -464,7 +461,7 @@ int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *
         && !(tctx->formatter->flags & AV_TEXTFORMAT_FLAG_SUPPORTS_OPTIONAL_FIELDS))
         return 0;
 
-    if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
+    if (!tctx->is_key_selected || tctx->is_key_selected(tctx, key)) {
         if (flags & AV_TEXTFORMAT_PRINT_STRING_VALIDATE) {
             char *key1 = NULL, *val1 = NULL;
             ret = validate_string(tctx, &key1, key);
diff --git a/fftools/textformat/avtextformat.h b/fftools/textformat/avtextformat.h
index cf23d93871..bd8c5d742f 100644
--- a/fftools/textformat/avtextformat.h
+++ b/fftools/textformat/avtextformat.h
@@ -57,9 +57,7 @@ typedef struct AVTextFormatSection {
     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
-    int show_all_entries;
     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
@@ -131,6 +129,16 @@ struct AVTextFormatContext {
     AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
                                                   ///  used by various formatters
 
+    /**
+     * Callback to discard certain elements based upon the key used.
+     * It is called before any element with a key is printed.
+     * If this callback is unset, all elements are printed.
+     *
+     * @retval 1 if the element is supposed to be printed
+     * @retval 0 if the element is supposed to be discarded
+     */
+    int (*is_key_selected)(struct AVTextFormatContext *tctx, const char *key);
+
     int show_optional_fields;
     int show_value_unit;
     int use_value_prefix;
@@ -145,6 +153,7 @@ struct AVTextFormatContext {
 };
 
 typedef struct AVTextFormatOptions {
+    int (*is_key_selected)(struct AVTextFormatContext *tctx, const char *key);
     int show_optional_fields;
     int show_value_unit;
     int use_value_prefix;
-- 
2.45.2


[-- Attachment #4: v2-0003-fftools-textformat-avtextformat-Avoid-relocations.patch --]
[-- Type: text/x-patch, Size: 881 bytes --]

From 109843e52da507b8d78e70050157746345b490d9 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 03:33:00 +0200
Subject: [PATCH v2 03/11] fftools/textformat/avtextformat: Avoid relocations

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/textformat/avtextformat.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index 8a87b9ee2c..81c6b0f0e5 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -43,8 +43,8 @@
 static const struct {
     double bin_val;
     double dec_val;
-    const char *bin_str;
-    const char *dec_str;
+    char bin_str[4];
+    char dec_str[4];
 } si_prefixes[] = {
     { 1.0, 1.0, "", "" },
     { 1.024e3, 1e3, "Ki", "K" },
-- 
2.45.2


[-- Attachment #5: v2-0004-fftools-resources-resman-Don-t-alloc-ResourceMana.patch --]
[-- Type: text/x-patch, Size: 2521 bytes --]

From be5d966c8d422546eb403cc4c0a007cfb459708c Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:15:58 +0200
Subject: [PATCH v2 04/11] fftools/resources/resman: Don't alloc
 ResourceManager, fix race

The resman_ctx pointer was accessed outside of its guarding
mutex.

Also make the ResourceManager static.

Reviewed-by: softworkz . <softworkz-at-hotmail.com@ffmpeg.org>
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/resources/resman.c | 37 +++----------------------------------
 1 file changed, 3 insertions(+), 34 deletions(-)

diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c
index a9e21626fa..e596c28039 100644
--- a/fftools/resources/resman.c
+++ b/fftools/resources/resman.c
@@ -61,7 +61,7 @@ typedef struct ResourceManagerContext {
 
 static AVMutex mutex = AV_MUTEX_INITIALIZER;
 
-ResourceManagerContext *resman_ctx = NULL;
+static ResourceManagerContext resman_ctx = { .class = &resman_class };
 
 
 #if CONFIG_RESOURCE_COMPRESSION
@@ -118,39 +118,11 @@ static int decompress_gzip(ResourceManagerContext *ctx, uint8_t *in, unsigned in
 }
 #endif
 
-static ResourceManagerContext *get_resman_context(void)
-{
-    ResourceManagerContext *res = resman_ctx;
-
-    ff_mutex_lock(&mutex);
-
-    if (res)
-        goto end;
-
-    res = av_mallocz(sizeof(ResourceManagerContext));
-    if (!res) {
-        av_log(NULL, AV_LOG_ERROR, "Failed to allocate resource manager context\n");
-        goto end;
-    }
-
-    res->class = &resman_class;
-    resman_ctx = res;
-
-end:
-    ff_mutex_unlock(&mutex);
-    return res;
-}
-
-
 void ff_resman_uninit(void)
 {
     ff_mutex_lock(&mutex);
 
-    if (resman_ctx) {
-        if (resman_ctx->resource_dic)
-            av_dict_free(&resman_ctx->resource_dic);
-        av_freep(&resman_ctx);
-    }
+    av_dict_free(&resman_ctx.resource_dic);
 
     ff_mutex_unlock(&mutex);
 }
@@ -158,14 +130,11 @@ void ff_resman_uninit(void)
 
 char *ff_resman_get_string(FFResourceId resource_id)
 {
-    ResourceManagerContext *ctx               = get_resman_context();
+    ResourceManagerContext *ctx = &resman_ctx;
     FFResourceDefinition resource_definition = { 0 };
     AVDictionaryEntry *dic_entry;
     char *res = NULL;
 
-    if (!ctx)
-        return NULL;
-
     for (unsigned i = 0; i < FF_ARRAY_ELEMS(resource_definitions); ++i) {
         FFResourceDefinition def = resource_definitions[i];
         if (def.resource_id == resource_id) {
-- 
2.45.2


[-- Attachment #6: v2-0005-fftools-resources-resman-Use-assert-for-always-fa.patch --]
[-- Type: text/x-patch, Size: 924 bytes --]

From f6d469ca8484dfa44e6ba3cdeba6aec641b75d3a Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:20:32 +0200
Subject: [PATCH v2 05/11] fftools/resources/resman: Use assert for
 always-false condition

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/resources/resman.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c
index e596c28039..dcbf43097d 100644
--- a/fftools/resources/resman.c
+++ b/fftools/resources/resman.c
@@ -143,10 +143,7 @@ char *ff_resman_get_string(FFResourceId resource_id)
         }
     }
 
-    if (!resource_definition.name) {
-        av_log(ctx, AV_LOG_ERROR, "Unable to find resource with ID %d\n", resource_id);
-        return NULL;
-    }
+    av_assert1(resource_definition.name);
 
     ff_mutex_lock(&mutex);
 
-- 
2.45.2


[-- Attachment #7: v2-0006-fftools-resources-resman-Use-proper-logcontext.patch --]
[-- Type: text/x-patch, Size: 2356 bytes --]

From 07c9664733e92fdd1e9a7d2372a8ca35508e1ca8 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 13:06:14 +0200
Subject: [PATCH v2 06/11] fftools/resources/resman: Use proper logcontext

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/resources/resman.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fftools/resources/resman.c b/fftools/resources/resman.c
index dcbf43097d..1c0cdb942d 100644
--- a/fftools/resources/resman.c
+++ b/fftools/resources/resman.c
@@ -160,13 +160,13 @@ char *ff_resman_get_string(FFResourceId resource_id)
         int ret = decompress_gzip(ctx, (uint8_t *)resource_definition.data, *resource_definition.data_len, &out, &out_len);
 
         if (ret) {
-            av_log(NULL, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id);
+            av_log(ctx, AV_LOG_ERROR, "Unable to decompress the resource with ID %d\n", resource_id);
             goto end;
         }
 
         dict_ret = av_dict_set(&ctx->resource_dic, resource_definition.name, out, 0);
         if (dict_ret < 0) {
-            av_log(NULL, AV_LOG_ERROR, "Failed to store decompressed resource in dictionary: %d\n", dict_ret);
+            av_log(ctx, AV_LOG_ERROR, "Failed to store decompressed resource in dictionary: %d\n", dict_ret);
             av_freep(&out);
             goto end;
         }
@@ -176,7 +176,7 @@ char *ff_resman_get_string(FFResourceId resource_id)
 
         dict_ret = av_dict_set(&ctx->resource_dic, resource_definition.name, (const char *)resource_definition.data, 0);
         if (dict_ret < 0) {
-            av_log(NULL, AV_LOG_ERROR, "Failed to store resource in dictionary: %d\n", dict_ret);
+            av_log(ctx, AV_LOG_ERROR, "Failed to store resource in dictionary: %d\n", dict_ret);
             goto end;
         }
 
@@ -184,7 +184,7 @@ char *ff_resman_get_string(FFResourceId resource_id)
         dic_entry = av_dict_get(ctx->resource_dic, resource_definition.name, NULL, 0);
 
         if (!dic_entry) {
-            av_log(NULL, AV_LOG_ERROR, "Failed to retrieve resource from dictionary after storing it\n");
+            av_log(ctx, AV_LOG_ERROR, "Failed to retrieve resource from dictionary after storing it\n");
             goto end;
         }
     }
-- 
2.45.2


[-- Attachment #8: v2-0007-fftools-textformat-avtextformat-Fix-races-when-in.patch --]
[-- Type: text/x-patch, Size: 2040 bytes --]

From edd6477256f13432efac6673c93d830a7b38fd91 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:28:12 +0200
Subject: [PATCH v2 07/11] fftools/textformat/avtextformat: Fix races when
 initializing formatters

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/textformat/avtextformat.c | 33 +++++++++++--------------------
 1 file changed, 12 insertions(+), 21 deletions(-)

diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index 81c6b0f0e5..30a017d1a1 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -678,31 +678,22 @@ fail:
     return ret;
 }
 
-static const AVTextFormatter *registered_formatters[9 + 1];
-
-static void formatters_register_all(void)
+static const AVTextFormatter *const registered_formatters[] =
 {
-    static int initialized;
-
-    if (initialized)
-        return;
-    initialized = 1;
-
-    registered_formatters[0] = &avtextformatter_default;
-    registered_formatters[1] = &avtextformatter_compact;
-    registered_formatters[2] = &avtextformatter_csv;
-    registered_formatters[3] = &avtextformatter_flat;
-    registered_formatters[4] = &avtextformatter_ini;
-    registered_formatters[5] = &avtextformatter_json;
-    registered_formatters[6] = &avtextformatter_xml;
-    registered_formatters[7] = &avtextformatter_mermaid;
-    registered_formatters[8] = &avtextformatter_mermaidhtml;
-}
+    &avtextformatter_default,
+    &avtextformatter_compact,
+    &avtextformatter_csv,
+    &avtextformatter_flat,
+    &avtextformatter_ini,
+    &avtextformatter_json,
+    &avtextformatter_xml,
+    &avtextformatter_mermaid,
+    &avtextformatter_mermaidhtml,
+    NULL
+};
 
 const AVTextFormatter *avtext_get_formatter_by_name(const char *name)
 {
-    formatters_register_all();
-
     for (int i = 0; registered_formatters[i]; i++) {
         const char *end;
         if (av_strstart(name, registered_formatters[i]->name, &end) &&
-- 
2.45.2


[-- Attachment #9: v2-0008-fftools-ffprobe-Factor-writing-common-side-data-t.patch --]
[-- Type: text/x-patch, Size: 7840 bytes --]

From d2971ee087bc07a49454335e77cab7af966ff3bc Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:54:45 +0200
Subject: [PATCH v2 08/11] fftools/ffprobe: Factor writing common side data
 types out

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/ffprobe.c | 95 +++++++++++++++++++++--------------------------
 1 file changed, 43 insertions(+), 52 deletions(-)

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index 77a0ea67bf..5cf5839202 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -472,6 +472,43 @@ static inline int show_tags(AVTextFormatContext *tfc, AVDictionary *tags, int se
     return ret;
 }
 
+static void print_displaymatrix(AVTextFormatContext *tfc, const int32_t matrix[9])
+{
+    double rotation = av_display_rotation_get(matrix);
+    if (isnan(rotation))
+        rotation = 0;
+    avtext_print_integers(tfc, "displaymatrix", (void*)matrix, 9, " %11d", 3, 4, 1);
+    print_int("rotation", rotation);
+}
+
+static void print_mastering_display_metadata(AVTextFormatContext *tfc,
+                                             const AVMasteringDisplayMetadata *metadata)
+{
+    if (metadata->has_primaries) {
+        print_q("red_x",   metadata->display_primaries[0][0], '/');
+        print_q("red_y",   metadata->display_primaries[0][1], '/');
+        print_q("green_x", metadata->display_primaries[1][0], '/');
+        print_q("green_y", metadata->display_primaries[1][1], '/');
+        print_q("blue_x",  metadata->display_primaries[2][0], '/');
+        print_q("blue_y",  metadata->display_primaries[2][1], '/');
+
+        print_q("white_point_x", metadata->white_point[0], '/');
+        print_q("white_point_y", metadata->white_point[1], '/');
+    }
+
+    if (metadata->has_luminance) {
+        print_q("min_luminance", metadata->min_luminance, '/');
+        print_q("max_luminance", metadata->max_luminance, '/');
+    }
+}
+
+static void print_context_light_level(AVTextFormatContext *tfc,
+                                      const AVContentLightMetadata *metadata)
+{
+    print_int("max_content", metadata->MaxCLL);
+    print_int("max_average", metadata->MaxFALL);
+}
+
 static void print_dovi_metadata(AVTextFormatContext *tfc, const AVDOVIMetadata *dovi)
 {
     if (!dovi)
@@ -949,11 +986,7 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
         avtext_print_section_header(tfc, sd, id_data);
         print_str("side_data_type", name ? name : "unknown");
         if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
-            double rotation = av_display_rotation_get((int32_t *)sd->data);
-            if (isnan(rotation))
-                rotation = 0;
-            avtext_print_integers(tfc, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
-            print_int("rotation", rotation);
+            print_displaymatrix(tfc, (const int32_t*)sd->data);
         } else if (sd->type == AV_PKT_DATA_STEREO3D) {
             const AVStereo3D *stereo = (AVStereo3D *)sd->data;
             print_str("type", av_stereo3d_type_name(stereo->type));
@@ -987,28 +1020,9 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
             print_int("skip_reason",     AV_RL8(sd->data + 8));
             print_int("discard_reason",  AV_RL8(sd->data + 9));
         } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
-            AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
-
-            if (metadata->has_primaries) {
-                print_q("red_x", metadata->display_primaries[0][0], '/');
-                print_q("red_y", metadata->display_primaries[0][1], '/');
-                print_q("green_x", metadata->display_primaries[1][0], '/');
-                print_q("green_y", metadata->display_primaries[1][1], '/');
-                print_q("blue_x", metadata->display_primaries[2][0], '/');
-                print_q("blue_y", metadata->display_primaries[2][1], '/');
-
-                print_q("white_point_x", metadata->white_point[0], '/');
-                print_q("white_point_y", metadata->white_point[1], '/');
-            }
-
-            if (metadata->has_luminance) {
-                print_q("min_luminance", metadata->min_luminance, '/');
-                print_q("max_luminance", metadata->max_luminance, '/');
-            }
+            print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data);
         } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
-            AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
-            print_int("max_content", metadata->MaxCLL);
-            print_int("max_average", metadata->MaxFALL);
+            print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
         } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
             print_ambient_viewing_environment(
                 tfc, (const AVAmbientViewingEnvironment *)sd->data);
@@ -1294,11 +1308,7 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
         name = av_frame_side_data_name(sd->type);
         print_str("side_data_type", name ? name : "unknown");
         if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
-            double rotation = av_display_rotation_get((int32_t *)sd->data);
-            if (isnan(rotation))
-                rotation = 0;
-            avtext_print_integers(tfc, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
-            print_int("rotation", rotation);
+            print_displaymatrix(tfc, (const int32_t*)sd->data);
         } else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) {
             print_int("active_format", *sd->data);
         } else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
@@ -1318,31 +1328,12 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
             }
             avtext_print_section_footer(tfc);
         } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) {
-            AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
-
-            if (metadata->has_primaries) {
-                print_q("red_x", metadata->display_primaries[0][0], '/');
-                print_q("red_y", metadata->display_primaries[0][1], '/');
-                print_q("green_x", metadata->display_primaries[1][0], '/');
-                print_q("green_y", metadata->display_primaries[1][1], '/');
-                print_q("blue_x", metadata->display_primaries[2][0], '/');
-                print_q("blue_y", metadata->display_primaries[2][1], '/');
-
-                print_q("white_point_x", metadata->white_point[0], '/');
-                print_q("white_point_y", metadata->white_point[1], '/');
-            }
-
-            if (metadata->has_luminance) {
-                print_q("min_luminance", metadata->min_luminance, '/');
-                print_q("max_luminance", metadata->max_luminance, '/');
-            }
+            print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data);
         } else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {
             AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
             print_dynamic_hdr10_plus(tfc, metadata);
         } else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
-            AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data;
-            print_int("max_content", metadata->MaxCLL);
-            print_int("max_average", metadata->MaxFALL);
+            print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
         } else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
             const AVDictionaryEntry *tag = av_dict_get(sd->metadata, "name", NULL, AV_DICT_MATCH_CASE);
             if (tag)
-- 
2.45.2


[-- Attachment #10: v2-0009-fftools-ffprobe-Fix-indentation.patch --]
[-- Type: text/x-patch, Size: 11995 bytes --]

From 17da5c4e50cb1f2190291d543ab797219ac525d9 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 04:59:27 +0200
Subject: [PATCH v2 09/11] fftools/ffprobe: Fix indentation

Forgotten after d76b0c4a3530005ce59ec1dcaefcb8dd03c4e0ce.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/ffprobe.c | 184 +++++++++++++++++++++++-----------------------
 1 file changed, 92 insertions(+), 92 deletions(-)

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index 5cf5839202..91976fb8ec 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -981,98 +981,98 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
                                 const AVPacketSideData *sd,
                                 SectionID id_data)
 {
-        const char *name = av_packet_side_data_name(sd->type);
-
-        avtext_print_section_header(tfc, sd, id_data);
-        print_str("side_data_type", name ? name : "unknown");
-        if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
-            print_displaymatrix(tfc, (const int32_t*)sd->data);
-        } else if (sd->type == AV_PKT_DATA_STEREO3D) {
-            const AVStereo3D *stereo = (AVStereo3D *)sd->data;
-            print_str("type", av_stereo3d_type_name(stereo->type));
-            print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
-            print_str("view", av_stereo3d_view_name(stereo->view));
-            print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye));
-            print_int("baseline", stereo->baseline);
-            print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/');
-            print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/');
-        } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
-            const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
-            print_str("projection", av_spherical_projection_name(spherical->projection));
-            if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
-                print_int("padding", spherical->padding);
-            } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
-                size_t l, t, r, b;
-                av_spherical_tile_bounds(spherical, par->width, par->height,
-                                         &l, &t, &r, &b);
-                print_int("bound_left", l);
-                print_int("bound_top", t);
-                print_int("bound_right", r);
-                print_int("bound_bottom", b);
-            }
-
-            print_int("yaw", (double) spherical->yaw / (1 << 16));
-            print_int("pitch", (double) spherical->pitch / (1 << 16));
-            print_int("roll", (double) spherical->roll / (1 << 16));
-        } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
-            print_int("skip_samples",    AV_RL32(sd->data));
-            print_int("discard_padding", AV_RL32(sd->data + 4));
-            print_int("skip_reason",     AV_RL8(sd->data + 8));
-            print_int("discard_reason",  AV_RL8(sd->data + 9));
-        } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
-            print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data);
-        } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
-            print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
-        } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
-            print_ambient_viewing_environment(
-                tfc, (const AVAmbientViewingEnvironment *)sd->data);
-        } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) {
-            AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
-            print_dynamic_hdr10_plus(tfc, metadata);
-        } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
-            AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data;
-            const char *comp = "unknown";
-            print_int("dv_version_major", dovi->dv_version_major);
-            print_int("dv_version_minor", dovi->dv_version_minor);
-            print_int("dv_profile", dovi->dv_profile);
-            print_int("dv_level", dovi->dv_level);
-            print_int("rpu_present_flag", dovi->rpu_present_flag);
-            print_int("el_present_flag", dovi->el_present_flag);
-            print_int("bl_present_flag", dovi->bl_present_flag);
-            print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
-            switch (dovi->dv_md_compression)
-            {
-                case AV_DOVI_COMPRESSION_NONE:     comp = "none";     break;
-                case AV_DOVI_COMPRESSION_LIMITED:  comp = "limited";  break;
-                case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break;
-                case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break;
-            }
-            print_str("dv_md_compression", comp);
-        } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) {
-            enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data;
-            print_int("service_type", *t);
-        } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) {
-            print_int("id", *sd->data);
-        } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) {
-            const AVCPBProperties *prop = (AVCPBProperties *)sd->data;
-            print_int("max_bitrate", prop->max_bitrate);
-            print_int("min_bitrate", prop->min_bitrate);
-            print_int("avg_bitrate", prop->avg_bitrate);
-            print_int("buffer_size", prop->buffer_size);
-            print_int("vbv_delay",   prop->vbv_delay);
-        } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER ||
-                   sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) {
-            if (do_show_data)
-                avtext_print_data(tfc, "data", sd->data, sd->size);
-            avtext_print_data_hash(tfc, "data_hash", sd->data, sd->size);
-        } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) {
-            print_int("crop_top",    AV_RL32(sd->data));
-            print_int("crop_bottom", AV_RL32(sd->data + 4));
-            print_int("crop_left",   AV_RL32(sd->data + 8));
-            print_int("crop_right",  AV_RL32(sd->data + 12));
-        } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {
-            print_int("active_format", *sd->data);
-        }
+    const char *name = av_packet_side_data_name(sd->type);
+
+    avtext_print_section_header(tfc, sd, id_data);
+    print_str("side_data_type", name ? name : "unknown");
+    if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
+        print_displaymatrix(tfc, (const int32_t*)sd->data);
+    } else if (sd->type == AV_PKT_DATA_STEREO3D) {
+        const AVStereo3D *stereo = (AVStereo3D *)sd->data;
+        print_str("type", av_stereo3d_type_name(stereo->type));
+        print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT));
+        print_str("view", av_stereo3d_view_name(stereo->view));
+        print_str("primary_eye", av_stereo3d_primary_eye_name(stereo->primary_eye));
+        print_int("baseline", stereo->baseline);
+        print_q("horizontal_disparity_adjustment", stereo->horizontal_disparity_adjustment, '/');
+        print_q("horizontal_field_of_view", stereo->horizontal_field_of_view, '/');
+    } else if (sd->type == AV_PKT_DATA_SPHERICAL) {
+        const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data;
+        print_str("projection", av_spherical_projection_name(spherical->projection));
+        if (spherical->projection == AV_SPHERICAL_CUBEMAP) {
+            print_int("padding", spherical->padding);
+        } else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
+            size_t l, t, r, b;
+            av_spherical_tile_bounds(spherical, par->width, par->height,
+                                     &l, &t, &r, &b);
+            print_int("bound_left", l);
+            print_int("bound_top", t);
+            print_int("bound_right", r);
+            print_int("bound_bottom", b);
+        }
+
+        print_int("yaw", (double) spherical->yaw / (1 << 16));
+        print_int("pitch", (double) spherical->pitch / (1 << 16));
+        print_int("roll", (double) spherical->roll / (1 << 16));
+    } else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) {
+        print_int("skip_samples",    AV_RL32(sd->data));
+        print_int("discard_padding", AV_RL32(sd->data + 4));
+        print_int("skip_reason",     AV_RL8(sd->data + 8));
+        print_int("discard_reason",  AV_RL8(sd->data + 9));
+    } else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) {
+        print_mastering_display_metadata(tfc, (AVMasteringDisplayMetadata *)sd->data);
+    } else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) {
+        print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
+    } else if (sd->type == AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT) {
+        print_ambient_viewing_environment(
+            tfc, (const AVAmbientViewingEnvironment *)sd->data);
+    } else if (sd->type == AV_PKT_DATA_DYNAMIC_HDR10_PLUS) {
+        AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
+        print_dynamic_hdr10_plus(tfc, metadata);
+    } else if (sd->type == AV_PKT_DATA_DOVI_CONF) {
+        AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data;
+        const char *comp = "unknown";
+        print_int("dv_version_major", dovi->dv_version_major);
+        print_int("dv_version_minor", dovi->dv_version_minor);
+        print_int("dv_profile", dovi->dv_profile);
+        print_int("dv_level", dovi->dv_level);
+        print_int("rpu_present_flag", dovi->rpu_present_flag);
+        print_int("el_present_flag", dovi->el_present_flag);
+        print_int("bl_present_flag", dovi->bl_present_flag);
+        print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id);
+        switch (dovi->dv_md_compression)
+        {
+            case AV_DOVI_COMPRESSION_NONE:     comp = "none";     break;
+            case AV_DOVI_COMPRESSION_LIMITED:  comp = "limited";  break;
+            case AV_DOVI_COMPRESSION_RESERVED: comp = "reserved"; break;
+            case AV_DOVI_COMPRESSION_EXTENDED: comp = "extended"; break;
+        }
+        print_str("dv_md_compression", comp);
+    } else if (sd->type == AV_PKT_DATA_AUDIO_SERVICE_TYPE) {
+        enum AVAudioServiceType *t = (enum AVAudioServiceType *)sd->data;
+        print_int("service_type", *t);
+    } else if (sd->type == AV_PKT_DATA_MPEGTS_STREAM_ID) {
+        print_int("id", *sd->data);
+    } else if (sd->type == AV_PKT_DATA_CPB_PROPERTIES) {
+        const AVCPBProperties *prop = (AVCPBProperties *)sd->data;
+        print_int("max_bitrate", prop->max_bitrate);
+        print_int("min_bitrate", prop->min_bitrate);
+        print_int("avg_bitrate", prop->avg_bitrate);
+        print_int("buffer_size", prop->buffer_size);
+        print_int("vbv_delay",   prop->vbv_delay);
+    } else if (sd->type == AV_PKT_DATA_WEBVTT_IDENTIFIER ||
+               sd->type == AV_PKT_DATA_WEBVTT_SETTINGS) {
+        if (do_show_data)
+            avtext_print_data(tfc, "data", sd->data, sd->size);
+        avtext_print_data_hash(tfc, "data_hash", sd->data, sd->size);
+    } else if (sd->type == AV_PKT_DATA_FRAME_CROPPING && sd->size >= sizeof(uint32_t) * 4) {
+        print_int("crop_top",    AV_RL32(sd->data));
+        print_int("crop_bottom", AV_RL32(sd->data + 4));
+        print_int("crop_left",   AV_RL32(sd->data + 8));
+        print_int("crop_right",  AV_RL32(sd->data + 12));
+    } else if (sd->type == AV_PKT_DATA_AFD && sd->size > 0) {
+        print_int("active_format", *sd->data);
+    }
 }
 
 static void print_private_data(AVTextFormatContext *tfc, void *priv_data)
-- 
2.45.2


[-- Attachment #11: v2-0010-fftools-textformat-avtextformat-Move-avtext_print.patch --]
[-- Type: text/x-patch, Size: 4907 bytes --]

From eb86578fa6a561b973f577b652e9fb7b2c58d8ba Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 05:09:32 +0200
Subject: [PATCH v2 10/11] fftools/textformat/avtextformat: Move
 avtext_print_integers to ffprobe.c

This is its only user and because this function is so specialised
it is very likely to stay that way. So move it back to ffprobe.c
(where it already was before d7a3f68feae0b1c3718f9d2671c6d41c60a40680).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/ffprobe.c                 | 27 ++++++++++++++++++++++++++-
 fftools/textformat/avtextformat.c | 30 ------------------------------
 fftools/textformat/avtextformat.h |  3 ---
 3 files changed, 26 insertions(+), 34 deletions(-)

diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c
index 91976fb8ec..61c2260ea4 100644
--- a/fftools/ffprobe.c
+++ b/fftools/ffprobe.c
@@ -446,6 +446,31 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
 #define print_duration_ts(k, v)       avtext_print_ts(tfc, k, v, 1)
 #define print_val(k, v, u)      avtext_print_unit_int(tfc, k, v, u)
 
+static void print_integers(AVTextFormatContext *tfc, const char *key,
+                           const void *data, int size, const char *format,
+                           int columns, int bytes, int offset_add)
+{
+    AVBPrint bp;
+    unsigned offset = 0;
+
+    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
+    av_bprint_chars(&bp, '\n', 1);
+    while (size) {
+        av_bprintf(&bp, "%08x: ", offset);
+        int l = FFMIN(size, columns);
+        for (int i = 0; i < l; i++) {
+            if      (bytes == 1) av_bprintf(&bp, format, *(const uint8_t*)data);
+            else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
+            else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
+            data = (const char*)data + bytes;
+            size--;
+        }
+        av_bprint_chars(&bp, '\n', 1);
+        offset += offset_add;
+    }
+    avtext_print_string(tfc, key, bp.str, 0);
+}
+
 #define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n)                        \
 {                                                                       \
     ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr)));           \
@@ -477,7 +502,7 @@ static void print_displaymatrix(AVTextFormatContext *tfc, const int32_t matrix[9
     double rotation = av_display_rotation_get(matrix);
     if (isnan(rotation))
         rotation = 0;
-    avtext_print_integers(tfc, "displaymatrix", (void*)matrix, 9, " %11d", 3, 4, 1);
+    print_integers(tfc, "displaymatrix", matrix, 9, " %11d", 3, 4, 1);
     print_int("rotation", rotation);
 }
 
diff --git a/fftools/textformat/avtextformat.c b/fftools/textformat/avtextformat.c
index 30a017d1a1..532d0f5bfc 100644
--- a/fftools/textformat/avtextformat.c
+++ b/fftools/textformat/avtextformat.c
@@ -562,36 +562,6 @@ void avtext_print_data_hash(AVTextFormatContext *tctx, const char *key,
     avtext_print_string(tctx, key, buf, 0);
 }
 
-void avtext_print_integers(AVTextFormatContext *tctx, const char *key,
-                           uint8_t *data, int size, const char *format,
-                           int columns, int bytes, int offset_add)
-{
-    AVBPrint bp;
-    unsigned offset = 0;
-    int l, i;
-
-    if (!key || !data || !format || columns <= 0 || bytes <= 0)
-        return;
-
-    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
-    av_bprintf(&bp, "\n");
-    while (size) {
-        av_bprintf(&bp, "%08x: ", offset);
-        l = FFMIN(size, columns);
-        for (i = 0; i < l; i++) {
-            if      (bytes == 1) av_bprintf(&bp, format, *data);
-            else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
-            else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
-            data += bytes;
-            size--;
-        }
-        av_bprintf(&bp, "\n");
-        offset += offset_add;
-    }
-    avtext_print_string(tctx, key, bp.str, 0);
-    av_bprint_finalize(&bp, NULL);
-}
-
 static const char *writercontext_get_writer_name(void *p)
 {
     AVTextWriterContext *wctx = p;
diff --git a/fftools/textformat/avtextformat.h b/fftools/textformat/avtextformat.h
index bd8c5d742f..4354181df4 100644
--- a/fftools/textformat/avtextformat.h
+++ b/fftools/textformat/avtextformat.h
@@ -190,9 +190,6 @@ void avtext_print_data(AVTextFormatContext *tctx, const char *key, const uint8_t
 
 void avtext_print_data_hash(AVTextFormatContext *tctx, const char *key, const uint8_t *data, int size);
 
-void avtext_print_integers(AVTextFormatContext *tctx, const char *key, uint8_t *data, int size,
-                           const char *format, int columns, int bytes, int offset_add);
-
 const AVTextFormatter *avtext_get_formatter_by_name(const char *name);
 
 extern const AVTextFormatter avtextformatter_default;
-- 
2.45.2


[-- Attachment #12: v2-0011-fftools-graph-graphprint-Remove-redundant-avio_fl.patch --]
[-- Type: text/x-patch, Size: 1080 bytes --]

From 48d07ef12388878832dcc4ecf91fc0508ff38216 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 1 Jun 2025 05:14:23 +0200
Subject: [PATCH v2 11/11] fftools/graph/graphprint: Remove redundant
 avio_flush()

The AVIOContext will be automatically flushed upon closure.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 fftools/graph/graphprint.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/fftools/graph/graphprint.c b/fftools/graph/graphprint.c
index 71dd421245..6152866313 100644
--- a/fftools/graph/graphprint.c
+++ b/fftools/graph/graphprint.c
@@ -1067,7 +1067,6 @@ static int print_filtergraphs_priv(FilterGraph **graphs, int nb_graphs, InputFil
             }
 
             avio_write(avio, (const unsigned char *)target_buf.str, FFMIN(target_buf.len, target_buf.size - 1));
-            avio_flush(avio);
 
             if ((ret = avio_closep(&avio)) < 0)
                 av_log(NULL, AV_LOG_ERROR, "Error closing graph output file, loss of information possible: %s\n", av_err2str(ret));
-- 
2.45.2


[-- Attachment #13: Type: text/plain, Size: 251 bytes --]

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint
  2025-06-01 10:39   ` Andreas Rheinhardt
@ 2025-06-01 21:41     ` softworkz .
  2025-06-01 22:07       ` Andreas Rheinhardt
  0 siblings, 1 reply; 7+ messages in thread
From: softworkz . @ 2025-06-01 21:41 UTC (permalink / raw)
  To: FFmpeg development discussions and patches



> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of Andreas
> Rheinhardt
> Sent: Sonntag, 1. Juni 2025 12:40
> To: ffmpeg-devel@ffmpeg.org
> Subject: Re: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races
> when initializing graphprint


Hi Andreas,

thanks for v2.


> > - Why do you want to remove the ResourceManager AVClass?
> 
> Because I think callers should provide their own logcontext

Do we have any precedent cases for this? What would be the 
parameter type for passing it - AVClass* ?



> >   It wasn't unused. Now the prefix is gone for log entries in
> >   decompress_gzip()
> 
> True, this patch is just wrong (in case of decompression errors,
> av_log() will treat ResourceManagerContext as a logging context,
> although it is no more; this would lead to segfaults if AVDictionary is
> already set, i.e. when initializing the second resource).

Yes, I had seen it crashing once as well when moving debugger 
execution to an av_log line during the second execution.
All good now!

> >   Actually, all av_log() calls should include the resman_ctx
> >   Seems this has been forgotten (well..by me)

Thanks for fixing!


> > - For the registered_formatters initialization:
> >   I used to have initialization order issues when I had tried
> >   with static initialization. That's the reason for those functions
> >   Probably you've done it differently as it seems to work so far
> 
> What issues?

Here's my comment from an earlier review:

----

> > +static const AVTextFormatter *registered_formatters[7+1];
> 
> maybe use a const here, also I'd be more happy if we had a more
> dynamic registration system to avoid the hardcoded bits

While trying this, I remembered that I had tried this before already, but it causes trouble with static initialization order. Probably that's the reason why it has been like this before already, I'm not sure?

----

What I had seen: The registered_formatters array was initialized before 
static initialization of all its members had been done.
It happened at a rather early stage, so it is well possible that it is 
resolved by changes that were made meanwhile. 
FATE tests are passing, so it's probably fine, now.




Here's my full review:

v2-0001-fftools-graph-graphprint-Fix-races-when-initializ

LGTM, I wasn't aware that av_strtok() is destructive,
maybe the doc text should mention it. s param being 
non-const might give a hint, but it's still a bit 
unexpected for anybody who doesn't know all the APIs
by heart.

Now that it's no longer updated, should print_graphs_format
be made const? Same for print_graphs_file?
Could also be in a future patch, though.


v2-0002-fftools-textformat-avtextformat-Separate-mutable-

I am aware of the mixed mutability in the section
definitions. The general idea of separation and making
the section definitions immutable is right of course.

Yet, the general goal is to build a versatile API for
other use cases, so we should not make changes based
on "x is currently used by a only, not by b, so make
it local to a".

The ability to limit the fields that should be output
for each section is an essential feature that should
be generally available for all usages, that's why it
should rather go in the opposite direction - i.e. 
from FFprobe (where it's specific atm) to the API.
I haven't come to do that yet.


We should also hear what Stefano will say about it,
as far as I understood he sees it similar, but I 
might be wrong.



v2-0003-fftools-textformat-avtextformat-Avoid-relocations

LGTM


v2-0004-fftools-resources-resman-Don-t-alloc-ResourceMana

LGTM


v2-0005-fftools-resources-resman-Use-assert-for-always-fa

LGTM


v2-0006-fftools-resources-resman-Use-proper-logcontext

LGTM, thanks!


v2-0007-fftools-textformat-avtextformat-Fix-races-when-in

LGTM


v2-0008-fftools-ffprobe-Factor-writing-common-side-data-t

LGTM


v2-0009-fftools-ffprobe-Fix-indentation

LGTM


v2-0010-fftools-textformat-avtextformat-Move-avtext_print

avtext_print_integers() allows to print binary data in 
a tabular layout and various formats.

It is generally useful and not specific to FFprobe's
usage. AFAIR, Stefano had seen it the same way.


v2-0011-fftools-graph-graphprint-Remove-redundant-avio_fl

LGTM


In summary

v2-0002-fftools-textformat-avtextformat-Separate-mutable-
v2-0010-fftools-textformat-avtextformat-Move-avtext_print

Should wait for Stefano to comment.


All others are good to go.


Thanks
sw
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint
  2025-06-01 21:41     ` softworkz .
@ 2025-06-01 22:07       ` Andreas Rheinhardt
  2025-06-01 23:14         ` softworkz .
  0 siblings, 1 reply; 7+ messages in thread
From: Andreas Rheinhardt @ 2025-06-01 22:07 UTC (permalink / raw)
  To: ffmpeg-devel

softworkz .:
> 
> 
>> -----Original Message-----
>> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of Andreas
>> Rheinhardt
>> Sent: Sonntag, 1. Juni 2025 12:40
>> To: ffmpeg-devel@ffmpeg.org
>> Subject: Re: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races
>> when initializing graphprint
> 
> 
> Hi Andreas,
> 
> thanks for v2.
> 
> 
>>> - Why do you want to remove the ResourceManager AVClass?
>>
>> Because I think callers should provide their own logcontext
> 
> Do we have any precedent cases for this? What would be the 
> parameter type for passing it - AVClass* ?
> 

The type would be void*. AVClass* is wrong (AVClass** would be correct).
There are lots of functions with a logcontext parameter (see git grep -E
'void \*log_?ctx' *.h)

> 
> 
>>>   It wasn't unused. Now the prefix is gone for log entries in
>>>   decompress_gzip()
>>
>> True, this patch is just wrong (in case of decompression errors,
>> av_log() will treat ResourceManagerContext as a logging context,
>> although it is no more; this would lead to segfaults if AVDictionary is
>> already set, i.e. when initializing the second resource).
> 
> Yes, I had seen it crashing once as well when moving debugger 
> execution to an av_log line during the second execution.
> All good now!
> 
>>>   Actually, all av_log() calls should include the resman_ctx
>>>   Seems this has been forgotten (well..by me)
> 
> Thanks for fixing!
> 
> 
>>> - For the registered_formatters initialization:
>>>   I used to have initialization order issues when I had tried
>>>   with static initialization. That's the reason for those functions
>>>   Probably you've done it differently as it seems to work so far
>>
>> What issues?
> 
> Here's my comment from an earlier review:
> 
> ----
> 
>>> +static const AVTextFormatter *registered_formatters[7+1];
>>
>> maybe use a const here, also I'd be more happy if we had a more
>> dynamic registration system to avoid the hardcoded bits
> 
> While trying this, I remembered that I had tried this before already, but it causes trouble with static initialization order. Probably that's the reason why it has been like this before already, I'm not sure?
> 
> ---->
> What I had seen: The registered_formatters array was initialized before 
> static initialization of all its members had been done.
> It happened at a rather early stage, so it is well possible that it is 
> resolved by changes that were made meanwhile. 
> FATE tests are passing, so it's probably fine, now.

FATE is mostly useless here, given that graphprint is not covered by it.

> Here's my full review:
> 
> v2-0001-fftools-graph-graphprint-Fix-races-when-initializ
> 
> LGTM, I wasn't aware that av_strtok() is destructive,
> maybe the doc text should mention it. s param being 
> non-const might give a hint, but it's still a bit 
> unexpected for anybody who doesn't know all the APIs
> by heart.
> 
> Now that it's no longer updated, should print_graphs_format
> be made const? Same for print_graphs_file?

They are updated generically, via the option system. Making them const
would lead to compiler warnings from the "{ &print_graphs_format },"
line in the options definition. Furthermore, the compiler would put
these variables into .rodata if they were made const, which would lead
to crashes if the user sets the relevant options.

> 
> 
> v2-0002-fftools-textformat-avtextformat-Separate-mutable-
> 
> I am aware of the mixed mutability in the section
> definitions. The general idea of separation and making
> the section definitions immutable is right of course.
> 
> Yet, the general goal is to build a versatile API for
> other use cases, so we should not make changes based
> on "x is currently used by a only, not by b, so make
> it local to a".
> 
> The ability to limit the fields that should be output
> for each section is an essential feature that should
> be generally available for all usages, that's why it
> should rather go in the opposite direction - i.e. 
> from FFprobe (where it's specific atm) to the API.
> I haven't come to do that yet.
> 
> 
> We should also hear what Stefano will say about it,
> as far as I understood he sees it similar, but I 
> might be wrong.

I'll of course wait for Stefano, but already want to add that nothing is
more versatile than a callback.

> 
> 
> 
> v2-0003-fftools-textformat-avtextformat-Avoid-relocations
> 
> LGTM
> 
> 
> v2-0004-fftools-resources-resman-Don-t-alloc-ResourceMana
> 
> LGTM
> 
> 
> v2-0005-fftools-resources-resman-Use-assert-for-always-fa
> 
> LGTM
> 
> 
> v2-0006-fftools-resources-resman-Use-proper-logcontext
> 
> LGTM, thanks!
> 
> 
> v2-0007-fftools-textformat-avtextformat-Fix-races-when-in
> 
> LGTM
> 
> 
> v2-0008-fftools-ffprobe-Factor-writing-common-side-data-t
> 
> LGTM
> 
> 
> v2-0009-fftools-ffprobe-Fix-indentation
> 
> LGTM
> 
> 
> v2-0010-fftools-textformat-avtextformat-Move-avtext_print
> 
> avtext_print_integers() allows to print binary data in 
> a tabular layout and various formats.

I don't see it that way. E.g. it forces you to write the offset at the
start of each line, it forces the layout of the offset upon you. One
could of course add yet more arguments to support more use cases, but
then it would be ever more of a monster.

> 
> It is generally useful and not specific to FFprobe's
> usage. AFAIR, Stefano had seen it the same way.
> 
> 
> v2-0011-fftools-graph-graphprint-Remove-redundant-avio_fl
> 
> LGTM
> 
> 
> In summary
> 
> v2-0002-fftools-textformat-avtextformat-Separate-mutable-
> v2-0010-fftools-textformat-avtextformat-Move-avtext_print
> 
> Should wait for Stefano to comment.
> 
> 
> All others are good to go.
> 

- Andreas

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint
  2025-06-01 22:07       ` Andreas Rheinhardt
@ 2025-06-01 23:14         ` softworkz .
  0 siblings, 0 replies; 7+ messages in thread
From: softworkz . @ 2025-06-01 23:14 UTC (permalink / raw)
  To: FFmpeg development discussions and patches; +Cc: Stefano Sabatini



> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of Andreas
> Rheinhardt
> Sent: Montag, 2. Juni 2025 00:08


> >>> - Why do you want to remove the ResourceManager AVClass?
> >>
> >> Because I think callers should provide their own logcontext
> >
> > Do we have any precedent cases for this? What would be the
> > parameter type for passing it - AVClass* ?
> >
> 
> The type would be void*. AVClass* is wrong (AVClass** would be correct).
> There are lots of functions with a logcontext parameter (see git grep -E
> 'void \*log_?ctx' *.h)

Alright, thanks.

> 
> >
> >
> >>>   It wasn't unused. Now the prefix is gone for log entries in
> >>>   decompress_gzip()
> >>
> >> True, this patch is just wrong (in case of decompression errors,
> >> av_log() will treat ResourceManagerContext as a logging context,
> >> although it is no more; this would lead to segfaults if AVDictionary is
> >> already set, i.e. when initializing the second resource).
> >
> > Yes, I had seen it crashing once as well when moving debugger
> > execution to an av_log line during the second execution.
> > All good now!
> >
> >>>   Actually, all av_log() calls should include the resman_ctx
> >>>   Seems this has been forgotten (well..by me)
> >
> > Thanks for fixing!
> >
> >
> >>> - For the registered_formatters initialization:
> >>>   I used to have initialization order issues when I had tried
> >>>   with static initialization. That's the reason for those functions
> >>>   Probably you've done it differently as it seems to work so far
> >>
> >> What issues?
> >
> > Here's my comment from an earlier review:
> >
> > ----
> >
> >>> +static const AVTextFormatter *registered_formatters[7+1];
> >>
> >> maybe use a const here, also I'd be more happy if we had a more
> >> dynamic registration system to avoid the hardcoded bits
> >
> > While trying this, I remembered that I had tried this before already, but it
> causes trouble with static initialization order. Probably that's the reason
> why it has been like this before already, I'm not sure?
> >
> > ---->
> > What I had seen: The registered_formatters array was initialized before
> > static initialization of all its members had been done.
> > It happened at a rather early stage, so it is well possible that it is
> > resolved by changes that were made meanwhile.
> > FATE tests are passing, so it's probably fine, now.
> 
> FATE is mostly useless here, given that graphprint is not covered by it.

It wasn't about graphprint. At that time, graphprint wasn't
even included. It was about the classic output formats, and
since some of them are used for output in FATE tests, it should
be a valid proof that the issues I had seen are no longer there.
Yet, I have run FATE on Linux only. 
Unfortunately, Patchwork takes always only the first patch when
sent as multiple attachments, so we can't see whether FATE is 
finishing well on all the builders.


> 
> > Here's my full review:
> >
> > v2-0001-fftools-graph-graphprint-Fix-races-when-initializ
> >
> > LGTM, I wasn't aware that av_strtok() is destructive,
> > maybe the doc text should mention it. s param being
> > non-const might give a hint, but it's still a bit
> > unexpected for anybody who doesn't know all the APIs
> > by heart.
> >
> > Now that it's no longer updated, should print_graphs_format
> > be made const? Same for print_graphs_file?
> 
> They are updated generically, via the option system. Making them const
> would lead to compiler warnings from the "{ &print_graphs_format },"
> line in the options definition. 

Why? The chars are const, but not the pointer.

I don't see a warning either (neither MSVC nor GCC)

> Furthermore, the compiler would put
> these variables into .rodata if they were made const, which would lead
> to crashes if the user sets the relevant options.

To be clear, what I meant is changing

extern char *print_graphs_file = NULL;

to

extern const char *print_graphs_file = NULL;




> > v2-0002-fftools-textformat-avtextformat-Separate-mutable-
> >
> > I am aware of the mixed mutability in the section
> > definitions. The general idea of separation and making
> > the section definitions immutable is right of course.
> >
> > Yet, the general goal is to build a versatile API for
> > other use cases, so we should not make changes based
> > on "x is currently used by a only, not by b, so make
> > it local to a".
> >
> > The ability to limit the fields that should be output
> > for each section is an essential feature that should
> > be generally available for all usages, that's why it
> > should rather go in the opposite direction - i.e.
> > from FFprobe (where it's specific atm) to the API.
> > I haven't come to do that yet.
> >
> >
> > We should also hear what Stefano will say about it,
> > as far as I understood he sees it similar, but I
> > might be wrong.
> 
> I'll of course wait for Stefano, but already want to add that nothing is
> more versatile than a callback.

By saying "versatile", I meant that the API is usable for
many cases, but it should also reduce the burden of
re-implementing common features. Specifically, in this 
case it would be more convenient for API consumers
when they wouldn't need to care about command line 
parsing and populating the dictionaries for sections
with the fields that should be printed.
Ideally, the API would allow both ways.


> > v2-0010-fftools-textformat-avtextformat-Move-avtext_print
> >
> > avtext_print_integers() allows to print binary data in
> > a tabular layout and various formats.
> 
> I don't see it that way. E.g. it forces you to write the offset at the
> start of each line, it forces the layout of the offset upon you. One
> could of course add yet more arguments to support more use cases, but
> then it would be ever more of a monster.

I think it would make sense to skim through the usages to
see what's actually required at the moment and based on that,
we can determine the best way to go forward, like a better 
signature and feature set.

PS: I'm CCing Stefano

Thanks
sw





_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-06-01 23:14 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-01  3:27 [FFmpeg-devel] [PATCH 01/11] fftools/graph/graphprint: Fix races when initializing graphprint Andreas Rheinhardt
2025-06-01  4:19 ` softworkz .
2025-06-01 10:39   ` Andreas Rheinhardt
2025-06-01 21:41     ` softworkz .
2025-06-01 22:07       ` Andreas Rheinhardt
2025-06-01 23:14         ` softworkz .
2025-06-01 11:25 ` Andreas Rheinhardt

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git