PR #22781 opened by Jun Zhao (mypopydev)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22781
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22781.patch

When a metadata tag (e.g. ©ART) contains multiple values, either as
multiple 'data' child atoms within one tag or as multiple sibling tag
atoms with the same key, only the first value was read.

Fix by joining multiple values with semicolons using AV_DICT_APPEND,
consistent with Ogg Vorbis Comment handling in oggparsevorbis.c, and
reusing the existing 'goto retry' loop that covr already uses.
Also add the missing atom.size -= str_size to correctly track remaining
bytes in the tag atom, matching the covr path.

Limitation: on remux the joined string is written back as a single
value, same lossy behavior as Ogg Vorbis. Lossless round-trip would
require AV_DICT_MULTIKEY support throughout the metadata pipeline.

Fix #22367
Signed-off-by: Jun Zhao <[email protected]>


From 16600097897ec2bce0208ae3c03612239367788b Mon Sep 17 00:00:00 2001
From: Jun Zhao <[email protected]>
Date: Fri, 10 Apr 2026 23:05:05 +0800
Subject: [PATCH] lavf/mov: read multi-valued metadata tags
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When a metadata tag (e.g. ©ART) contains multiple values, either as
multiple 'data' child atoms within one tag or as multiple sibling tag
atoms with the same key, only the first value was read.

Fix by joining multiple values with semicolons using AV_DICT_APPEND,
consistent with Ogg Vorbis Comment handling in oggparsevorbis.c, and
reusing the existing 'goto retry' loop that covr already uses.
Also add the missing atom.size -= str_size to correctly track remaining
bytes in the tag atom, matching the covr path.

Limitation: on remux the joined string is written back as a single
value, same lossy behavior as Ogg Vorbis. Lossless round-trip would
require AV_DICT_MULTIKEY support throughout the metadata pipeline.

Fix #22367
Signed-off-by: Jun Zhao <[email protected]>
---
 libavformat/mov.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/libavformat/mov.c b/libavformat/mov.c
index dc9233b8a8..eb7487e2c2 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -579,10 +579,14 @@ retry:
             str[str_size] = 0;
         }
         c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
-        av_dict_set(metadata, key, str, 0);
+        if (av_dict_get(*metadata, key, NULL, 0))
+            av_dict_set(metadata, key, ";", AV_DICT_APPEND);
+        av_dict_set(metadata, key, str, AV_DICT_APPEND);
         if (*language && strcmp(language, "und")) {
             snprintf(key2, sizeof(key2), "%s-%s", key, language);
-            av_dict_set(metadata, key2, str, 0);
+            if (av_dict_get(*metadata, key2, NULL, 0))
+                av_dict_set(metadata, key2, ";", AV_DICT_APPEND);
+            av_dict_set(metadata, key2, str, AV_DICT_APPEND);
         }
         if (!strcmp(key, "encoder")) {
             int major, minor, micro;
@@ -590,6 +594,18 @@ retry:
                 c->handbrake_version = 1000000*major + 1000*minor + micro;
             }
         }
+
+        atom.size -= str_size;
+        av_freep(&str);
+
+        // Read remaining data atoms for multi-valued iTunes tags (e.g. 
multiple
+        // artists stored as multiple data atoms within one tag atom), 
consistent
+        // with how covr already handles multiple data atoms (line 483).
+        // Note: multiple sibling tag atoms with the same key (e.g. three 
separate
+        // ©ART atoms under ilst) are handled by the AV_DICT_APPEND logic 
above,
+        // since mov_read_udta_string() is called once per tag atom.
+        if (c->itunes_metadata && atom.size > 8)
+            goto retry;
     }
 
     av_freep(&str);
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to