id3v1.c
Go to the documentation of this file.
1 /*
2  * ID3v1 header parser
3  * Copyright (c) 2003 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; 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 "libavcodec/avcodec.h"
24 #include "libavutil/dict.h"
25 
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] = "Psychadelic",
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] = "Bebob",
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 capella",
151  [124] = "Euro-House",
152  [125] = "Dance Hall",
153  [126] = "Goa",
154  [127] = "Drum & Bass",
155  [128] = "Club-House",
156  [129] = "Hardcore",
157  [130] = "Terror",
158  [131] = "Indie",
159  [132] = "BritPop",
160  [133] = "Negerpunk",
161  [134] = "Polsk Punk",
162  [135] = "Beat",
163  [136] = "Christian Gangsta",
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 };
176 
177 static void get_string(AVFormatContext *s, const char *key,
178  const uint8_t *buf, int buf_size)
179 {
180  int i, c;
181  char *q, str[512];
182 
183  q = str;
184  for(i = 0; i < buf_size; i++) {
185  c = buf[i];
186  if (c == '\0')
187  break;
188  if ((q - str) >= sizeof(str) - 1)
189  break;
190  *q++ = c;
191  }
192  *q = '\0';
193 
194  if (*str)
195  av_dict_set(&s->metadata, key, str, 0);
196 }
197 
203 static int parse_tag(AVFormatContext *s, const uint8_t *buf)
204 {
205  char str[5];
206  int genre;
207 
208  if (!(buf[0] == 'T' &&
209  buf[1] == 'A' &&
210  buf[2] == 'G'))
211  return -1;
212  get_string(s, "title", buf + 3, 30);
213  get_string(s, "artist", buf + 33, 30);
214  get_string(s, "album", buf + 63, 30);
215  get_string(s, "date", buf + 93, 4);
216  get_string(s, "comment", buf + 97, 30);
217  if (buf[125] == 0 && buf[126] != 0) {
218  snprintf(str, sizeof(str), "%d", buf[126]);
219  av_dict_set(&s->metadata, "track", str, 0);
220  }
221  genre = buf[127];
222  if (genre <= ID3v1_GENRE_MAX)
223  av_dict_set(&s->metadata, "genre", ff_id3v1_genre_str[genre], 0);
224  return 0;
225 }
226 
228 {
229  int ret;
230  uint8_t buf[ID3v1_TAG_SIZE];
231  int64_t filesize, position = avio_tell(s->pb);
232 
233  if (s->pb->seekable) {
234  /* XXX: change that */
235  filesize = avio_size(s->pb);
236  if (filesize > 128) {
237  avio_seek(s->pb, filesize - 128, SEEK_SET);
238  ret = avio_read(s->pb, buf, ID3v1_TAG_SIZE);
239  if (ret == ID3v1_TAG_SIZE) {
240  parse_tag(s, buf);
241  }
242  avio_seek(s->pb, position, SEEK_SET);
243  }
244  }
245 }