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