summaryrefslogtreecommitdiff
path: root/firmware/mp3data.c
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2003-03-10 14:55:31 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2003-03-10 14:55:31 +0000
commita039091187f40d018b6353b8c13de7a01d3a6fe0 (patch)
tree08f7eb86e86e2c61f4d36f9c91731cb93252ba84 /firmware/mp3data.c
parent22cbe938feb48895d7488449835d3ee577399057 (diff)
downloadrockbox-a039091187f40d018b6353b8c13de7a01d3a6fe0.tar.gz
rockbox-a039091187f40d018b6353b8c13de7a01d3a6fe0.zip
New ID3 and MP3 stream parser, plus not-yet-ready Xing header generation code
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3410 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/mp3data.c')
-rw-r--r--firmware/mp3data.c664
1 files changed, 664 insertions, 0 deletions
diff --git a/firmware/mp3data.c b/firmware/mp3data.c
new file mode 100644
index 0000000000..8d925041ce
--- /dev/null
+++ b/firmware/mp3data.c
@@ -0,0 +1,664 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20/*
21 * Parts of this code has been stolen from the Ample project and was written
22 * by David Härdeman. It has since been extended and enhanced pretty much by
23 * all sorts of friendly Rockbox people.
24 *
25 * A nice reference for MPEG header info:
26 * http://rockbox.haxx.se/docs/mpeghdr.html
27 *
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <stdbool.h>
34#include "debug.h"
35#include "mp3data.h"
36#include "file.h"
37
38#define DEBUG_VERBOSE
39
40#define BYTES2INT(b1,b2,b3,b4) (((b1 & 0xFF) << (3*8)) | \
41 ((b2 & 0xFF) << (2*8)) | \
42 ((b3 & 0xFF) << (1*8)) | \
43 ((b4 & 0xFF) << (0*8)))
44
45#define SYNC_MASK (0x7ff << 21)
46#define VERSION_MASK (3 << 19)
47#define LAYER_MASK (3 << 17)
48#define PROTECTION_MASK (1 << 16)
49#define BITRATE_MASK (0xf << 12)
50#define SAMPLERATE_MASK (3 << 10)
51#define PADDING_MASK (1 << 9)
52#define PRIVATE_MASK (1 << 8)
53#define CHANNELMODE_MASK (3 << 6)
54#define MODE_EXT_MASK (3 << 4)
55#define COPYRIGHT_MASK (1 << 3)
56#define ORIGINAL_MASK (1 << 2)
57#define EMPHASIS_MASK 3
58
59/* Table of bitrates for MP3 files, all values in kilo.
60 * Indexed by version, layer and value of bit 15-12 in header.
61 */
62const int bitrate_table[2][3][16] =
63{
64 {
65 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
66 {0,32,48,56, 64,80, 96, 112,128,160,192,224,256,320,384,0},
67 {0,32,40,48, 56,64, 80, 96, 112,128,160,192,224,256,320,0}
68 },
69 {
70 {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0},
71 {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0},
72 {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0}
73 }
74};
75
76/* Table of samples per frame for MP3 files.
77 * Indexed by layer. Multiplied with 1000.
78 */
79const int bs[3] = {384000, 1152000, 1152000};
80
81/* Table of sample frequency for MP3 files.
82 * Indexed by version and layer.
83 */
84
85const int freqtab[][4] =
86{
87 {11025, 12000, 8000, 0}, /* MPEG version 2.5 */
88 {44100, 48000, 32000, 0}, /* MPEG Version 1 */
89 {22050, 24000, 16000, 0}, /* MPEG version 2 */
90};
91
92/* check if 'head' is a valid mp3 frame header */
93static bool is_mp3frameheader(unsigned long head)
94{
95 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
96 return false;
97 if ((head & VERSION_MASK) == (1 << 19)) /* bad version? */
98 return false;
99 if (!(head & LAYER_MASK)) /* no layer? */
100 return false;
101 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
102 return false;
103 if (!(head & BITRATE_MASK)) /* no bitrate? */
104 return false;
105 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
106 return false;
107 if (((head >> 19) & 1) == 1 &&
108 ((head >> 17) & 3) == 3 &&
109 ((head >> 16) & 1) == 1)
110 return false;
111 if ((head & 0xffff0000) == 0xfffe0000)
112 return false;
113
114 return true;
115}
116
117static bool mp3headerinfo(struct mp3info *info, unsigned long header)
118{
119 int bittable = 0;
120 int bitindex;
121 int freqindex;
122
123 /* MPEG Audio Version */
124 switch(header & VERSION_MASK) {
125 case 0:
126 /* MPEG version 2.5 is not an official standard */
127 info->version = MPEG_VERSION2_5;
128 bittable = MPEG_VERSION2 - 1; /* use the V2 bit rate table */
129 break;
130
131 case (1 << 19):
132 return false;
133
134 case (2 << 19):
135 /* MPEG version 2 (ISO/IEC 13818-3) */
136 info->version = MPEG_VERSION2;
137 bittable = MPEG_VERSION2 - 1;
138 break;
139
140 case (3 << 19):
141 /* MPEG version 1 (ISO/IEC 11172-3) */
142 info->version = MPEG_VERSION1;
143 bittable = MPEG_VERSION1 - 1;
144 break;
145 }
146
147 switch(header & LAYER_MASK) {
148 case 0:
149 return false;
150 case (1 << 17):
151 info->layer = 2;
152 break;
153 case (2 << 17):
154 info->layer = 1;
155 break;
156 case (3 << 17):
157 info->layer = 0;
158 break;
159 }
160
161 info->protection = (header & PROTECTION_MASK)?true:false;
162
163 /* Bitrate */
164 bitindex = (header & 0xf000) >> 12;
165 info->bitrate = bitrate_table[bittable][info->layer][bitindex];
166 if(info->bitrate == 0)
167 return false;
168
169 /* Sampling frequency */
170 freqindex = (header & 0x0C00) >> 10;
171 info->frequency = freqtab[info->version][freqindex];
172 if(info->frequency == 0)
173 return false;
174
175 info->padding = (header & 0x0200)?1:0;
176
177 /* Calculate number of bytes, calculation depends on layer */
178 switch(info->layer) {
179 case 0:
180 info->frame_size = info->bitrate * 48000;
181 info->frame_size /=
182 freqtab[info->version][freqindex] << bittable;
183 break;
184 case 1:
185 case 2:
186 info->frame_size = info->bitrate * 144000;
187 info->frame_size /=
188 freqtab[info->version][freqindex] << bittable;
189 break;
190 default:
191 info->frame_size = 1;
192 }
193
194 info->frame_size += info->padding;
195
196 /* Calculate time per frame */
197 info->frame_time = bs[info->layer] /
198 (freqtab[info->version][freqindex] << bittable);
199
200 info->channel_mode = (header & 0xc0) >> 6;
201 info->mode_extension = (header & 0x30) >> 4;
202 info->emphasis = header & 3;
203
204#ifdef DEBUG_VERBOSE
205 DEBUGF( "Header: %08x, Ver %d, lay %d, bitr %d, freq %d, "
206 "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d\n",
207 header, info->version, info->layer, info->bitrate, info->frequency,
208 info->channel_mode, info->mode_extension,
209 info->emphasis, info->frame_size, info->frame_time);
210#endif
211 return true;
212}
213
214unsigned long find_next_frame(int fd, int *offset, int max_offset, unsigned long last_header)
215{
216 unsigned long header=0;
217 unsigned char tmp;
218 int i;
219
220 int pos = 0;
221
222 /* We remember the last header we found, to use as a template to see if
223 the header we find has the same frequency, layer etc */
224 last_header &= 0xffff0c00;
225
226 /* Fill up header with first 24 bits */
227 for(i = 0; i < 3; i++) {
228 header <<= 8;
229 if(!read(fd, &tmp, 1))
230 return 0;
231 header |= tmp;
232 pos++;
233 }
234
235 do {
236 header <<= 8;
237 if(!read(fd, &tmp, 1))
238 return 0;
239 header |= tmp;
240 pos++;
241 if(max_offset > 0 && pos > max_offset)
242 return 0;
243 } while(!is_mp3frameheader(header) ||
244 (last_header?((header & 0xffff0c00) != last_header):false));
245
246 *offset = pos - 4;
247
248#ifdef DEBUG
249 if(*offset)
250 DEBUGF("Warning: skipping %d bytes of garbage\n", *offset);
251#endif
252
253 return header;
254}
255
256#ifdef SIMULATOR
257unsigned char mp3buf[0x100000];
258unsigned char mp3end[1];
259#else
260extern unsigned char mp3buf[];
261extern unsigned char mp3end[];
262#endif
263static int fnf_read_index;
264static int fnf_buf_len;
265
266static int fd;
267
268static int buf_getbyte(unsigned char *c)
269{
270 if(fnf_read_index < fnf_buf_len)
271 {
272 *c = mp3buf[fnf_read_index++];
273 return 1;
274 }
275 else
276 {
277 fnf_buf_len = read(fd, mp3buf, mp3end - mp3buf);
278 if(fnf_buf_len < 0)
279 return -1;
280
281 fnf_read_index = 0;
282
283 if(fnf_buf_len > 0)
284 {
285 *c = mp3buf[fnf_read_index++];
286 return 1;
287 }
288 else
289 return 0;
290 }
291 return 0;
292}
293
294static int buf_seek(int len)
295{
296 fnf_read_index += len;
297 if(fnf_read_index > fnf_buf_len)
298 {
299 len = fnf_read_index - fnf_buf_len;
300
301 fnf_buf_len = read(fd, mp3buf, mp3end - mp3buf);
302 if(fnf_buf_len < 0)
303 return -1;
304
305 fnf_read_index = 0;
306 fnf_read_index += len;
307 }
308
309 if(fnf_read_index > fnf_buf_len)
310 {
311 return -1;
312 }
313 else
314 return 0;
315}
316
317static void buf_init(void)
318{
319 fnf_buf_len = 0;
320 fnf_read_index = 0;
321}
322
323unsigned long buf_find_next_frame(int *offset, int max_offset,
324 unsigned long last_header)
325{
326 unsigned long header=0;
327 unsigned char tmp;
328 int i;
329
330 int pos = 0;
331
332 /* We remember the last header we found, to use as a template to see if
333 the header we find has the same frequency, layer etc */
334 last_header &= 0xffff0c00;
335
336 /* Fill up header with first 24 bits */
337 for(i = 0; i < 3; i++) {
338 header <<= 8;
339 if(!buf_getbyte(&tmp))
340 return 0;
341 header |= tmp;
342 pos++;
343 }
344
345 do {
346 header <<= 8;
347 if(!buf_getbyte(&tmp))
348 return 0;
349 header |= tmp;
350 pos++;
351 if(max_offset > 0 && pos > max_offset)
352 return 0;
353 } while(!is_mp3frameheader(header) ||
354 (last_header?((header & 0xffff0c00) != last_header):false));
355
356 *offset = pos - 4;
357
358#ifdef DEBUG
359 if(*offset)
360 DEBUGF("Warning: skipping %d bytes of garbage\n", *offset);
361#endif
362
363 return header;
364}
365
366int get_mp3file_info(int fd, struct mp3info *info)
367{
368 unsigned char frame[1024];
369 unsigned char *vbrheader;
370 unsigned long header;
371 int bytecount;
372 int num_offsets;
373 int frames_per_entry;
374 int i;
375 int offset;
376 int j;
377 int tmp;
378
379 header = find_next_frame(fd, &bytecount, 0x20000, 0);
380 /* Quit if we haven't found a valid header within 128K */
381 if(header == 0)
382 return -1;
383
384 memset(info, 0, sizeof(struct mp3info));
385 if(!mp3headerinfo(info, header))
386 return -2;
387
388 /* OK, we have found a frame. Let's see if it has a Xing header */
389 if(read(fd, frame, info->frame_size-4) < 0)
390 return -3;
391
392 /* calculate position of VBR header */
393 if ( info->version == MPEG_VERSION1 ) {
394 if (info->channel_mode == 3) /* mono */
395 vbrheader = frame + 17;
396 else
397 vbrheader = frame + 32;
398 }
399 else {
400 if (info->channel_mode == 3) /* mono */
401 vbrheader = frame + 9;
402 else
403 vbrheader = frame + 17;
404 }
405
406 if (vbrheader[0] == 'X' &&
407 vbrheader[1] == 'i' &&
408 vbrheader[2] == 'n' &&
409 vbrheader[3] == 'g')
410 {
411 int i = 8; /* Where to start parsing info */
412
413 DEBUGF("Xing header\n");
414
415 /* Remember where in the file the Xing header is */
416 info->xing_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size;
417
418 /* We want to skip the Xing frame when playing the stream */
419 bytecount += info->frame_size;
420
421 /* Now get the next frame to find out the real info about
422 the mp3 stream */
423 header = find_next_frame(fd, &tmp, 0x20000, 0);
424 if(header == 0)
425 return -4;
426
427 if(!mp3headerinfo(info, header))
428 return -5;
429
430 /* Yes, it is a VBR file */
431 info->is_vbr = true;
432 info->is_xing_vbr = true;
433
434 if(vbrheader[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
435 {
436 info->frame_count = BYTES2INT(vbrheader[i], vbrheader[i+1],
437 vbrheader[i+2], vbrheader[i+3]);
438 info->file_time = info->frame_count * info->frame_time;
439 i += 4;
440 }
441
442 if(vbrheader[7] & VBR_BYTES_FLAG) /* Is byte count there? */
443 {
444 info->byte_count = BYTES2INT(vbrheader[i], vbrheader[i+1],
445 vbrheader[i+2], vbrheader[i+3]);
446 info->bitrate = info->byte_count * 8 / info->file_time;
447 i += 4;
448 }
449
450 if(vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
451 {
452 memcpy( info->toc, vbrheader+i, 100 );
453 }
454 }
455
456 if (vbrheader[0] == 'V' &&
457 vbrheader[1] == 'B' &&
458 vbrheader[2] == 'R' &&
459 vbrheader[3] == 'I')
460 {
461 DEBUGF("VBRI header\n");
462
463 /* We want to skip the VBRI frame when playing the stream */
464 bytecount += info->frame_size;
465
466 /* Now get the next frame to find out the real info about
467 the mp3 stream */
468 header = find_next_frame(fd, &bytecount, 0x20000, 0);
469 if(header == 0)
470 return -6;
471
472 if(!mp3headerinfo(info, header))
473 return -7;
474
475 DEBUGF("%04x: %04x %04x ", 0, header >> 16, header & 0xffff);
476 for(i = 4;i < (int)sizeof(frame)-4;i+=2) {
477 if(i % 16 == 0) {
478 DEBUGF("\n%04x: ", i-4);
479 }
480 DEBUGF("%04x ", (frame[i-4] << 8) | frame[i-4+1]);
481 }
482
483 DEBUGF("\n");
484
485 /* Yes, it is a FhG VBR file */
486 info->is_vbr = true;
487 info->is_vbri_vbr = true;
488 info->has_toc = false; /* We don't parse the TOC (yet) */
489
490 info->byte_count = BYTES2INT(vbrheader[10], vbrheader[11],
491 vbrheader[12], vbrheader[13]);
492 info->frame_count = BYTES2INT(vbrheader[14], vbrheader[15],
493 vbrheader[16], vbrheader[17]);
494
495 info->file_time = info->frame_count * info->frame_time;
496 info->bitrate = info->byte_count * 8 / info->file_time;
497
498 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
499 num_offsets = BYTES2INT(0, 0, vbrheader[18], vbrheader[19]);
500 frames_per_entry = BYTES2INT(0, 0, vbrheader[24], vbrheader[25]);
501 DEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
502 info->bitrate, info->frame_size, info->frame_size);
503 DEBUGF("Frame count: %x\n", info->frame_count);
504 DEBUGF("Byte count: %x\n", info->byte_count);
505 DEBUGF("Offsets: %d\n", num_offsets);
506 DEBUGF("Frames/entry: %d\n", frames_per_entry);
507
508 offset = 0;
509
510 for(i = 0;i < num_offsets;i++)
511 {
512 j = BYTES2INT(0, 0, vbrheader[26+i*2], vbrheader[27+i*2]);
513 offset += j;
514 DEBUGF("%03d: %x (%x)\n", i, offset - bytecount, j);
515 }
516 }
517
518 /* Is it a LAME Info frame? */
519 if (vbrheader[0] == 'I' &&
520 vbrheader[1] == 'n' &&
521 vbrheader[2] == 'f' &&
522 vbrheader[3] == 'o')
523 {
524 /* Make sure we skip this frame in playback */
525 bytecount += info->frame_size;
526 }
527
528 return bytecount;
529}
530
531/* This is an MP3 header, 128kbit/s, 44.1kHz, with silence */
532static const unsigned char xing_frame_header[] = {
533 0xff, 0xfa, 0x90, 0x64, 0x86, 0x1f
534};
535
536static const char cooltext[] = "Rockbox rocks";
537
538static void int2bytes(unsigned char *buf, int val)
539{
540 buf[0] = (val >> 24) & 0xff;
541 buf[1] = (val >> 16) & 0xff;
542 buf[2] = (val >> 8) & 0xff;
543 buf[3] = val & 0xff;
544}
545
546int count_mp3_frames(int fd, int startpos, int filesize,
547 void (*progressfunc)(int))
548{
549 unsigned long header = 0;
550 struct mp3info info;
551 int num_frames;
552 int bytes;
553 int cnt;
554 int progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
555 int progress_cnt = 0;
556
557 if(lseek(fd, startpos, SEEK_SET) < 0)
558 return -1;
559
560 buf_init();
561
562 /* Find out the total number of frames */
563 num_frames = 0;
564 cnt = 0;
565
566 while((header = buf_find_next_frame(&bytes, -1, header))) {
567 mp3headerinfo(&info, header);
568 buf_seek(info.frame_size-4);
569 num_frames++;
570 if(progressfunc)
571 {
572 cnt += bytes + info.frame_size;
573 if(cnt > progress_chunk)
574 {
575 progress_cnt++;
576 progressfunc(progress_cnt);
577 cnt = 0;
578 }
579 }
580 }
581 DEBUGF("Total number of frames: %d\n", num_frames);
582
583 return num_frames;
584}
585
586int create_xing_header(int fd, int startpos, int filesize,
587 unsigned char *buf, int num_frames,
588 void (*progressfunc)(int))
589{
590 unsigned long header = 0;
591 struct mp3info info;
592 int pos, last_pos;
593 int i, j;
594 int bytes;
595 int filepos;
596 int tocentry;
597 int x;
598
599 DEBUGF("create_xing_header()\n");
600
601 /* Create the frame header */
602 memset(buf, 0, 417);
603 memcpy(buf, xing_frame_header, 6);
604
605 lseek(fd, startpos, SEEK_SET);
606 buf_init();
607
608 buf[36] = 'X';
609 buf[36+1] = 'i';
610 buf[36+2] = 'n';
611 buf[36+3] = 'g';
612 int2bytes(&buf[36+4], (VBR_FRAMES_FLAG | VBR_BYTES_FLAG | VBR_TOC_FLAG));
613 int2bytes(&buf[36+8], num_frames);
614 int2bytes(&buf[36+12], filesize - startpos);
615
616 /* Generate filepos table */
617 last_pos = 0;
618 filepos = 0;
619 header = 0;
620 x = 0;
621 for(i = 0;i < 100;i++) {
622 /* Calculate the absolute frame number for this seek point */
623 pos = i * num_frames / 100;
624
625 /* Advance from the last seek point to this one */
626 for(j = 0;j < pos - last_pos;j++)
627 {
628 DEBUGF("fpos: %x frame no: %x ", filepos, x++);
629 header = buf_find_next_frame(&bytes, -1, header);
630 mp3headerinfo(&info, header);
631 buf_seek(info.frame_size-4);
632 filepos += info.frame_size;
633 }
634
635 if(progressfunc)
636 {
637 progressfunc(50 + i/2);
638 }
639
640 tocentry = filepos * 256 / filesize;
641
642 DEBUGF("Pos %d: %d relpos: %d filepos: %x tocentry: %x\n",
643 i, pos, pos-last_pos, filepos, tocentry);
644
645 /* Fill in the TOC entry */
646 buf[36+16+i] = tocentry;
647
648 last_pos = pos;
649 }
650
651 memcpy(buf+152, cooltext, sizeof(cooltext));
652
653#ifdef DEBUG
654 for(i = 0;i < 417;i++)
655 {
656 if(i && !(i % 16))
657 DEBUGF("\n");
658
659 DEBUGF("%02x ", buf[i]);
660 }
661#endif
662
663 return 0;
664}