diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 62eee15591..7cedf6e698 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -273,46 +273,67 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic) 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"}, - { "TSOA", "album-sort"}, - { "TSOP", "artist-sort"}, - { "TSOT", "title-sort"}, { "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"}, + { 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 }, }; diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index c2e1add849..e429001385 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -65,12 +65,25 @@ int ff_id3v2_tag_len(const uint8_t *buf); */ 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 */ diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index db180d66e8..f55e12319c 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -148,6 +148,20 @@ AVOutputFormat mp2_muxer = { #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 */ @@ -166,29 +180,25 @@ static int mp3_write_header(struct AVFormatContext *s) 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 ((ret = id3v2_check_write_tag(s, t, ff_id3v2_4_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; - totlen += ret; - } + /* 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);