1 /**
2 * (c) 2001-2006 Nathan Hjelm <hjelmn@users.sourceforge.net>
3 * v1.5.0 mp3.c
4 *
5 * MPEG file parser
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 **/
21
22 #include <string.h>
23 #include <errno.h>
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28
29 #include <sys/ioctl.h>
30 #include <sys/types.h>
31 #include <sys/uio.h>
32 #include <sys/stat.h>
33
34 #include <time.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37
38 #include "rioi.h"
39
40 #ifdef HAVE_LIBGEN_H
41 #include <libgen.h>
42 #endif
43
44
45 #define MP3_DEBUG 0
46
47 #define MP3_PROTECTION_BIT 0x00010000
48 #define MP3_PADDING_BIT 0x00000200
49
mp3_debug(char * format,...)50 void mp3_debug (char *format, ...) {
51 #if MP3_DEBUG==1
52 va_list arg;
53 va_start (arg, format);
54 vfprintf (stderr, format, arg);
55 va_end (arg);
56 #endif
57 }
58
59 struct mp3_file {
60 FILE *fh;
61
62 int file_size; /* Bytes */
63 int tagv2_size; /* Bytes */
64 int skippage; /* Bytes */
65 int data_size; /* Bytes */
66
67 int vbr;
68 int bitrate; /* bps */
69
70 int initial_header;
71
72 int frames;
73 int xdata_size;
74
75 int layer;
76 int version;
77
78 int samplerate; /* Hz */
79
80 int length; /* ms */
81 int mod_date;
82 };
83
84 /* [version][layer][bitrate] */
85 int bitrate_table[4][4][16] = {
86 /* v2.5 */
87 {{-1, -1, -1, -1, -1. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
88 {-1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1},
89 {-1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1},
90 {-1, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1}},
91
92 /* NOTUSED */
93 {{-1, -1, -1, -1, -1. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
94 {-1, -1, -1, -1, -1. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
95 {-1, -1, -1, -1, -1. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
96 {-1, -1, -1, -1, -1. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
97
98 /* v2 */
99 {{-1, -1, -1, -1, -1. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
100 {-1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1},
101 {-1, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1},
102 {-1, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1}},
103
104 /* v1 */
105 {{-1, -1, -1, -1, -1. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
106 {-1, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1},
107 {-1, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1},
108 {-1, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1}},
109
110 };
111
112 int samplerate_table[4][4] = {
113 {11025, 12000, 8000, -1},
114 { -1, -1, -1, -1},
115 {22050, 24000, 16000, -1},
116 {44100, 48000, 32000, -1}
117 };
118
119 double version_table[] = {
120 2.5, -1.0, 2.0, 1.0
121 };
122
123 size_t layer_table[] = {
124 -1, 3, 2, 1
125 };
126
127 #define MPEG_VERSION(header) ((header & 0x00180000) >> 19)
128 #define MPEG_LAYER(header) ((header & 0x00060000) >> 17)
129 #define MPEG_BITRATEI(header) ((header & 0x0000f000) >> 12)
130 #define MPEG_SAMPLERATEI(header) ((header & 0x00000c00) >> 10)
131 #define MPEG_PADDING(header) ((header & 0x00000200) >> 9)
132
133 #define BITRATE(header) bitrate_table[MPEG_VERSION(header)][MPEG_LAYER(header)][MPEG_BITRATEI(header)]
134 #define SAMPLERATE(header) samplerate_table[MPEG_VERSION(header)][MPEG_SAMPLERATEI(header)]
135 #define PADDING(header) ((MPEG_LAYER(header) == 0x3) ? 4 : 1)
136
mpeg_frame_length(int header)137 static size_t mpeg_frame_length (int header) {
138 double bitrate = (double)BITRATE(header) * 1000.0;
139 double samplerate = (double)SAMPLERATE(header);
140 double padding = (double)MPEG_PADDING(header);
141 char layer = MPEG_LAYER(header);
142 size_t frame_length;
143
144 if (layer == 0x11)
145 frame_length = 144.0 * bitrate/samplerate + padding;
146 else
147 frame_length = (12 * bitrate/samplerate + padding) * 4.0;
148
149 return (size_t)((layer != 0x11) ? (144.0 * bitrate/samplerate + padding)
150 : (12 * bitrate/samplerate + padding) * 4.0);
151 }
152
153 /* check_mp3_header: returns 0 on success */
check_mp3_header(int header)154 static int check_mp3_header (int header) {
155 if (((header & 0xffe00000) == 0xffe00000) &&
156 (MPEG_VERSION(header) > 0.0) && (BITRATE(header) > 0)
157 && (SAMPLERATE(header) > 0))
158 return 0;
159 else if (header == 0x4d4c4c54) /* MLLT */
160 return 2;
161 else
162 return 1;
163 }
164
find_first_frame(struct mp3_file * mp3)165 static int find_first_frame (struct mp3_file *mp3) {
166 int header;
167 int buffer;
168 int ret;
169 mp3->skippage = 0;
170
171 while (fread (&header, 4, 1, mp3->fh)) {
172 header = big32_2_arch32(header);
173
174 /* MPEG-1 Layer III */
175 if ((ret = check_mp3_header (header)) == 0) {
176 /* Check for Xing frame and skip it */
177 fseek (mp3->fh, 32, SEEK_CUR);
178 fread (&buffer, 4, 1, mp3->fh);
179
180 buffer = big32_2_arch32(buffer);
181
182 if (buffer == ('X' << 24 | 'i' << 16 | 'n' << 8 | 'g') ) {
183 int xstart = ftell (mp3->fh);
184 int xflags;
185
186 /* an mp3 with an Xing header is ALWAYS vbr */
187 mp3->vbr = 1;
188
189 fread (&xflags, 4, 1, mp3->fh);
190
191 mp3_debug ("Xing flags = %08x\n", xflags);
192
193 if (xflags & 0x00000001) {
194 fread (&buffer, 4, 1, mp3->fh);
195 mp3->frames = buffer;
196
197 mp3_debug ("MPEG file has %i frames\n", mp3->frames);
198 }
199
200 if (xflags & 0x00000002) {
201 fread (&buffer, 4, 1, mp3->fh);
202 mp3->xdata_size = buffer;
203
204 mp3_debug ("MPEG file has %i bytes of data\n", mp3->xdata_size);
205 }
206
207 fseek (mp3->fh, xstart, SEEK_SET);
208 }
209
210 mp3->initial_header = header;
211
212 mp3->samplerate = SAMPLERATE(header);
213
214 mp3_debug ("Inital bitrate = %i\n", BITRATE(header));
215
216 fseek (mp3->fh, -40, SEEK_CUR);
217 return 0;
218 } else if (ret == 2)
219 return -2;
220
221 fseek (mp3->fh, -3, SEEK_CUR);
222 mp3->skippage++;
223 }
224
225 return -1;
226 }
227
228
mp3_open(char * file_name,struct mp3_file * mp3)229 static int mp3_open (char *file_name, struct mp3_file *mp3) {
230 struct stat statinfo;
231
232 char buffer[14];
233 int has_v1 = 0;
234
235 mp3_debug ("mp3_open: Entering...\n");
236
237 memset (mp3, 0 , sizeof (struct mp3_file));
238
239 if (stat (file_name, &statinfo) < 0)
240 return -errno;
241
242 mp3->file_size = mp3->data_size = statinfo.st_size;
243 mp3->mod_date = statinfo.st_mtime;
244
245 mp3->fh = fopen (file_name, "r");
246 if (mp3->fh == NULL)
247 return -errno;
248
249 /* Adjust total_size if an id3v1 tag exists */
250 fseek (mp3->fh, -128, SEEK_END);
251 memset (buffer, 0, 5);
252
253 fread (buffer, 1, 3, mp3->fh);
254 if (strncmp (buffer, "TAG", 3) == 0) {
255 mp3->data_size -= 128;
256
257 has_v1 = 1;
258
259 mp3_debug ("mp3_open: Found id3v1 tag.\n");
260 }
261 /* */
262
263 /* Check for Lyrics v2.00 */
264 fseek (mp3->fh, -9 - (has_v1 ? 128 : 0), SEEK_END);
265 memset (buffer, 0, 10);
266 fread (buffer, 1, 9, mp3->fh);
267
268 if (strncmp (buffer, "LYRICS200", 9) == 0) {
269 int lyrics_size;
270 mp3_debug ("mp3_open: Found Lyrics v2.00\n");
271
272 /* Get the size of the Lyrics */
273 fseek (mp3->fh, -15, SEEK_CUR);
274 memset (buffer, 0, 7);
275 fread (buffer, 1, 6, mp3->fh);
276
277 /* Include the size if LYRICS200 (9) and the size field (6) */
278 lyrics_size = strtol (buffer, NULL, 10) + 15;
279 mp3->data_size -= lyrics_size;
280
281 mp3_debug ("mp3_open: Lyrics are 0x%x Bytes in length.\n", lyrics_size);
282 }
283
284 /* find and skip id3v2 tag if it exists */
285 fseek (mp3->fh, 0, SEEK_SET);
286 fread (buffer, 1, 14, mp3->fh);
287 mp3->tagv2_size = id3v2_size (buffer);
288
289 fseek (mp3->fh, mp3->tagv2_size, SEEK_SET);
290
291 mp3_debug ("mp3_open: id3v2 size: 0x%08x\n", mp3->tagv2_size);
292 /****************************************/
293
294 mp3->vbr = 0;
295
296 mp3_debug ("mp3_open: Complete\n");
297
298 return find_first_frame (mp3);
299 }
300
301 #define FRAME_COUNT 30
302
mp3_scan(struct mp3_file * mp3)303 static int mp3_scan (struct mp3_file *mp3) {
304 int header;
305 int ret;
306 int frames = 0;
307 int last_bitrate = -1;
308 int total_framesize = 0;
309
310 size_t bitrate;
311 int frame_size;
312
313 mp3_debug ("mp3_scan: Entering...\n");
314
315 if (mp3->frames == 0 || mp3->xdata_size == 0) {
316 while (ftell (mp3->fh) < mp3->data_size && (frames < FRAME_COUNT || mp3->vbr)) {
317 fread (&header, 4, 1, mp3->fh);
318
319 header = big32_2_arch32 (header);
320
321 if (check_mp3_header (header) != 0) {
322 fseek (mp3->fh, -4, SEEK_CUR);
323
324 mp3_debug ("mp3_scan: Invalid header %08x %08x Bytes into the file.\n", header, ftell(mp3->fh));
325
326 if ((ret = find_first_frame (mp3)) == -1) {
327 mp3_debug ("mp3_scan: An error occured at line: %i\n", __LINE__);
328
329 /* This is hack-ish, but there might be junk at the end of the file. */
330
331 break;
332 } else if (ret == -2) {
333 mp3_debug ("mp3_scan: Ran into MLLT frame.\n");
334
335 mp3->data_size -= (mp3->file_size) - ftell (mp3->fh);
336
337 break;
338 }
339
340 continue;
341 }
342
343 bitrate = BITRATE(header);
344
345 if (!mp3->vbr && (last_bitrate != -1) && (bitrate != last_bitrate))
346 mp3->vbr = 1;
347 else
348 last_bitrate = bitrate;
349
350 frame_size = mpeg_frame_length (header);
351 total_framesize += frame_size;
352 fseek (mp3->fh, frame_size - 4, SEEK_CUR);
353 frames++;
354 }
355
356 if (frames == FRAME_COUNT) {
357 frames = (int)((double)((mp3->data_size - mp3->tagv2_size) * FRAME_COUNT) / (double)total_framesize);
358 total_framesize = mp3->data_size - mp3->tagv2_size;
359 }
360
361 if (mp3->frames == 0)
362 mp3->frames = frames;
363
364 if (mp3->xdata_size == 0)
365 mp3->xdata_size = total_framesize;
366 }
367
368 mp3->length = (int)((double)mp3->frames * 26.12245); /* each mpeg frame represents 26.12245ms */
369 mp3->bitrate = (int)(((float)mp3->xdata_size * 8.0)/(float)mp3->length);
370
371 mp3_debug ("mp3_scan: Finished scan. SampleRate: %i, BitRate: %i, Length: %i, Frames: %i.\n",
372 mp3->samplerate, mp3->bitrate, mp3->length, mp3->frames);
373
374 if (mp3->samplerate <= 0 || mp3->bitrate <= 0 || mp3->length <= 0)
375 return -1;
376
377 return 0;
378 }
379
mp3_close(struct mp3_file * mp3)380 static void mp3_close (struct mp3_file *mp3) {
381 fclose (mp3->fh);
382 }
383
get_mp3_info(char * file_name,rio_file_t * mp3_file)384 static int get_mp3_info (char *file_name, rio_file_t *mp3_file) {
385 struct mp3_file mp3;
386
387 if (mp3_open (file_name, &mp3) < 0)
388 return -1;
389
390 mp3_scan (&mp3);
391 mp3_close (&mp3);
392
393 mp3_file->bit_rate = mp3.bitrate << 7;
394 mp3_file->sample_rate = mp3.samplerate;
395 mp3_file->time = mp3.length/1000;
396 mp3_file->size = mp3.file_size;
397
398 return mp3.skippage;
399 }
400
401
402 /*
403 mp3_info:
404 Function takes in a file name (MP3) and returns a
405 Info structure containing the amount of junk (in bytes)
406 and a compete Rio header struct.
407 */
mp3_info(info_page_t * newInfo,char * file_name)408 int mp3_info (info_page_t *newInfo, char *file_name){
409 rio_file_t *mp3_file = newInfo->data;
410
411 int id3_version;
412 int mp3_header_offset;
413
414 if ((mp3_header_offset = get_mp3_info(file_name, mp3_file)) < 0) {
415 free(mp3_file);
416 newInfo->data = NULL;
417 return -1;
418 }
419
420 if ((id3_version = get_id3_info(file_name, mp3_file)) < 0) {
421 free(mp3_file);
422 newInfo->data = NULL;
423 return -1;
424 }
425
426 /* the file that will be uploaded is smaller if there is junk */
427 if (mp3_header_offset > 0 && !(id3_version >= 2)) {
428 mp3_file->size -= mp3_header_offset;
429 newInfo->skip = mp3_header_offset;
430 } else
431 /* dont want to not copy the id3v2 tags */
432 newInfo->skip = 0;
433
434 /* it is an mp3 all right, finish up the INFO structure */
435 mp3_file->bits = 0x10000b11;
436 mp3_file->type = TYPE_MP3;
437 mp3_file->foo4 = 0x00020000;
438
439 return URIO_SUCCESS;
440 }
441