id3v2: read all textual chapter subframes
authorPaul B Mahol <onemda@gmail.com>
Thu, 9 May 2013 13:09:28 +0000 (13:09 +0000)
committerPaul B Mahol <onemda@gmail.com>
Fri, 7 Jun 2013 09:28:07 +0000 (09:28 +0000)
Signed-off-by: Paul B Mahol <onemda@gmail.com>
libavformat/id3v2.c

index e585f0e..74d6375 100644 (file)
@@ -271,7 +271,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
  * Parse a text tag.
  */
 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
-                      const char *key)
+                      AVDictionary **metadata, const char *key)
 {
     uint8_t *dst;
     int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
@@ -306,7 +306,7 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
         av_freep(&dst);
 
     if (dst)
-        av_dict_set(&s->metadata, key, dst, dict_flags);
+        av_dict_set(metadata, key, dst, dict_flags);
 }
 
 /**
@@ -518,39 +518,49 @@ fail:
     avio_seek(pb, end, SEEK_SET);
 }
 
-static void read_chapter(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
+static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *ttag, ID3v2ExtraMeta **extra_meta)
 {
     AVRational time_base = {1, 1000};
     uint32_t start, end;
+    AVChapter *chapter;
     uint8_t *dst = NULL;
-    int encoding;
+    int taglen;
+    char tag[5];
 
-    decode_str(s, pb, 0, &dst, &taglen);
-    if (taglen < 16)
+    decode_str(s, pb, 0, &dst, &len);
+    if (len < 16)
         return;
 
     start = avio_rb32(pb);
     end   = avio_rb32(pb);
-    taglen -= 27;
-    if (taglen > 0) {
-        char tag[4];
+    avio_skip(pb, 8);
+
+    chapter = avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, dst);
+    if (!chapter) {
+        av_free(dst);
+        return;
+    }
 
-        avio_skip(pb, 8);
+    len -= 16;
+    while (len > 10) {
         avio_read(pb, tag, 4);
-        if (!memcmp(tag, "TIT2", 4)) {
-            taglen = FFMIN(taglen, avio_rb32(pb));
-            if (taglen < 0) {
-                av_free(dst);
-                return;
-            }
-            avio_skip(pb, 2);
-            encoding = avio_r8(pb);
-            av_freep(&dst);
-            decode_str(s, pb, encoding, &dst, &taglen);
+        tag[4] = 0;
+        taglen = avio_rb32(pb);
+        avio_skip(pb, 2);
+        len -= 10;
+        if (taglen < 0 || taglen > len) {
+            av_free(dst);
+            return;
         }
+        if (tag[0] == 'T')
+            read_ttag(s, pb, taglen, &chapter->metadata, tag);
+        else
+            avio_skip(pb, taglen);
+        len -= taglen;
     }
 
-    avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, dst);
+    ff_metadata_conv(&chapter->metadata, NULL, ff_id3v2_34_metadata_conv);
+    ff_metadata_conv(&chapter->metadata, NULL, ff_id3v2_4_metadata_conv);
     av_free(dst);
 }
 
@@ -774,7 +784,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
 #endif
             if (tag[0] == 'T')
                 /* parse text tag */
-                read_ttag(s, pbx, tlen, tag);
+                read_ttag(s, pbx, tlen, &s->metadata, tag);
             else
                 /* parse special meta tag */
                 extra_func->read(s, pbx, tlen, tag, extra_meta);