| /* | |
| * ID3v1 header parser | |
| * Copyright (c) 2003 Fabrice Bellard | |
| * | |
| * This file is part of FFmpeg. | |
| * | |
| * FFmpeg is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * FFmpeg is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with FFmpeg; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| */ | |
| #include "id3v1.h" | |
| #include "libavutil/dict.h" | |
| /* See Genre List at http://id3.org/id3v2.3.0 */ | |
| const char * const ff_id3v1_genre_str[ID3v1_GENRE_MAX + 1] = { | |
| [0] = "Blues", | |
| [1] = "Classic Rock", | |
| [2] = "Country", | |
| [3] = "Dance", | |
| [4] = "Disco", | |
| [5] = "Funk", | |
| [6] = "Grunge", | |
| [7] = "Hip-Hop", | |
| [8] = "Jazz", | |
| [9] = "Metal", | |
| [10] = "New Age", | |
| [11] = "Oldies", | |
| [12] = "Other", | |
| [13] = "Pop", | |
| [14] = "R&B", | |
| [15] = "Rap", | |
| [16] = "Reggae", | |
| [17] = "Rock", | |
| [18] = "Techno", | |
| [19] = "Industrial", | |
| [20] = "Alternative", | |
| [21] = "Ska", | |
| [22] = "Death Metal", | |
| [23] = "Pranks", | |
| [24] = "Soundtrack", | |
| [25] = "Euro-Techno", | |
| [26] = "Ambient", | |
| [27] = "Trip-Hop", | |
| [28] = "Vocal", | |
| [29] = "Jazz+Funk", | |
| [30] = "Fusion", | |
| [31] = "Trance", | |
| [32] = "Classical", | |
| [33] = "Instrumental", | |
| [34] = "Acid", | |
| [35] = "House", | |
| [36] = "Game", | |
| [37] = "Sound Clip", | |
| [38] = "Gospel", | |
| [39] = "Noise", | |
| [40] = "AlternRock", | |
| [41] = "Bass", | |
| [42] = "Soul", | |
| [43] = "Punk", | |
| [44] = "Space", | |
| [45] = "Meditative", | |
| [46] = "Instrumental Pop", | |
| [47] = "Instrumental Rock", | |
| [48] = "Ethnic", | |
| [49] = "Gothic", | |
| [50] = "Darkwave", | |
| [51] = "Techno-Industrial", | |
| [52] = "Electronic", | |
| [53] = "Pop-Folk", | |
| [54] = "Eurodance", | |
| [55] = "Dream", | |
| [56] = "Southern Rock", | |
| [57] = "Comedy", | |
| [58] = "Cult", | |
| [59] = "Gangsta", | |
| [60] = "Top 40", | |
| [61] = "Christian Rap", | |
| [62] = "Pop/Funk", | |
| [63] = "Jungle", | |
| [64] = "Native American", | |
| [65] = "Cabaret", | |
| [66] = "New Wave", | |
| [67] = "Psychedelic", | |
| [68] = "Rave", | |
| [69] = "Showtunes", | |
| [70] = "Trailer", | |
| [71] = "Lo-Fi", | |
| [72] = "Tribal", | |
| [73] = "Acid Punk", | |
| [74] = "Acid Jazz", | |
| [75] = "Polka", | |
| [76] = "Retro", | |
| [77] = "Musical", | |
| [78] = "Rock & Roll", | |
| [79] = "Hard Rock", | |
| [80] = "Folk", | |
| [81] = "Folk-Rock", | |
| [82] = "National Folk", | |
| [83] = "Swing", | |
| [84] = "Fast Fusion", | |
| [85] = "Bebop", | |
| [86] = "Latin", | |
| [87] = "Revival", | |
| [88] = "Celtic", | |
| [89] = "Bluegrass", | |
| [90] = "Avantgarde", | |
| [91] = "Gothic Rock", | |
| [92] = "Progressive Rock", | |
| [93] = "Psychedelic Rock", | |
| [94] = "Symphonic Rock", | |
| [95] = "Slow Rock", | |
| [96] = "Big Band", | |
| [97] = "Chorus", | |
| [98] = "Easy Listening", | |
| [99] = "Acoustic", | |
| [100] = "Humour", | |
| [101] = "Speech", | |
| [102] = "Chanson", | |
| [103] = "Opera", | |
| [104] = "Chamber Music", | |
| [105] = "Sonata", | |
| [106] = "Symphony", | |
| [107] = "Booty Bass", | |
| [108] = "Primus", | |
| [109] = "Porn Groove", | |
| [110] = "Satire", | |
| [111] = "Slow Jam", | |
| [112] = "Club", | |
| [113] = "Tango", | |
| [114] = "Samba", | |
| [115] = "Folklore", | |
| [116] = "Ballad", | |
| [117] = "Power Ballad", | |
| [118] = "Rhythmic Soul", | |
| [119] = "Freestyle", | |
| [120] = "Duet", | |
| [121] = "Punk Rock", | |
| [122] = "Drum Solo", | |
| [123] = "A Cappella", | |
| [124] = "Euro-House", | |
| [125] = "Dance Hall", | |
| [126] = "Goa", | |
| [127] = "Drum & Bass", | |
| [128] = "Club-House", | |
| [129] = "Hardcore Techno", | |
| [130] = "Terror", | |
| [131] = "Indie", | |
| [132] = "BritPop", | |
| [133] = "Negerpunk", | |
| [134] = "Polsk Punk", | |
| [135] = "Beat", | |
| [136] = "Christian Gangsta Rap", | |
| [137] = "Heavy Metal", | |
| [138] = "Black Metal", | |
| [139] = "Crossover", | |
| [140] = "Contemporary Christian", | |
| [141] = "Christian Rock", | |
| [142] = "Merengue", | |
| [143] = "Salsa", | |
| [144] = "Thrash Metal", | |
| [145] = "Anime", | |
| [146] = "Jpop", | |
| [147] = "Synthpop", | |
| [148] = "Abstract", | |
| [149] = "Art Rock", | |
| [150] = "Baroque", | |
| [151] = "Bhangra", | |
| [152] = "Big Beat", | |
| [153] = "Breakbeat", | |
| [154] = "Chillout", | |
| [155] = "Downtempo", | |
| [156] = "Dub", | |
| [157] = "EBM", | |
| [158] = "Eclectic", | |
| [159] = "Electro", | |
| [160] = "Electroclash", | |
| [161] = "Emo", | |
| [162] = "Experimental", | |
| [163] = "Garage", | |
| [164] = "Global", | |
| [165] = "IDM", | |
| [166] = "Illbient", | |
| [167] = "Industro-Goth", | |
| [168] = "Jam Band", | |
| [169] = "Krautrock", | |
| [170] = "Leftfield", | |
| [171] = "Lounge", | |
| [172] = "Math Rock", | |
| [173] = "New Romantic", | |
| [174] = "Nu-Breakz", | |
| [175] = "Post-Punk", | |
| [176] = "Post-Rock", | |
| [177] = "Psytrance", | |
| [178] = "Shoegaze", | |
| [179] = "Space Rock", | |
| [180] = "Trop Rock", | |
| [181] = "World Music", | |
| [182] = "Neoclassical", | |
| [183] = "Audiobook", | |
| [184] = "Audio Theatre", | |
| [185] = "Neue Deutsche Welle", | |
| [186] = "Podcast", | |
| [187] = "Indie Rock", | |
| [188] = "G-Funk", | |
| [189] = "Dubstep", | |
| [190] = "Garage Rock", | |
| [191] = "Psybient" | |
| }; | |
| static void get_string(AVFormatContext *s, const char *key, | |
| const uint8_t *buf, int buf_size) | |
| { | |
| int i, c; | |
| char *q, str[512], *first_free_space = NULL; | |
| q = str; | |
| for(i = 0; i < buf_size; i++) { | |
| c = buf[i]; | |
| if (c == '\0') | |
| break; | |
| if ((q - str) >= sizeof(str) - 1) | |
| break; | |
| if (c == ' ') { | |
| if (!first_free_space) | |
| first_free_space = q; | |
| } else { | |
| first_free_space = NULL; | |
| } | |
| *q++ = c; | |
| } | |
| *q = '\0'; | |
| if (first_free_space) | |
| *first_free_space = '\0'; | |
| if (*str) | |
| av_dict_set(&s->metadata, key, str, 0); | |
| } | |
| /** | |
| * Parse an ID3v1 tag | |
| * | |
| * @param buf ID3v1_TAG_SIZE long buffer containing the tag | |
| */ | |
| static int parse_tag(AVFormatContext *s, const uint8_t *buf) | |
| { | |
| int genre; | |
| if (!(buf[0] == 'T' && | |
| buf[1] == 'A' && | |
| buf[2] == 'G')) | |
| return -1; | |
| get_string(s, "title", buf + 3, 30); | |
| get_string(s, "artist", buf + 33, 30); | |
| get_string(s, "album", buf + 63, 30); | |
| get_string(s, "date", buf + 93, 4); | |
| get_string(s, "comment", buf + 97, 30); | |
| if (buf[125] == 0 && buf[126] != 0) { | |
| av_dict_set_int(&s->metadata, "track", buf[126], 0); | |
| } | |
| genre = buf[127]; | |
| if (genre <= ID3v1_GENRE_MAX) | |
| av_dict_set(&s->metadata, "genre", ff_id3v1_genre_str[genre], 0); | |
| return 0; | |
| } | |
| void ff_id3v1_read(AVFormatContext *s) | |
| { | |
| int ret; | |
| uint8_t buf[ID3v1_TAG_SIZE]; | |
| int64_t filesize, position = avio_tell(s->pb); | |
| if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { | |
| /* XXX: change that */ | |
| filesize = avio_size(s->pb); | |
| if (filesize > 128) { | |
| avio_seek(s->pb, filesize - 128, SEEK_SET); | |
| ret = avio_read(s->pb, buf, ID3v1_TAG_SIZE); | |
| if (ret == ID3v1_TAG_SIZE) { | |
| parse_tag(s, buf); | |
| } | |
| avio_seek(s->pb, position, SEEK_SET); | |
| } | |
| } | |
| } |