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

Benoit Fouet git at videolan.org
Fri Oct 17 16:23:46 CEST 2014


ffmpeg | branch: master | Benoit Fouet <benoit.fouet at free.fr> | Fri Oct 17 10:56:59 2014 +0200| [242f8bb3a8a11a54266f43ad45a5a4a260dcbe7f] | committer: Michael Niedermayer

avformat/id3v2: support buggy id3v2.3 tag length in id3v2.4

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

Signed-off-by: Michael Niedermayer <michaelni at gmx.at>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=242f8bb3a8a11a54266f43ad45a5a4a260dcbe7f
---

 libavformat/id3v2.c |   64 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 62 insertions(+), 2 deletions(-)

diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 44df4ff..3e54620 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -170,6 +170,48 @@ static unsigned int get_size(AVIOContext *s, int len)
     return v;
 }
 
+static unsigned int size_to_syncsafe(unsigned int size)
+{
+    return (((size) & (0x7f <<  0)) >> 0) +
+           (((size) & (0x7f <<  8)) >> 1) +
+           (((size) & (0x7f << 16)) >> 2) +
+           (((size) & (0x7f << 24)) >> 3);
+}
+
+/* No real verification, only check that the tag consists of
+ * a combination of capital alpha-numerical characters */
+static int is_tag(const char *buf, unsigned 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;
+}
+
+/**
+ * Return 1 if the tag of length len at the given offset is valid, 0 if not, -1 on error
+ */
+static int check_tag(AVIOContext *s, int offset, unsigned int len)
+{
+    char tag[4];
+
+    if (len > 4 ||
+        avio_seek(s, offset, SEEK_SET) < 0 ||
+        avio_read(s, tag, len) < len)
+        return -1;
+    else if (!AV_RB32(tag) || is_tag(tag, len))
+        return 1;
+
+    return 0;
+}
+
 /**
  * Free GEOB type extra metadata.
  */
@@ -734,8 +776,26 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
             tag[4] = 0;
             if (version == 3) {
                 tlen = avio_rb32(pb);
-            } else
-                tlen = get_size(pb, 4);
+            } else {
+                /* some encoders incorrectly uses v3 sizes instead of syncsafe ones
+                 * so check the next tag to see which one to use */
+                tlen = avio_rb32(pb);
+                if (tlen > 0x7f) {
+                    if (tlen < len) {
+                        int64_t cur = avio_tell(pb);
+
+                        if (ffio_ensure_seekback(pb, 2 /* tflags */ + tlen + 4 /* next tag */))
+                            break;
+
+                        if (check_tag(pb, cur + 2 + size_to_syncsafe(tlen), 4) == 1)
+                            tlen = size_to_syncsafe(tlen);
+                        else if (check_tag(pb, cur + 2 + tlen, 4) != 1)
+                            break;
+                        avio_seek(pb, cur, SEEK_SET);
+                    } else
+                        tlen = size_to_syncsafe(tlen);
+                }
+            }
             tflags  = avio_rb16(pb);
             tunsync = tflags & ID3v2_FLAG_UNSYNCH;
         } else {



More information about the ffmpeg-cvslog mailing list