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] ffplay: print new metadata (PR #20867)
@ 2025-11-08 18:05 toots via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: toots via ffmpeg-devel @ 2025-11-08 18:05 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: toots

PR #20867 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20867
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20867.patch


>From f3a114f7dea9f31888dc9deb39bbe5ee5e808c0c Mon Sep 17 00:00:00 2001
From: Romain Beauxis <romain.beauxis@gmail.com>
Date: Sat, 8 Nov 2025 10:19:30 -0600
Subject: [PATCH 1/3] libavformat: export av_dump_dictionary

---
 doc/APIchanges         |  3 +++
 libavformat/avformat.h | 14 ++++++++++++++
 libavformat/dump.c     | 12 ++++++------
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 9d128ae77b..42bc3dba35 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-11-08 - xxxxxxxxxx - lavf 62.6.101 - avformat.h
+  Added av_dump_dictionary().
+
 2025-11-01 - xxxxxxxxxx - lavc 62.19.100 - avcodec.h
   Schedule AVCodecParser and av_parser_init() to use enum AVCodecID
   for codec ids on the next major version bump.
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index a7446546e5..a6cf9b0dfa 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2818,6 +2818,20 @@ void av_dump_format(AVFormatContext *ic,
                     const char *url,
                     int is_output);
 
+/**
+ * Print the given dictionary.
+ *
+ * @param ctx       the logging context
+ * @param m         the dictionay to print
+ * @param name      name of the dictionary
+ * @param indent    intendation to use between key and values
+ * @param log_level log level to use for printing
+ */
+void av_dump_dictionary(void *ctx,
+                        const AVDictionary *m,
+                        const char *name,
+                        const char *indent,
+                        int log_level);
 
 #define AV_FRAME_FILENAME_FLAGS_MULTIPLE          1  ///< Allow multiple %d
 #define AV_FRAME_FILENAME_FLAGS_IGNORE_TRUNCATION 2  ///< Ignore truncated output instead of returning an error
diff --git a/libavformat/dump.c b/libavformat/dump.c
index 2948189432..d30732fbef 100644
--- a/libavformat/dump.c
+++ b/libavformat/dump.c
@@ -139,9 +139,9 @@ static void print_fps(double d, const char *postfix, int log_level)
         av_log(NULL, log_level, "%1.0fk %s", d / 1000, postfix);
 }
 
-static void dump_dictionary(void *ctx, const AVDictionary *m,
-                            const char *name, const char *indent,
-                            int log_level)
+void av_dump_dictionary(void *ctx, const AVDictionary *m,
+                        const char *name, const char *indent,
+                        int log_level)
 {
     const AVDictionaryEntry *tag = NULL;
 
@@ -170,7 +170,7 @@ static void dump_metadata(void *ctx, const AVDictionary *m, const char *indent,
                           int log_level)
 {
     if (m && !(av_dict_count(m) == 1 && av_dict_get(m, "language", NULL, 0)))
-        dump_dictionary(ctx, m, "Metadata", indent, log_level);
+        av_dump_dictionary(ctx, m, "Metadata", indent, log_level);
 }
 
 /* param change side data*/
@@ -734,7 +734,7 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
         dump_disposition(stg->disposition, AV_LOG_INFO);
         av_log(NULL, AV_LOG_INFO, "\n");
         dump_metadata(NULL, stg->metadata, "    ", AV_LOG_INFO);
-        dump_dictionary(NULL, mix_presentation->annotations, "Annotations", "    ", AV_LOG_INFO);
+        av_dump_dictionary(NULL, mix_presentation->annotations, "Annotations", "    ", AV_LOG_INFO);
         for (int j = 0; j < mix_presentation->nb_submixes; j++) {
             AVIAMFSubmix *sub_mix = mix_presentation->submixes[j];
             av_log(NULL, AV_LOG_INFO, "    Submix %d:\n", j);
@@ -753,7 +753,7 @@ static void dump_stream_group(const AVFormatContext *ic, uint8_t *printed,
                     if (flags & AVFMT_SHOW_IDS)
                         av_log(NULL, AV_LOG_INFO, "[0x%"PRIx64"]", audio_element->id);
                     av_log(NULL, AV_LOG_INFO, "\n");
-                    dump_dictionary(NULL, submix_element->annotations, "Annotations", "        ", AV_LOG_INFO);
+                    av_dump_dictionary(NULL, submix_element->annotations, "Annotations", "        ", AV_LOG_INFO);
                 }
             }
             for (int k = 0; k < sub_mix->nb_layouts; k++) {
-- 
2.49.1


>From 020070a61204ab3b227f1f977abbb466b3316859 Mon Sep 17 00:00:00 2001
From: Romain Beauxis <romain.beauxis@gmail.com>
Date: Sat, 8 Nov 2025 12:03:32 -0600
Subject: [PATCH 2/3] libavutil: add av_dict_md5_sum.

---
 doc/APIchanges   |  3 +++
 libavutil/dict.c | 22 ++++++++++++++++++++++
 libavutil/dict.h | 12 ++++++++++++
 3 files changed, 37 insertions(+)

diff --git a/doc/APIchanges b/doc/APIchanges
index 42bc3dba35..7c9c864577 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-11-08 -  xxxxxxxxxx - lavu 60.17.100 - dict.h
+  Added av_dict_md5_sum().
+
 2025-11-08 - xxxxxxxxxx - lavf 62.6.101 - avformat.h
   Added av_dump_dictionary().
 
diff --git a/libavutil/dict.c b/libavutil/dict.c
index fafb454fd3..9404718429 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -26,6 +26,7 @@
 #include "avstring.h"
 #include "dict.h"
 #include "error.h"
+#include "md5.h"
 #include "mem.h"
 #include "bprint.h"
 
@@ -284,3 +285,24 @@ int av_dict_get_string(const AVDictionary *m, char **buffer,
     }
     return av_bprint_finalize(&bprint, buffer);
 }
+
+int av_dict_md5_sum(uint8_t *dst, const AVDictionary *m)
+{
+    struct AVMD5 *ctx = av_md5_alloc();
+    const AVDictionaryEntry *entry = av_dict_iterate(m, NULL);
+
+    if (!ctx) return AVERROR(ENOMEM);
+
+    av_md5_init(ctx);
+
+    while (entry) {
+        av_md5_update(ctx, entry->key, strlen(entry->key));
+        av_md5_update(ctx, entry->value, strlen(entry->value));
+        entry = av_dict_iterate(m, entry);
+    }
+
+    av_md5_final(ctx, dst);
+    av_free(ctx);
+
+    return 0;
+}
diff --git a/libavutil/dict.h b/libavutil/dict.h
index 93c7cbf128..2685974e8e 100644
--- a/libavutil/dict.h
+++ b/libavutil/dict.h
@@ -31,6 +31,7 @@
 #define AVUTIL_DICT_H
 
 #include <stdint.h>
+#include <stddef.h>
 
 /**
  * @addtogroup lavu_dict AVDictionary
@@ -235,6 +236,17 @@ void av_dict_free(AVDictionary **m);
 int av_dict_get_string(const AVDictionary *m, char **buffer,
                        const char key_val_sep, const char pairs_sep);
 
+/**
+ * Compute the md5 sum of a dictionary.
+ *
+ * @param dst The output buffer to write the digest into
+ * @param m   The dictionary
+ * @param len The length of the data, in bytes
+ *
+ * @return                   >= 0 on success, negative on error
+ */
+int av_dict_md5_sum(uint8_t *dst, const AVDictionary *m);
+
 /**
  * @}
  */
-- 
2.49.1


>From 05b34a1e3911c1430ade6360641b5e8dea99a6f4 Mon Sep 17 00:00:00 2001
From: Romain Beauxis <romain.beauxis@gmail.com>
Date: Sat, 8 Nov 2025 10:32:32 -0600
Subject: [PATCH 3/3] ffplay: print new metadata

---
 fftools/ffplay.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/fftools/ffplay.c b/fftools/ffplay.c
index dc2627521e..6d7b7a57af 100644
--- a/fftools/ffplay.c
+++ b/fftools/ffplay.c
@@ -196,6 +196,7 @@ typedef struct Decoder {
     int64_t next_pts;
     AVRational next_pts_tb;
     SDL_Thread *decoder_tid;
+    uint8_t last_metadata_hash[16];
 } Decoder;
 
 typedef struct VideoState {
@@ -577,6 +578,8 @@ static int decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, S
 
 static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
     int ret = AVERROR(EAGAIN);
+    uint8_t metadata_hash[16];
+    char metadata_description[96];
 
     for (;;) {
         if (d->queue->serial == d->pkt_serial) {
@@ -615,8 +618,26 @@ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
                     avcodec_flush_buffers(d->avctx);
                     return 0;
                 }
-                if (ret >= 0)
+                if (ret >= 0) {
+                    if (frame->metadata) {
+                        ret = av_dict_md5_sum(metadata_hash, frame->metadata);
+                        if (ret < 0) return ret;
+                        if (memcmp(metadata_hash, d->last_metadata_hash, sizeof(metadata_hash))) {
+                            memcpy(d->last_metadata_hash, metadata_hash, sizeof(metadata_hash));
+                            if (show_status) {
+                                printf("\x1b[2K\r");
+                                fflush(stdout);
+                            }
+                            snprintf(metadata_description,
+                                     sizeof(metadata_description),
+                                     "\r  New metadata for %s stream %d",
+                                     d->avctx->codec_type == AVMEDIA_TYPE_AUDIO ? "audio" : "video",
+                                     d->pkt ? d->pkt->stream_index : -1);
+                            av_dump_dictionary(NULL, frame->metadata, metadata_description, "    ", AV_LOG_INFO);
+                        }
+                    }
                     return 1;
+                }
             } while (ret != AVERROR(EAGAIN));
         }
 
@@ -2762,6 +2783,11 @@ static int stream_component_open(VideoState *is, int stream_index)
         is->audio_stream = stream_index;
         is->audio_st = ic->streams[stream_index];
 
+        if (is->audio_st->metadata) {
+            ret = av_dict_md5_sum(is->auddec.last_metadata_hash, is->audio_st->metadata);
+            if (ret < 0) goto fail;
+        }
+
         if ((ret = decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread)) < 0)
             goto fail;
         if (is->ic->iformat->flags & AVFMT_NOTIMESTAMPS) {
@@ -2776,6 +2802,11 @@ static int stream_component_open(VideoState *is, int stream_index)
         is->video_stream = stream_index;
         is->video_st = ic->streams[stream_index];
 
+        if (is->video_st->metadata) {
+            ret = av_dict_md5_sum(is->viddec.last_metadata_hash, is->video_st->metadata);
+            if (ret < 0) goto fail;
+        }
+
         if ((ret = decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread)) < 0)
             goto fail;
         if ((ret = decoder_start(&is->viddec, video_thread, "video_decoder", is)) < 0)
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-11-08 18:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-11-08 18:05 [FFmpeg-devel] [PATCH] ffplay: print new metadata (PR #20867) toots via ffmpeg-devel

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