[FFmpeg-devel] [PATCH] avformat/id3v2: support buggy id3v2.3 tag length in id3v2.4

Benoit Fouet benoit.fouet at free.fr
Thu Oct 16 11:44:47 CEST 2014


Some encoders do not use syncsafe sizes in v2.4 id3 tags. Check the next
tag to try to choose between the two.

Fixes ticket #4003
---
 libavformat/id3v2.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 5469e0a..3bccd76 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -170,6 +170,23 @@ static unsigned int get_size(AVIOContext *s, int len)
     return v;
 }
 
+/* No real verification, only check that the tag consists of
+ * a combination of capital alpha-numerical characters */
+static int is_tag(const char *buf, int len)
+{
+    if (!len)
+        return 0;
+
+    while (len--)
+        if ((buf[len] < 'A' ||
+             buf[len] > 'Z') &&
+            (buf[len] < '0' ||
+             buf[len] > '9'))
+            return 0;
+
+    return 1;
+}
+
 /**
  * Free GEOB type extra metadata.
  */
@@ -734,8 +751,31 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
             tag[4] = 0;
             if (version == 3) {
                 tlen = avio_rb32(pb);
-            } else
+            } else {
                 tlen = get_size(pb, 4);
+                if (tlen > 0x7f) {
+                    /* some encoders incorrectly uses v3 sizes instead of syncsafe ones
+                     * so check the next tag to see which one to use */
+                    int64_t cur = avio_tell(pb);
+                    char next_tag[5];
+
+                    next = cur + 2 /* tflags */ + tlen;
+                    avio_seek(pb, next, SEEK_SET);
+                    if (avio_read(pb, next_tag, 4) < 4)
+                        break;
+                    if (AV_RB32(next_tag) && !is_tag(next_tag, 4)) {
+                        avio_seek(pb, cur - 4, SEEK_SET);
+                        tlen = avio_rb32(pb);
+                        next = cur + 2 + tlen;
+                        avio_seek(pb, next, SEEK_SET);
+                        if (avio_read(pb, next_tag, 4) < 4)
+                            break;
+                        if (AV_RB32(next_tag) && !is_tag(next_tag, 4))
+                            break;
+                    }
+                    avio_seek(pb, cur, SEEK_SET);
+                }
+            }
             tflags  = avio_rb16(pb);
             tunsync = tflags & ID3v2_FLAG_UNSYNCH;
         } else {
-- 
2.1.2.443.g670a3c1



More information about the ffmpeg-devel mailing list