url_fseek(s->pb, off, SEEK_SET);
}
} while (found_header);
- ff_metadata_conv(&s->metadata, NULL, ff_id3v2_metadata_conv);
+ ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
+ ff_metadata_conv(&s->metadata, NULL, ff_id3v2_2_metadata_conv);
+ ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
}
-const AVMetadataConv ff_id3v2_metadata_conv[] = {
+const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
{ "TALB", "album"},
- { "TAL", "album"},
{ "TCOM", "composer"},
{ "TCON", "genre"},
- { "TCO", "genre"},
{ "TCOP", "copyright"},
- { "TDRL", "date"},
- { "TDRC", "date"},
- { "TDEN", "creation_time"},
{ "TENC", "encoded_by"},
- { "TEN", "encoded_by"},
{ "TIT2", "title"},
- { "TT2", "title"},
{ "TLAN", "language"},
{ "TPE1", "artist"},
- { "TP1", "artist"},
{ "TPE2", "album_artist"},
- { "TP2", "album_artist"},
{ "TPE3", "performer"},
- { "TP3", "performer"},
{ "TPOS", "disc"},
{ "TPUB", "publisher"},
{ "TRCK", "track"},
- { "TRK", "track"},
+ { "TSSE", "encoder"},
+ { 0 }
+};
+
+const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
+ { "TDRL", "date"},
+ { "TDRC", "date"},
+ { "TDEN", "creation_time"},
{ "TSOA", "album-sort"},
{ "TSOP", "artist-sort"},
{ "TSOT", "title-sort"},
- { "TSSE", "encoder"},
{ 0 }
};
+const AVMetadataConv ff_id3v2_2_metadata_conv[] = {
+ { "TAL", "album"},
+ { "TCO", "genre"},
+ { "TT2", "title"},
+ { "TEN", "encoded_by"},
+ { "TP1", "artist"},
+ { "TP2", "album_artist"},
+ { "TP3", "performer"},
+ { "TRK", "track"},
+ { 0 }
+};
+
+
const char ff_id3v2_tags[][4] = {
- "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDEN", "TDLY", "TDOR", "TDRC",
- "TDRL", "TDTG", "TENC", "TEXT", "TFLT", "TIPL", "TIT1", "TIT2", "TIT3",
- "TKEY", "TLAN", "TLEN", "TMCL", "TMED", "TMOO", "TOAL", "TOFN", "TOLY",
- "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPRO", "TPUB",
- "TRCK", "TRSN", "TRSO", "TSOA", "TSOP", "TSOT", "TSRC", "TSSE", "TSST",
+ "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
+ "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
+ "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
+ "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
+ { 0 },
+};
+
+const char ff_id3v2_4_tags[][4] = {
+ "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
+ "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
+ { 0 },
+};
+
+const char ff_id3v2_3_tags[][4] = {
+ "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
{ 0 },
};
*/
void ff_id3v2_read(AVFormatContext *s, const char *magic);
-extern const AVMetadataConv ff_id3v2_metadata_conv[];
+extern const AVMetadataConv ff_id3v2_34_metadata_conv[];
+extern const AVMetadataConv ff_id3v2_4_metadata_conv[];
+extern const AVMetadataConv ff_id3v2_2_metadata_conv[];
/**
- * A list of ID3v2.4 text information frames.
+ * A list of text information frames allowed in both ID3 v2.3 and v2.4
* http://www.id3.org/id3v2.4.0-frames
+ * http://www.id3.org/id3v2.4.0-changes
*/
extern const char ff_id3v2_tags[][4];
+/**
+ * ID3v2.4-only text information frames.
+ */
+extern const char ff_id3v2_4_tags[][4];
+
+/**
+ * ID3v2.3-only text information frames.
+ */
+extern const char ff_id3v2_3_tags[][4];
+
#endif /* AVFORMAT_ID3V2_H */
#endif
#if CONFIG_MP3_MUXER
+static int id3v2_check_write_tag(AVFormatContext *s, AVMetadataTag *t, const char table[][4])
+{
+ uint32_t tag;
+ int i;
+
+ if (t->key[0] != 'T' || strlen(t->key) != 4)
+ return -1;
+ tag = AV_RB32(t->key);
+ for (i = 0; *table[i]; i++)
+ if (tag == AV_RB32(table[i]))
+ return id3v2_put_ttag(s, t->value, NULL, tag, ID3v2_ENCODING_UTF8);
+ return -1;
+}
+
/**
* Write an ID3v2.4 header at beginning of stream
*/
size_pos = url_ftell(s->pb);
put_be32(s->pb, 0);
- ff_metadata_conv(&s->metadata, ff_id3v2_metadata_conv, NULL);
+ ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL);
+ ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL);
while ((t = av_metadata_get(s->metadata, "", t, AV_METADATA_IGNORE_SUFFIX))) {
- uint32_t tag = 0;
int ret;
- if (t->key[0] == 'T' && strlen(t->key) == 4) {
- int i;
- for (i = 0; *ff_id3v2_tags[i]; i++)
- if (AV_RB32(t->key) == AV_RB32(ff_id3v2_tags[i])) {
- tag = AV_RB32(t->key);
- if ((ret = id3v2_put_ttag(s, t->value, NULL, tag, ID3v2_ENCODING_UTF8)) < 0)
- return ret;
- totlen += ret;
- break;
- }
+ if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_tags)) > 0) {
+ totlen += ret;
+ continue;
}
-
- if (!tag) { /* unknown tag, write as TXXX frame */
- tag = MKBETAG('T', 'X', 'X', 'X');
- if ((ret = id3v2_put_ttag(s, t->key, t->value, tag, ID3v2_ENCODING_UTF8)) < 0)
- return ret;
+ if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_4_tags)) > 0) {
totlen += ret;
+ continue;
}
+
+ /* unknown tag, write as TXXX frame */
+ if ((ret = id3v2_put_ttag(s, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'),
+ ID3v2_ENCODING_UTF8)) < 0)
+ return ret;
+ totlen += ret;
}
cur_pos = url_ftell(s->pb);