Fixed red build
[kugel-rb.git] / firmware / id3.c
blobf09ccf4ab21fb19fea9ed0afd6b9d0b00db0db30
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Daniel Stenberg
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
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.
25 * A nice reference for MPEG header info:
26 * http://rockbox.haxx.se/docs/mpeghdr.html
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdbool.h>
35 #include "file.h"
36 #include "debug.h"
37 #include "atoi.h"
39 #include "id3.h"
41 #define UNSYNC(b0,b1,b2,b3) (((b0 & 0x7F) << (3*7)) | \
42 ((b1 & 0x7F) << (2*7)) | \
43 ((b2 & 0x7F) << (1*7)) | \
44 ((b3 & 0x7F) << (0*7)))
46 #define BYTES2INT(b0,b1,b2,b3) (((b0 & 0xFF) << (3*8)) | \
47 ((b1 & 0xFF) << (2*8)) | \
48 ((b2 & 0xFF) << (1*8)) | \
49 ((b3 & 0xFF) << (0*8)))
51 /* Table of bitrates for MP3 files, all values in kilo.
52 * Indexed by version, layer and value of bit 15-12 in header.
54 const int bitrate_table[2][3][16] =
57 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
58 {0,32,48,56, 64,80, 96, 112,128,160,192,224,256,320,384,0},
59 {0,32,40,48, 56,64, 80, 96, 112,128,160,192,224,256,320,0}
62 {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0},
63 {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0},
64 {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0}
68 /* Table of samples per frame for MP3 files.
69 * Indexed by layer. Multiplied with 1000.
71 const int bs[4] = {0, 384000, 1152000, 1152000};
73 /* Table of sample frequency for MP3 files.
74 * Indexed by version and layer.
76 const int freqtab[][4] =
78 {11025, 12000, 8000, 0}, /* MPEG version 2.5 */
79 {44100, 48000, 32000, 0}, /* MPEG Version 1 */
80 {22050, 24000, 16000, 0}, /* MPEG version 2 */
83 #define UNICODE_BOM_1 0xfffe
84 #define UNICODE_BOM_2 0xfeff
86 /* Checks to see if the passed in string is a 16-bit wide Unicode v2
87 string. If it is, we attempt to convert it to a 8-bit ASCII string
88 (for valid 8-bit ASCII characters). If it's not unicode, we leave
89 it alone. At some point we should fully support unicode strings */
90 static int unicode_munge(char** string, int *len) {
91 int tmp;
92 bool le = false;
93 int i;
94 char *str = *string;
95 char *outstr = *string;
97 if(str[0] > 0x03) {
98 /* Plain old string */
99 return 0;
102 /* Type 0x00 is ordinary ISO 8859-1 */
103 if(str[0] == 0x00) {
104 (*len)--;
105 (*string)++; /* Skip the encoding type byte */
106 return 0;
109 /* Unicode with or without BOM */
110 if(str[0] == 0x01 || str[0] == 0x02) {
111 str++;
112 tmp = BYTES2INT(0, 0, str[1], str[2]);
114 if(tmp == UNICODE_BOM_2) { /* Little endian? */
115 le = true;
116 str += 2;
119 if(tmp == UNICODE_BOM_1) /* Big endian? */
120 str += 2;
122 i = 0;
124 do {
125 if(le) {
126 if(str[1])
127 outstr[i++] = '.';
128 else
129 outstr[i++] = str[0];
130 } else {
131 if(str[0])
132 outstr[i++] = '.';
133 else
134 outstr[i++] = str[1];
136 } while(str[0] || str[1]);
138 *len = i;
139 (*string)++; /* Skip the encoding type byte */
140 return 0;
143 /* If we come here, the string was of an unsupported type */
144 *len = 1;
145 outstr[0] = 0;
146 return -1;
150 * Removes trailing spaces from a string.
152 * Arguments: buffer - the string to process
154 * Returns: void
156 static void
157 stripspaces(char *buffer)
159 int i = 0;
160 while(*(buffer + i) != '\0')
161 i++;
163 for(;i >= 0; i--) {
164 if(*(buffer + i) == ' ')
165 *(buffer + i) = '\0';
166 else if(*(buffer + i) == '\0')
167 continue;
168 else
169 break;
174 * Sets the title of an MP3 entry based on its ID3v1 tag.
176 * Arguments: file - the MP3 file to scen for a ID3v1 tag
177 * entry - the entry to set the title in
179 * Returns: true if a title was found and created, else false
181 static bool setid3v1title(int fd, struct mp3entry *entry)
183 unsigned char buffer[31];
184 int offsets[4] = {-95,-65,-125,-31};
185 int i;
187 for (i=0;i<4;i++) {
188 if (-1 == lseek(fd, offsets[i], SEEK_END))
189 return false;
191 buffer[30]=0;
192 read(fd, buffer, 30);
193 stripspaces(buffer);
195 if (buffer[0] || i == 3) {
196 switch(i) {
197 case 0:
198 strcpy(entry->id3v1buf[0], buffer);
199 entry->artist = entry->id3v1buf[0];
200 break;
201 case 1:
202 strcpy(entry->id3v1buf[1], buffer);
203 entry->album = entry->id3v1buf[1];
204 break;
205 case 2:
206 strcpy(entry->id3v1buf[2], buffer);
207 entry->title = entry->id3v1buf[2];
208 break;
209 case 3:
210 /* id3v1.1 uses last two bytes of comment field for track
211 number: first must be 0 and second is track num */
212 if (buffer[28] == 0)
213 entry->tracknum = buffer[29];
214 break;
219 return true;
224 * Sets the title of an MP3 entry based on its ID3v2 tag.
226 * Arguments: file - the MP3 file to scan for a ID3v2 tag
227 * entry - the entry to set the title in
229 * Returns: true if a title was found and created, else false
231 static void setid3v2title(int fd, struct mp3entry *entry)
233 int minframesize;
234 int size;
235 int bufferpos = 0, totframelen, framelen;
236 char header[10];
237 unsigned short int version;
238 char *buffer = entry->id3v2buf;
239 char *tracknum = NULL;
240 int bytesread = 0;
241 int buffersize = sizeof(entry->id3v2buf);
243 /* Bail out if the tag is shorter than 10 bytes */
244 if(entry->id3v2len < 10)
245 return;
247 /* Read the ID3 tag version from the header */
248 lseek(fd, 0, SEEK_SET);
249 if(10 != read(fd, header, 10))
250 return;
252 version = (unsigned short int)header[3];
254 /* Get the total ID3 tag size */
255 size = entry->id3v2len - 10;
257 /* Set minimum frame size according to ID3v2 version */
258 if(version > 2)
259 minframesize = 12;
260 else
261 minframesize = 8;
264 * We must have at least minframesize bytes left for the
265 * remaining frames to be interesting
267 while(size > minframesize) {
268 /* Read frame header and check length */
269 if(version > 2) {
270 if(10 != read(fd, header, 10))
271 return;
272 /* Adjust for the 10 bytes we read */
273 size -= 10;
275 if (version > 3) {
276 framelen = UNSYNC(header[4], header[5],
277 header[6], header[7]);
278 } else {
279 /* version .3 files don't use synchsafe ints for
280 * size */
281 framelen = BYTES2INT(header[4], header[5],
282 header[6], header[7]);
284 } else {
285 if(6 != read(fd, header, 6))
286 return;
287 /* Adjust for the 6 bytes we read */
288 size -= 6;
290 framelen = BYTES2INT(0, header[3], header[4], header[5]);
293 /* Keep track of the total size */
294 totframelen = framelen;
296 if(framelen == 0)
297 return;
299 /* If the frame is larger than the remaining buffer space we try
300 to read as much as would fit in the buffer */
301 if(framelen >= buffersize - bufferpos)
302 framelen = buffersize - bufferpos - 1;
304 /* Check for certain frame headers */
305 if(!strncmp(header, "TPE1", strlen("TPE1")) ||
306 !strncmp(header, "TP1", strlen("TP1"))) {
307 bytesread = read(fd, buffer + bufferpos, framelen);
308 entry->artist = buffer + bufferpos;
309 unicode_munge(&entry->artist, &bytesread);
310 entry->artist[bytesread + 1] = '\0';
311 bufferpos += bytesread + 2;
312 size -= bytesread;
314 else if(!strncmp(header, "TIT2", strlen("TIT2")) ||
315 !strncmp(header, "TT2", strlen("TT2"))) {
316 bytesread = read(fd, buffer + bufferpos, framelen);
317 entry->title = buffer + bufferpos;
318 unicode_munge(&entry->title, &bytesread);
319 entry->title[bytesread + 1] = '\0';
320 bufferpos += bytesread + 2;
321 size -= bytesread;
323 else if(!strncmp(header, "TALB", strlen("TALB"))) {
324 bytesread = read(fd, buffer + bufferpos, framelen);
325 entry->album = buffer + bufferpos;
326 unicode_munge(&entry->album, &bytesread);
327 entry->album[bytesread + 1] = '\0';
328 bufferpos += bytesread + 2;
329 size -= bytesread;
331 else if(!strncmp(header, "TRCK", strlen("TRCK"))) {
332 bytesread = read(fd, buffer + bufferpos, framelen);
333 tracknum = buffer + bufferpos;
334 unicode_munge(&tracknum, &bytesread);
335 tracknum[bytesread + 1] = '\0';
336 entry->tracknum = atoi(tracknum);
337 bufferpos += bytesread + 1;
338 size -= bytesread;
340 else {
341 /* Unknown frame, skip it using the total size in case
342 it was truncated */
343 size -= totframelen;
344 lseek(fd, totframelen, SEEK_CUR);
350 * Calculates the size of the ID3v2 tag.
352 * Arguments: file - the file to search for a tag.
354 * Returns: the size of the tag or 0 if none was found
356 static int getid3v2len(int fd)
358 char buf[6];
359 int offset;
361 /* Make sure file has a ID3 tag */
362 if((-1 == lseek(fd, 0, SEEK_SET)) ||
363 (read(fd, buf, 6) != 6) ||
364 (strncmp(buf, "ID3", strlen("ID3")) != 0))
365 offset = 0;
367 /* Now check what the ID3v2 size field says */
368 else if(read(fd, buf, 4) != 4)
369 offset = 0;
370 else
371 offset = UNSYNC(buf[0], buf[1], buf[2], buf[3]) + 10;
373 return offset;
376 static int getfilesize(int fd)
378 int size;
380 /* seek to the end of it */
381 size = lseek(fd, 0, SEEK_END);
382 if(-1 == size)
383 return 0; /* unknown */
385 return size;
389 * Calculates the size of the ID3v1 tag.
391 * Arguments: file - the file to search for a tag.
393 * Returns: the size of the tag or 0 if none was found
395 static int getid3v1len(int fd)
397 char buf[3];
398 int offset;
400 /* Check if we find "TAG" 128 bytes from EOF */
401 if((lseek(fd, -128, SEEK_END) == -1) ||
402 (read(fd, buf, 3) != 3) ||
403 (strncmp(buf, "TAG", 3) != 0))
404 offset = 0;
405 else
406 offset = 128;
408 return offset;
411 /* check if 'head' is a valid mp3 frame header */
412 static bool mp3frameheader(unsigned long head)
414 if ((head & 0xffe00000) != 0xffe00000) /* bad sync? */
415 return false;
416 if (!((head >> 17) & 3)) /* no layer? */
417 return false;
418 if (((head >> 12) & 0xf) == 0xf) /* bad bitrate? */
419 return false;
420 if (!((head >> 12) & 0xf)) /* no bitrate? */
421 return false;
422 if (((head >> 10) & 0x3) == 0x3) /* bad sample rate? */
423 return false;
424 if (((head >> 19) & 1) == 1 &&
425 ((head >> 17) & 3) == 3 &&
426 ((head >> 16) & 1) == 1)
427 return false;
428 if ((head & 0xffff0000) == 0xfffe0000)
429 return false;
431 return true;
435 * Calculates the length (in milliseconds) of an MP3 file.
437 * Modified to only use integers.
439 * Arguments: file - the file to calculate the length upon
440 * entry - the entry to update with the length
442 * Returns: the song length in milliseconds,
443 * 0 means that it couldn't be calculated
445 static int getsonglength(int fd, struct mp3entry *entry)
447 unsigned int filetime = 0;
448 unsigned long header=0;
449 unsigned char tmp;
450 unsigned char frame[156];
451 unsigned char* xing;
453 enum {
454 MPEG_VERSION2_5,
455 MPEG_VERSION1,
456 MPEG_VERSION2
457 } version;
458 int layer;
459 int bitindex;
460 int bitrate;
461 int freqindex;
462 int frequency;
463 int chmode;
464 int bytecount;
465 int bytelimit;
466 int bittable; /* which bitrate table to use */
467 bool header_found = false;
469 long bpf;
470 long tpf;
472 /* Start searching after ID3v2 header */
473 if(-1 == lseek(fd, entry->id3v2len, SEEK_SET))
474 return 0;
476 /* Fill up header with first 24 bits */
477 for(version = 0; version < 3; version++) {
478 header <<= 8;
479 if(!read(fd, &tmp, 1))
480 return 0;
481 header |= tmp;
484 /* Loop trough file until we find a frame header */
485 bytecount = entry->id3v2len - 1;
486 bytelimit = entry->id3v2len + 0x20000;
487 restart:
488 do {
489 header <<= 8;
490 if(!read(fd, &tmp, 1))
491 return 0;
492 header |= tmp;
494 /* Quit if we haven't found a valid header within 128K */
495 bytecount++;
496 if(bytecount > bytelimit)
497 return 0;
498 } while(!mp3frameheader(header));
501 * Some files are filled with garbage in the beginning,
502 * if the bitrate index of the header is binary 1111
503 * that is a good indicator
505 if((header & 0xF000) == 0xF000)
506 goto restart;
508 /* MPEG Audio Version */
509 switch((header & 0x180000) >> 19) {
510 case 0:
511 /* MPEG version 2.5 is not an official standard */
512 version = MPEG_VERSION2_5;
513 bittable = MPEG_VERSION2; /* use the V2 bit rate table */
514 break;
516 case 2:
517 /* MPEG version 2 (ISO/IEC 13818-3) */
518 version = MPEG_VERSION2;
519 bittable = MPEG_VERSION2;
520 break;
522 case 3:
523 /* MPEG version 1 (ISO/IEC 11172-3) */
524 version = MPEG_VERSION1;
525 bittable = MPEG_VERSION1;
526 break;
527 default:
528 goto restart;
531 /* Layer */
532 switch((header & 0x060000) >> 17) {
533 case 1:
534 layer = 3;
535 break;
536 case 2:
537 layer = 2;
538 break;
539 case 3:
540 layer = 1;
541 break;
542 default:
543 goto restart;
546 /* Bitrate */
547 bitindex = (header & 0xF000) >> 12;
548 bitrate = bitrate_table[bittable-1][layer-1][bitindex];
549 if(bitrate == 0)
550 goto restart;
552 /* Sampling frequency */
553 freqindex = (header & 0x0C00) >> 10;
554 frequency = freqtab[version][freqindex];
555 if(frequency == 0)
556 goto restart;
558 #ifdef DEBUG_VERBOSE
559 DEBUGF( "Version %i, lay %i, biti %i, bitr %i, freqi %i, freq %i, chmode %d\n",
560 version, layer, bitindex, bitrate, freqindex, frequency, chmode);
561 #endif
562 entry->version = version;
563 entry->layer = layer;
564 entry->frequency = frequency;
566 /* Calculate bytes per frame, calculation depends on layer */
567 switch(layer) {
568 case 1:
569 bpf = bitrate_table[bittable - 1][layer - 1][bitindex];
570 bpf *= 48000;
571 bpf /= freqtab[version][freqindex] << (bittable - 1);
572 break;
573 case 2:
574 case 3:
575 bpf = bitrate_table[bittable - 1][layer - 1][bitindex];
576 bpf *= 144000;
577 bpf /= freqtab[version][freqindex] << (bittable - 1);
578 break;
579 default:
580 bpf = 1;
583 /* Calculate time per frame */
584 tpf = bs[layer] / (freqtab[version][freqindex] << (bittable - 1));
586 entry->bpf = bpf;
587 entry->tpf = tpf;
589 /* OK, we have found a frame. Let's see if it has a Xing header */
590 if(read(fd, frame, sizeof frame) < 0)
591 return -1;
593 /* Channel mode (stereo/mono) */
594 chmode = (header & 0xc0) >> 6;
596 /* calculate position of Xing VBR header */
597 if ( version == 1 ) {
598 if ( chmode == 3 ) /* mono */
599 xing = frame + 17;
600 else
601 xing = frame + 32;
603 else {
604 if ( chmode == 3 ) /* mono */
605 xing = frame + 9;
606 else
607 xing = frame + 17;
610 if (xing[0] == 'X' &&
611 xing[1] == 'i' &&
612 xing[2] == 'n' &&
613 xing[3] == 'g')
615 int i = 8; /* Where to start parsing info */
617 /* Yes, it is a VBR file */
618 entry->vbr = true;
619 entry->vbrflags = xing[7];
621 if (entry->vbrflags & VBR_FRAMES_FLAG) /* Is the frame count there? */
623 int framecount = (xing[i] << 24) | (xing[i+1] << 16) |
624 (xing[i+2] << 8) | xing[i+3];
626 filetime = framecount * tpf;
627 i += 4;
630 if (entry->vbrflags & VBR_BYTES_FLAG) /* is byte count there? */
632 int bytecount = (xing[i] << 24) | (xing[i+1] << 16) |
633 (xing[i+2] << 8) | xing[i+3];
635 bitrate = bytecount * 8 / filetime;
636 i += 4;
639 if (entry->vbrflags & VBR_TOC_FLAG) /* is table-of-contents there? */
641 memcpy( entry->toc, xing+i, 100 );
644 /* Make sure we skip this frame in playback */
645 bytecount += bpf;
647 header_found = true;
650 if (xing[0] == 'V' &&
651 xing[1] == 'B' &&
652 xing[2] == 'R' &&
653 xing[3] == 'I')
655 int framecount;
656 int bytecount;
658 /* Yes, it is a FhG VBR file */
659 entry->vbr = true;
660 entry->vbrflags = 0;
662 bytecount = (xing[10] << 24) | (xing[11] << 16) |
663 (xing[12] << 8) | xing[13];
665 framecount = (xing[14] << 24) | (xing[15] << 16) |
666 (xing[16] << 8) | xing[17];
668 filetime = framecount * tpf;
669 bitrate = bytecount * 8 / filetime;
671 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
673 /* Make sure we skip this frame in playback */
674 bytecount += bpf;
676 header_found = true;
679 /* Is it a LAME Info frame? */
680 if (xing[0] == 'I' &&
681 xing[1] == 'n' &&
682 xing[2] == 'f' &&
683 xing[3] == 'o')
685 /* Make sure we skip this frame in playback */
686 bytecount += bpf;
688 header_found = true;
692 entry->bitrate = bitrate;
694 /* If the file time hasn't been established, this may be a fixed
695 rate MP3, so just use the default formula */
696 if(filetime == 0)
699 * Now song length is
700 * ((filesize)/(bytes per frame))*(time per frame)
702 filetime = entry->filesize/bpf*tpf;
705 /* Update the seek point for the first playable frame */
706 entry->first_frame_offset = bytecount;
707 DEBUGF("First frame is at %x\n", entry->first_frame_offset);
709 return filetime;
714 * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc)
715 * about an MP3 file and updates it's entry accordingly.
717 * Arguments: entry - the entry to check and update with the new information
719 * Returns: void
721 bool mp3info(struct mp3entry *entry, char *filename)
723 int fd;
724 fd = open(filename, O_RDONLY);
725 if(-1 == fd)
726 return true;
728 memset(entry, 0, sizeof(struct mp3entry));
730 strncpy(entry->path, filename, sizeof(entry->path));
732 entry->title = NULL;
733 entry->filesize = getfilesize(fd);
734 entry->id3v2len = getid3v2len(fd);
735 entry->tracknum = 0;
737 if (entry->id3v2len)
738 setid3v2title(fd, entry);
739 entry->length = getsonglength(fd, entry);
741 entry->id3v1len = getid3v1len(fd);
742 if(entry->id3v1len && !entry->title)
743 setid3v1title(fd, entry);
745 close(fd);
747 if(!entry->length || (entry->filesize < 8 ))
748 /* no song length or less than 8 bytes is hereby considered to be an
749 invalid mp3 and won't be played by us! */
750 return true;
752 return false;
755 #ifdef DEBUG_STANDALONE
757 char *secs2str(int ms)
759 static char buffer[32];
760 int secs = ms/1000;
761 ms %= 1000;
762 snprintf(buffer, sizeof(buffer), "%d:%02d.%d", secs/60, secs%60, ms/100);
763 return buffer;
766 int main(int argc, char **argv)
768 int i;
769 for(i=1; i<argc; i++) {
770 struct mp3entry mp3;
771 if(mp3info(&mp3, argv[i])) {
772 printf("Failed to get %s\n", argv[i]);
773 return 0;
776 printf("****** File: %s\n"
777 " Title: %s\n"
778 " Artist: %s\n"
779 " Album: %s\n"
780 " Length: %s / %d s\n"
781 " Bitrate: %d\n"
782 " Frequency: %d\n",
783 argv[i],
784 mp3.title?mp3.title:"<blank>",
785 mp3.artist?mp3.artist:"<blank>",
786 mp3.album?mp3.album:"<blank>",
787 secs2str(mp3.length),
788 mp3.length/1000,
789 mp3.bitrate,
790 mp3.frequency);
793 return 0;
796 #endif
798 /* -----------------------------------------------------------------
799 * local variables:
800 * eval: (load-file "rockbox-mode.el")
801 * end: