Mercurial > libavformat.hg
annotate mp3.c @ 355:46029c682234 libavformat
seeking stuff
adaptively change middle position selection algo for seeking, this avoids some ugly worstcases of the interpolated variant
avoid backward search for mpeg where possible, its 17 times slower then forward according to my benchmark
author | michael |
---|---|
date | Sat, 17 Jan 2004 20:26:44 +0000 |
parents | 5552d3761ec0 |
children | 60f897e8dd2d |
rev | line source |
---|---|
234 | 1 /* |
2 * MP3 encoder and decoder | |
3 * Copyright (c) 2003 Fabrice Bellard. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 #include "avformat.h" | |
20 | |
21 #define ID3_HEADER_SIZE 10 | |
22 #define ID3_TAG_SIZE 128 | |
23 | |
24 #define ID3_GENRE_MAX 125 | |
25 | |
26 static const char *id3_genre_str[ID3_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 }; | |
154 | |
155 /* buf must be ID3_HEADER_SIZE byte long */ | |
156 static int id3_match(const uint8_t *buf) | |
157 { | |
158 return (buf[0] == 'I' && | |
159 buf[1] == 'D' && | |
160 buf[2] == '3' && | |
161 buf[3] != 0xff && | |
162 buf[4] != 0xff && | |
163 (buf[6] & 0x80) == 0 && | |
164 (buf[7] & 0x80) == 0 && | |
165 (buf[8] & 0x80) == 0 && | |
166 (buf[9] & 0x80) == 0); | |
167 } | |
168 | |
169 static void id3_get_string(char *str, int str_size, | |
170 const uint8_t *buf, int buf_size) | |
171 { | |
172 int i, c; | |
173 char *q; | |
174 | |
175 q = str; | |
176 for(i = 0; i < buf_size; i++) { | |
177 c = buf[i]; | |
178 if (c == '\0') | |
179 break; | |
180 if ((q - str) >= str_size - 1) | |
181 break; | |
182 *q++ = c; | |
183 } | |
184 *q = '\0'; | |
185 } | |
186 | |
187 /* 'buf' must be ID3_TAG_SIZE byte long */ | |
188 static int id3_parse_tag(AVFormatContext *s, const uint8_t *buf) | |
189 { | |
190 char str[5]; | |
191 int genre; | |
192 | |
193 if (!(buf[0] == 'T' && | |
194 buf[1] == 'A' && | |
195 buf[2] == 'G')) | |
196 return -1; | |
197 id3_get_string(s->title, sizeof(s->title), buf + 3, 30); | |
198 id3_get_string(s->author, sizeof(s->author), buf + 33, 30); | |
199 id3_get_string(s->album, sizeof(s->album), buf + 63, 30); | |
200 id3_get_string(str, sizeof(str), buf + 93, 4); | |
201 s->year = atoi(str); | |
202 id3_get_string(s->comment, sizeof(s->comment), buf + 97, 30); | |
203 if (buf[125] == 0 && buf[126] != 0) | |
204 s->track = buf[126]; | |
205 genre = buf[127]; | |
206 if (genre <= ID3_GENRE_MAX) | |
207 pstrcpy(s->genre, sizeof(s->genre), id3_genre_str[genre]); | |
208 return 0; | |
209 } | |
210 | |
211 static void id3_create_tag(AVFormatContext *s, uint8_t *buf) | |
212 { | |
213 int v, i; | |
214 | |
215 memset(buf, 0, ID3_TAG_SIZE); /* fail safe */ | |
216 buf[0] = 'T'; | |
217 buf[1] = 'A'; | |
218 buf[2] = 'G'; | |
219 strncpy(buf + 3, s->title, 30); | |
220 strncpy(buf + 33, s->author, 30); | |
221 strncpy(buf + 63, s->album, 30); | |
222 v = s->year; | |
223 if (v > 0) { | |
224 for(i = 0;i < 4; i++) { | |
225 buf[96 - i] = '0' + (v % 10); | |
226 v = v / 10; | |
227 } | |
228 } | |
229 strncpy(buf + 97, s->comment, 30); | |
230 if (s->track != 0) { | |
231 buf[125] = 0; | |
232 buf[126] = s->track; | |
233 } | |
234 for(i = 0; i <= ID3_GENRE_MAX; i++) { | |
235 if (!strcasecmp(s->genre, id3_genre_str[i])) { | |
236 buf[127] = i; | |
237 break; | |
238 } | |
239 } | |
240 } | |
241 | |
242 /* mp3 read */ | |
243 static int mp3_read_header(AVFormatContext *s, | |
244 AVFormatParameters *ap) | |
245 { | |
246 AVStream *st; | |
247 uint8_t buf[ID3_TAG_SIZE]; | |
248 int len, ret, filesize; | |
249 | |
250 st = av_new_stream(s, 0); | |
251 if (!st) | |
252 return AVERROR_NOMEM; | |
253 | |
254 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
255 st->codec.codec_id = CODEC_ID_MP3; | |
307 | 256 st->need_parsing = 1; |
257 | |
234 | 258 /* try to get the TAG */ |
259 if (!url_is_streamed(&s->pb)) { | |
260 /* XXX: change that */ | |
261 filesize = url_filesize(url_fileno(&s->pb)); | |
262 if (filesize > 128) { | |
263 url_fseek(&s->pb, filesize - 128, SEEK_SET); | |
264 ret = get_buffer(&s->pb, buf, ID3_TAG_SIZE); | |
265 if (ret == ID3_TAG_SIZE) { | |
266 id3_parse_tag(s, buf); | |
267 } | |
268 url_fseek(&s->pb, 0, SEEK_SET); | |
269 } | |
270 } | |
271 | |
272 /* if ID3 header found, skip it */ | |
273 ret = get_buffer(&s->pb, buf, ID3_HEADER_SIZE); | |
274 if (ret != ID3_HEADER_SIZE) | |
275 return -1; | |
276 if (id3_match(buf)) { | |
277 /* skip ID3 header */ | |
278 len = ((buf[6] & 0x7f) << 21) | | |
279 ((buf[7] & 0x7f) << 14) | | |
280 ((buf[8] & 0x7f) << 7) | | |
281 (buf[9] & 0x7f); | |
282 url_fskip(&s->pb, len); | |
283 } else { | |
284 url_fseek(&s->pb, 0, SEEK_SET); | |
285 } | |
286 | |
287 /* the parameters will be extracted from the compressed bitstream */ | |
288 return 0; | |
289 } | |
290 | |
291 #define MP3_PACKET_SIZE 1024 | |
292 | |
293 static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt) | |
294 { | |
295 int ret, size; | |
296 // AVStream *st = s->streams[0]; | |
297 | |
298 size= MP3_PACKET_SIZE; | |
299 | |
300 if (av_new_packet(pkt, size) < 0) | |
301 return -EIO; | |
302 | |
303 pkt->stream_index = 0; | |
304 ret = get_buffer(&s->pb, pkt->data, size); | |
305 if (ret <= 0) { | |
306 av_free_packet(pkt); | |
307 return -EIO; | |
308 } | |
309 /* note: we need to modify the packet size here to handle the last | |
310 packet */ | |
311 pkt->size = ret; | |
312 return ret; | |
313 } | |
314 | |
315 static int mp3_read_close(AVFormatContext *s) | |
316 { | |
317 return 0; | |
318 } | |
319 | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
241
diff
changeset
|
320 #ifdef CONFIG_ENCODERS |
234 | 321 /* simple formats */ |
322 static int mp3_write_header(struct AVFormatContext *s) | |
323 { | |
324 return 0; | |
325 } | |
326 | |
327 static int mp3_write_packet(struct AVFormatContext *s, int stream_index, | |
241 | 328 const uint8_t *buf, int size, int64_t pts) |
234 | 329 { |
330 put_buffer(&s->pb, buf, size); | |
331 put_flush_packet(&s->pb); | |
332 return 0; | |
333 } | |
334 | |
335 static int mp3_write_trailer(struct AVFormatContext *s) | |
336 { | |
337 uint8_t buf[ID3_TAG_SIZE]; | |
338 | |
339 /* write the id3 header */ | |
340 if (s->title[0] != '\0') { | |
341 id3_create_tag(s, buf); | |
342 put_buffer(&s->pb, buf, ID3_TAG_SIZE); | |
343 put_flush_packet(&s->pb); | |
344 } | |
345 return 0; | |
346 } | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
241
diff
changeset
|
347 #endif //CONFIG_ENCODERS |
234 | 348 |
349 AVInputFormat mp3_iformat = { | |
350 "mp3", | |
351 "MPEG audio", | |
352 0, | |
353 NULL, | |
354 mp3_read_header, | |
355 mp3_read_packet, | |
356 mp3_read_close, | |
357 .extensions = "mp2,mp3", /* XXX: use probe */ | |
358 }; | |
359 | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
241
diff
changeset
|
360 #ifdef CONFIG_ENCODERS |
234 | 361 AVOutputFormat mp2_oformat = { |
362 "mp2", | |
363 "MPEG audio layer 2", | |
364 "audio/x-mpeg", | |
365 #ifdef CONFIG_MP3LAME | |
366 "mp2", | |
367 #else | |
368 "mp2,mp3", | |
369 #endif | |
370 0, | |
371 CODEC_ID_MP2, | |
372 0, | |
373 mp3_write_header, | |
374 mp3_write_packet, | |
375 mp3_write_trailer, | |
376 }; | |
377 | |
378 #ifdef CONFIG_MP3LAME | |
379 AVOutputFormat mp3_oformat = { | |
380 "mp3", | |
381 "MPEG audio layer 3", | |
382 "audio/x-mpeg", | |
383 "mp3", | |
384 0, | |
385 CODEC_ID_MP3, | |
386 0, | |
387 mp3_write_header, | |
388 mp3_write_packet, | |
389 mp3_write_trailer, | |
390 }; | |
391 #endif | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
241
diff
changeset
|
392 #endif //CONFIG_ENCODERS |
234 | 393 |
394 int mp3_init(void) | |
395 { | |
396 av_register_input_format(&mp3_iformat); | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
241
diff
changeset
|
397 #ifdef CONFIG_ENCODERS |
234 | 398 av_register_output_format(&mp2_oformat); |
399 #ifdef CONFIG_MP3LAME | |
400 av_register_output_format(&mp3_oformat); | |
401 #endif | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
241
diff
changeset
|
402 #endif //CONFIG_ENCODERS |
234 | 403 return 0; |
404 } |