avformat/id3v2: support USLT tags
authorwm4 <nfxjfg@googlemail.com>
Mon, 5 Jan 2015 17:56:20 +0000 (18:56 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Tue, 6 Jan 2015 15:39:52 +0000 (16:39 +0100)
I think this turned out pretty terrible. There's no good way to add new
custom tags that write to AVFormatContext->metadata.

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libavformat/id3v2.c

index 847d4af..02955ff 100644 (file)
@@ -55,6 +55,7 @@ const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
     { "TPUB", "publisher"    },
     { "TRCK", "track"        },
     { "TSSE", "encoder"      },
+    { "USLT", "lyrics"       },
     { 0 }
 };
 
@@ -353,6 +354,52 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
         av_dict_set(metadata, key, dst, dict_flags);
 }
 
+static void read_uslt(AVFormatContext *s, AVIOContext *pb, int taglen,
+                      AVDictionary **metadata)
+{
+    uint8_t lang[4];
+    uint8_t *descriptor = NULL; // 'Content descriptor'
+    uint8_t *text = NULL;
+    char *key = NULL;
+    int encoding;
+    unsigned genre;
+    int ok = 0;
+
+    if (taglen < 1)
+        goto error;
+
+    encoding = avio_r8(pb);
+    taglen--;
+
+    if (avio_read(pb, lang, 3) < 3)
+        goto error;
+    lang[3] = '\0';
+    taglen -= 3;
+
+    if (decode_str(s, pb, encoding, &descriptor, &taglen) < 0)
+        goto error;
+
+    if (decode_str(s, pb, encoding, &text, &taglen) < 0)
+        goto error;
+
+    // FFmpeg does not support hierarchical metadata, so concatenate the keys.
+    key = av_asprintf("lyrics-%s%s%s", descriptor[0] ? (char *)descriptor : "",
+                                       descriptor[0] ? "-" : "",
+                                       lang);
+    if (!key)
+        goto error;
+
+    av_dict_set(metadata, key, text, 0);
+
+    ok = 1;
+error:
+    if (!ok)
+        av_log(s, AV_LOG_ERROR, "Error reading lyrics, skipped\n");
+    av_free(descriptor);
+    av_free(text);
+    av_free(key);
+}
+
 /**
  * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
  */
@@ -845,6 +892,7 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
             avio_skip(pb, tlen);
         /* check for text tag or supported special meta tag */
         } else if (tag[0] == 'T' ||
+                   !memcmp(tag, "USLT", 4) ||
                    (extra_meta &&
                     (extra_func = get_extra_meta_func(tag, isv34)))) {
             pbx = pb;
@@ -910,6 +958,8 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
             if (tag[0] == 'T')
                 /* parse text tag */
                 read_ttag(s, pbx, tlen, metadata, tag);
+            else if (!memcmp(tag, "USLT", 4))
+                read_uslt(s, pbx, tlen, metadata);
             else
                 /* parse special meta tag */
                 extra_func->read(s, pbx, tlen, tag, extra_meta, isv34);