Add resume support for AC3 files.
[kugel-rb.git] / firmware / id3.c
blob35e05177691273e520683b8e335977c07238ad61
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 ****************************************************************************/
20 * Parts of this code has been stolen from the Ample project and was written
21 * by David Härdeman. It has since been extended and enhanced pretty much by
22 * all sorts of friendly Rockbox people.
26 /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <stdbool.h>
34 #include <stddef.h>
35 #include <ctype.h>
36 #include "config.h"
37 #include "file.h"
38 #include "debug.h"
39 #include "atoi.h"
41 #include "id3.h"
42 #include "mp3data.h"
43 #include "system.h"
44 #include "replaygain.h"
45 #include "rbunicode.h"
47 #define UNSYNC(b0,b1,b2,b3) (((long)(b0 & 0x7F) << (3*7)) | \
48 ((long)(b1 & 0x7F) << (2*7)) | \
49 ((long)(b2 & 0x7F) << (1*7)) | \
50 ((long)(b3 & 0x7F) << (0*7)))
52 #define BYTES2INT(b0,b1,b2,b3) (((long)(b0 & 0xFF) << (3*8)) | \
53 ((long)(b1 & 0xFF) << (2*8)) | \
54 ((long)(b2 & 0xFF) << (1*8)) | \
55 ((long)(b3 & 0xFF) << (0*8)))
57 static const char* const genres[] = {
58 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
59 "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
60 "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
61 "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
62 "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
63 "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock",
64 "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
65 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
66 "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
67 "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
68 "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
69 "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
70 "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
72 /* winamp extensions */
73 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob",
74 "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
75 "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
76 "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
77 "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
78 "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
79 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
80 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
81 "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
82 "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap",
83 "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
84 "Christian Rock", "Merengue", "Salsa", "Trash Metal", "Anime", "Jpop",
85 "Synthpop"
88 static const char* const codec_labels[] = {
89 "???", /* Unknown file format */
91 "MP1", /* MPEG Audio layer 1 */
92 "MP2", /* MPEG Audio layer 2 */
93 "MP3", /* MPEG Audio layer 3 */
95 #if CONFIG_CODEC == SWCODEC
96 "WAV", /* Uncompressed PCM in a WAV file */
97 "Ogg", /* Ogg Vorbis */
98 "FLAC", /* FLAC */
99 "MPC", /* Musepack */
100 "AC3", /* A/52 (aka AC3) audio */
101 "WV", /* WavPack */
102 "ALAC", /* Apple Lossless Audio Codec */
103 "AAC", /* Advanced Audio Coding in M4A container */
104 "SHN", /* Shorten */
105 "AIFF", /* Audio Interchange File Format */
106 "SID", /* SID File Format */
107 #endif
110 char* id3_get_genre(const struct mp3entry* id3)
112 if( id3->genre_string )
113 return id3->genre_string ;
115 if (id3->genre < sizeof(genres)/sizeof(char*))
116 return (char*)genres[id3->genre];
117 return NULL;
120 char* id3_get_codec(const struct mp3entry* id3)
122 if (id3->codectype < sizeof(codec_labels)/sizeof(char*)) {
123 return (char*)codec_labels[id3->codectype];
124 } else {
125 return NULL;
130 HOW TO ADD ADDITIONAL ID3 VERSION 2 TAGS
131 Code and comments by Thomas Paul Diffenbach
133 To add another ID3v2 Tag, do the following:
134 1. add a char* named for the tag to struct mp3entry in id3.h,
135 (I (tpd) prefer to use char* rather than ints, even for what seems like
136 numerical values, for cases where a number won't do, e.g.,
137 YEAR: "circa 1765", "1790/1977" (composed/performed), "28 Feb 1969"
138 TRACK: "1/12", "1 of 12", GENRE: "Freeform genre name"
139 Text is more flexible, and as the main use of id3 data is to
140 display it, converting it to an int just means reconverting to
141 display it, at a runtime cost.)
143 2. If any special processing beyond copying the tag value from the Id3
144 block to the struct mp3entry is rrequired (such as converting to an
145 int), write a function to perform this special processing.
147 This function's prototype must match that of
148 typedef tagPostProcessFunc, that is it must be:
149 int func( struct mp3entry*, char* tag, int bufferpos )
150 the first argument is a pointer to the current mp3entry structure the
151 second argument is a pointer to the null terminated string value of the
152 tag found the third argument is the offset of the next free byte in the
153 mp3entry's buffer your function should return the corrected offset; if
154 you don't lengthen or shorten the tag string, you can return the third
155 argument unchanged.
157 Unless you have a good reason no to, make the function static.
158 TO JUST COPY THE TAG NO SPECIAL PROCESSING FUNCTION IS NEEDED.
160 3. add one or more entries to the tagList array, using the format:
161 char* ID3 Tag symbolic name -- see the ID3 specification for these,
162 sizeof() that name minus 1,
163 offsetof( struct mp3entry, variable_name_in_struct_mp3entry ),
164 pointer to your special processing function or NULL
165 if you need no special processing
166 flag indicating if this tag is binary or textual
167 Many ID3 symbolic names come in more than one form. You can add both
168 forms, each referencing the same variable in struct mp3entry.
169 If both forms are present, the last found will be used.
170 Note that the offset can be zero, in which case no entry will be set
171 in the mp3entry struct; the frame is still read into the buffer and
172 the special processing function is called (several times, if there
173 are several frames with the same name).
175 4. Alternately, use the TAG_LIST_ENTRY macro with
176 ID3 tag symbolic name,
177 variable in struct mp3entry,
178 special processing function address
180 5. Add code to wps-display.c function get_tag to assign a printf-like
181 format specifier for the tag */
183 /* Structure for ID3 Tag extraction information */
184 struct tag_resolver {
185 const char* tag;
186 int tag_length;
187 size_t offset;
188 int (*ppFunc)(struct mp3entry*, char* tag, int bufferpos);
189 bool binary;
192 static bool global_ff_found;
194 static int unsynchronize(char* tag, int len, bool *ff_found)
196 int i;
197 unsigned char c;
198 unsigned char *rp, *wp;
200 wp = rp = (unsigned char *)tag;
202 rp = (unsigned char *)tag;
203 for(i = 0;i < len;i++) {
204 /* Read the next byte and write it back, but don't increment the
205 write pointer */
206 c = *rp++;
207 *wp = c;
208 if(*ff_found) {
209 /* Increment the write pointer if it isn't an unsynch pattern */
210 if(c != 0)
211 wp++;
212 *ff_found = false;
213 } else {
214 if(c == 0xff)
215 *ff_found = true;
216 wp++;
219 return (long)wp - (long)tag;
222 static int unsynchronize_frame(char* tag, int len)
224 bool ff_found = false;
226 return unsynchronize(tag, len, &ff_found);
229 static int read_unsynched(int fd, void *buf, int len)
231 int i;
232 int rc;
233 int remaining = len;
234 char *wp;
235 char *rp;
237 wp = buf;
239 while(remaining) {
240 rp = wp;
241 rc = read(fd, rp, remaining);
242 if(rc < 0)
243 return rc;
245 i = unsynchronize(wp, remaining, &global_ff_found);
246 remaining -= i;
247 wp += i;
250 return len;
253 static int skip_unsynched(int fd, int len)
255 int rc;
256 int remaining = len;
257 int rlen;
258 char buf[32];
260 while(remaining) {
261 rlen = MIN(sizeof(buf), (unsigned int)remaining);
262 rc = read(fd, buf, rlen);
263 if(rc < 0)
264 return rc;
266 remaining -= unsynchronize(buf, rlen, &global_ff_found);
269 return len;
272 /* parse numeric value from string */
273 static int parsetracknum( struct mp3entry* entry, char* tag, int bufferpos )
275 entry->tracknum = atoi( tag );
276 return bufferpos;
279 /* parse numeric value from string */
280 static int parseyearnum( struct mp3entry* entry, char* tag, int bufferpos )
282 entry->year = atoi( tag );
283 return bufferpos;
286 /* parse numeric genre from string, version 2.2 and 2.3 */
287 static int parsegenre( struct mp3entry* entry, char* tag, int bufferpos )
289 if(entry->id3version >= ID3_VER_2_4) {
290 /* In version 2.4 and up, there are no parentheses, and the genre frame
291 is a list of strings, either numbers or text. */
293 /* Is it a number? */
294 if(isdigit(tag[0])) {
295 entry->genre = atoi( tag );
296 entry->genre_string = 0;
297 return tag - entry->id3v2buf;
298 } else {
299 entry->genre_string = tag;
300 entry->genre = 0xff;
301 return bufferpos;
303 } else {
304 if( tag[0] == '(' && tag[1] != '(' ) {
305 entry->genre = atoi( tag + 1 );
306 entry->genre_string = 0;
307 return tag - entry->id3v2buf;
309 else {
310 entry->genre_string = tag;
311 entry->genre = 0xff;
312 return bufferpos;
317 #if CONFIG_CODEC == SWCODEC
318 /* parse user defined text, looking for replaygain information. */
319 static int parseuser( struct mp3entry* entry, char* tag, int bufferpos )
321 char* value = NULL;
322 int desc_len = strlen(tag);
323 int value_len = 0;
325 /* Note: for ID3v2.4, parse_replaygain will not overwrite replaygain
326 values already parsed from RVA2 tags */
327 if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos) {
328 /* At least part of the value was read, so we can safely try to
329 * parse it
331 value = tag + desc_len + 1;
332 value_len = parse_replaygain(tag, value, entry, tag,
333 bufferpos - (tag - entry->id3v2buf));
336 if (value_len) {
337 bufferpos = tag - entry->id3v2buf + value_len;
338 } else {
339 bufferpos = tag - entry->id3v2buf;
342 return bufferpos;
345 /* parse RVA2 binary data and convert to replaygain information. */
346 static int parserva2( struct mp3entry* entry, char* tag, int bufferpos )
348 char* value = NULL;
349 int desc_len = strlen(tag);
350 int value_len = 0;
352 /* Only parse RVA2 replaygain tags if tag version == 2.4 */
353 if (entry->id3version == ID3_VER_2_4 &&
354 (tag - entry->id3v2buf + desc_len + 2) < bufferpos) {
355 value = tag + desc_len + 1;
356 value_len = parse_replaygain_rva(tag, value, entry, tag,
357 bufferpos - (tag - entry->id3v2buf));
360 if (value_len) {
361 bufferpos = tag - entry->id3v2buf + value_len;
362 } else {
363 bufferpos = tag - entry->id3v2buf;
366 return bufferpos;
368 #endif
370 static const struct tag_resolver taglist[] = {
371 { "TPE1", 4, offsetof(struct mp3entry, artist), NULL, false },
372 { "TP1", 3, offsetof(struct mp3entry, artist), NULL, false },
373 { "TIT2", 4, offsetof(struct mp3entry, title), NULL, false },
374 { "TT2", 3, offsetof(struct mp3entry, title), NULL, false },
375 { "TALB", 4, offsetof(struct mp3entry, album), NULL, false },
376 { "TAL", 3, offsetof(struct mp3entry, album), NULL, false },
377 { "TRK", 3, offsetof(struct mp3entry, track_string), &parsetracknum, false },
378 { "TRCK", 4, offsetof(struct mp3entry, track_string), &parsetracknum, false },
379 { "TDRC", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false },
380 { "TYER", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false },
381 { "TYE", 3, offsetof(struct mp3entry, year_string), &parseyearnum, false },
382 { "TCOM", 4, offsetof(struct mp3entry, composer), NULL, false },
383 { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre, false },
384 { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre, false },
385 #if CONFIG_CODEC == SWCODEC
386 { "TXXX", 4, 0, &parseuser, false },
387 { "RVA2", 4, 0, &parserva2, true },
388 #endif
391 #define TAGLIST_SIZE ((int)(sizeof(taglist) / sizeof(taglist[0])))
393 /* Checks to see if the passed in string is a 16-bit wide Unicode v2
394 string. If it is, we convert it to a UTF-8 string. If it's not unicode,
395 we convert from the default codepage */
396 static int unicode_munge(char* string, char* utf8buf, int *len) {
397 long tmp;
398 bool le = false;
399 int i = 0;
400 char *str = string;
401 int templen = 0;
402 char* utf8 = utf8buf;
404 switch (str[0]) {
405 case 0x00: /* Type 0x00 is ordinary ISO 8859-1 */
406 str++;
407 (*len)--;
408 utf8 = iso_decode(str, utf8, -1, *len);
409 *utf8 = 0;
410 *len = utf8 - utf8buf;
411 break;
413 case 0x01: /* Unicode with or without BOM */
414 case 0x02:
415 (*len)--;
416 str++;
418 /* Handle frames with more than one string
419 (needed for TXXX frames).*/
420 do {
421 tmp = BYTES2INT(0, 0, str[0], str[1]);
423 /* Now check if there is a BOM
424 (zero-width non-breaking space, 0xfeff)
425 and if it is in little or big endian format */
426 if(tmp == 0xfffe) { /* Little endian? */
427 le = true;
428 str += 2;
429 (*len)-=2;
430 } else if(tmp == 0xfeff) { /* Big endian? */
431 str += 2;
432 (*len)-=2;
433 } else
434 /* If there is no BOM (which is a specification violation),
435 let's try to guess it. If one of the bytes is 0x00, it is
436 probably the most significant one. */
437 if(str[1] == 0)
438 le = true;
440 do {
441 if(le)
442 utf8 = utf16LEdecode(str, utf8, 1);
443 else
444 utf8 = utf16BEdecode(str, utf8, 1);
446 str+=2;
447 i += 2;
448 } while((str[0] || str[1]) && (i < *len));
450 *utf8++ = 0; /* Terminate the string */
451 templen += (strlen(&utf8buf[templen]) + 1);
452 str += 2;
453 i+=2;
454 } while(i < *len);
455 *len = templen - 1;
456 break;
458 case 0x03: /* UTF-8 encoded string */
459 for(i=0; i < *len; i++)
460 utf8[i] = str[i+1];
461 (*len)--;
462 break;
464 default: /* Plain old string */
465 utf8 = iso_decode(str, utf8, -1, *len);
466 *utf8 = 0;
467 *len = utf8 - utf8buf;
468 break;
470 return 0;
474 * Sets the title of an MP3 entry based on its ID3v1 tag.
476 * Arguments: file - the MP3 file to scen for a ID3v1 tag
477 * entry - the entry to set the title in
479 * Returns: true if a title was found and created, else false
481 static bool setid3v1title(int fd, struct mp3entry *entry)
483 unsigned char buffer[128];
484 static const char offsets[] = {3, 33, 63, 93, 125, 127};
485 int i, j;
486 unsigned char* utf8;
488 if (-1 == lseek(fd, -128, SEEK_END))
489 return false;
491 if (read(fd, buffer, sizeof buffer) != sizeof buffer)
492 return false;
494 if (strncmp((char *)buffer, "TAG", 3))
495 return false;
497 entry->id3v1len = 128;
498 entry->id3version = ID3_VER_1_0;
500 for (i=0; i < (int)sizeof offsets; i++) {
501 unsigned char* ptr = (unsigned char *)buffer + offsets[i];
503 if (i<3) {
504 /* kill trailing space in strings */
505 for (j=29; j && ptr[j]==' '; j--)
506 ptr[j] = 0;
509 switch(i) {
510 case 0:
511 case 1:
512 case 2:
513 /* convert string to utf8 */
514 utf8 = entry->id3v1buf[i];
515 utf8 = iso_decode(ptr, utf8, -1, 30);
516 /* make sure string is terminated */
517 *utf8 = 0;
518 break;
520 case 3:
521 ptr[4] = 0;
522 entry->year = atoi(ptr);
523 break;
525 case 4:
526 /* id3v1.1 uses last two bytes of comment field for track
527 number: first must be 0 and second is track num */
528 if (!ptr[0] && ptr[1]) {
529 entry->tracknum = ptr[1];
530 entry->id3version = ID3_VER_1_1;
532 break;
534 case 5:
535 /* genre */
536 entry->genre = ptr[0];
537 break;
541 entry->title = entry->id3v1buf[0];
542 entry->artist = entry->id3v1buf[1];
543 entry->album = entry->id3v1buf[2];
545 return true;
550 * Sets the title of an MP3 entry based on its ID3v2 tag.
552 * Arguments: file - the MP3 file to scan for a ID3v2 tag
553 * entry - the entry to set the title in
555 * Returns: true if a title was found and created, else false
557 static void setid3v2title(int fd, struct mp3entry *entry)
559 int minframesize;
560 int size;
561 long bufferpos = 0, totframelen, framelen;
562 char header[10];
563 char tmp[4];
564 unsigned char version;
565 char *buffer = entry->id3v2buf;
566 int bytesread = 0;
567 int buffersize = sizeof(entry->id3v2buf);
568 unsigned char global_flags;
569 int flags;
570 int skip;
571 bool global_unsynch = false;
572 bool unsynch = false;
573 int data_length_ind;
574 int i, j;
575 int rc;
577 global_ff_found = false;
579 /* Bail out if the tag is shorter than 10 bytes */
580 if(entry->id3v2len < 10)
581 return;
583 /* Read the ID3 tag version from the header */
584 lseek(fd, 0, SEEK_SET);
585 if(10 != read(fd, header, 10))
586 return;
588 /* Get the total ID3 tag size */
589 size = entry->id3v2len - 10;
591 version = header[3];
592 switch ( version ) {
593 case 2:
594 version = ID3_VER_2_2;
595 minframesize = 8;
596 break;
598 case 3:
599 version = ID3_VER_2_3;
600 minframesize = 12;
601 break;
603 case 4:
604 version = ID3_VER_2_4;
605 minframesize = 12;
606 break;
608 default:
609 /* unsupported id3 version */
610 return;
612 entry->id3version = version;
613 entry->tracknum = entry->year = 0;
614 entry->genre = 0xff;
615 entry->title = entry->artist = entry->album = NULL;
617 global_flags = header[5];
619 /* Skip the extended header if it is present */
620 if(global_flags & 0x40) {
621 if(version == ID3_VER_2_3) {
622 if(10 != read(fd, header, 10))
623 return;
624 /* The 2.3 extended header size doesn't include the following
625 data, so we have to find out the size by checking the flags.
626 Also, it is not unsynched. */
627 framelen = BYTES2INT(header[0], header[1], header[2], header[3]) +
628 BYTES2INT(header[6], header[7], header[8], header[9]);
629 flags = BYTES2INT(0, 0, header[4], header[5]);
630 if(flags & 0x8000)
631 framelen += 4; /* CRC */
633 lseek(fd, framelen - 10, SEEK_CUR);
636 if(version >= ID3_VER_2_4) {
637 if(4 != read(fd, header, 4))
638 return;
640 /* The 2.4 extended header size does include the entire header,
641 so here we can just skip it. This header is unsynched. */
642 framelen = UNSYNC(header[0], header[1],
643 header[2], header[3]);
645 lseek(fd, framelen - 4, SEEK_CUR);
649 /* Is unsynchronization applied? */
650 if(global_flags & 0x80) {
651 global_unsynch = true;
655 * We must have at least minframesize bytes left for the
656 * remaining frames to be interesting
658 while (size >= minframesize && bufferpos < buffersize - 1) {
659 flags = 0;
661 /* Read frame header and check length */
662 if(version >= ID3_VER_2_3) {
663 if(global_unsynch && version <= ID3_VER_2_3)
664 rc = read_unsynched(fd, header, 10);
665 else
666 rc = read(fd, header, 10);
667 if(rc != 10)
668 return;
669 /* Adjust for the 10 bytes we read */
670 size -= 10;
672 flags = BYTES2INT(0, 0, header[8], header[9]);
674 if (version >= ID3_VER_2_4) {
675 framelen = UNSYNC(header[4], header[5],
676 header[6], header[7]);
677 } else {
678 /* version .3 files don't use synchsafe ints for
679 * size */
680 framelen = BYTES2INT(header[4], header[5],
681 header[6], header[7]);
683 } else {
684 if(6 != read(fd, header, 6))
685 return;
686 /* Adjust for the 6 bytes we read */
687 size -= 6;
689 framelen = BYTES2INT(0, header[3], header[4], header[5]);
692 /* Keep track of the total size */
693 totframelen = framelen;
695 DEBUGF("framelen = %d\n", framelen);
696 if(framelen == 0){
697 if (header[0] == 0 && header[1] == 0 && header[2] == 0)
698 return;
699 else
700 continue;
703 unsynch = false;
704 data_length_ind = 0;
706 if(flags)
708 skip = 0;
710 if (version >= ID3_VER_2_4) {
711 if(flags & 0x0040) { /* Grouping identity */
712 lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */
713 framelen--;
715 } else {
716 if(flags & 0x0020) { /* Grouping identity */
717 lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */
718 framelen--;
722 if(flags & 0x000c) /* Compression or encryption */
724 /* Skip it using the total size in case
725 it was truncated */
726 size -= totframelen;
727 lseek(fd, totframelen, SEEK_CUR);
728 continue;
731 if(flags & 0x0002) /* Unsynchronization */
732 unsynch = true;
734 if (version >= ID3_VER_2_4) {
735 if(flags & 0x0001) { /* Data length indicator */
736 if(4 != read(fd, tmp, 4))
737 return;
739 data_length_ind = UNSYNC(tmp[0], tmp[1], tmp[2], tmp[3]);
740 framelen -= 4;
745 /* If the frame is larger than the remaining buffer space we try
746 to read as much as would fit in the buffer */
747 if(framelen >= buffersize - bufferpos)
748 framelen = buffersize - bufferpos - 1;
750 DEBUGF("id3v2 frame: %.4s\n", header);
752 /* Check for certain frame headers
754 'size' is the amount of frame bytes remaining. We decrement it by
755 the amount of bytes we read. If we fail to read as many bytes as
756 we expect, we assume that we can't read from this file, and bail
757 out.
759 For each frame. we will iterate over the list of supported tags,
760 and read the tag into entry's buffer. All tags will be kept as
761 strings, for cases where a number won't do, e.g., YEAR: "circa
762 1765", "1790/1977" (composed/performed), "28 Feb 1969" TRACK:
763 "1/12", "1 of 12", GENRE: "Freeform genre name" Text is more
764 flexible, and as the main use of id3 data is to display it,
765 converting it to an int just means reconverting to display it, at a
766 runtime cost.
768 For tags that the current code does convert to ints, a post
769 processing function will be called via a pointer to function. */
771 for (i=0; i<TAGLIST_SIZE; i++) {
772 const struct tag_resolver* tr = &taglist[i];
773 char** ptag = tr->offset ? (char**) (((char*)entry) + tr->offset)
774 : NULL;
775 char* tag;
777 /* Only ID3_VER_2_2 uses frames with three-character names. */
778 if (((version == ID3_VER_2_2) && (tr->tag_length != 3))
779 || ((version > ID3_VER_2_2) && (tr->tag_length != 4))) {
780 continue;
783 /* Note that parser functions sometimes set *ptag to NULL, so
784 * the "!*ptag" check here doesn't always have the desired
785 * effect. Should the parser functions (parsegenre in
786 * particular) be updated to handle the case of being called
787 * multiple times, or should the "*ptag" check be removed?
789 if( (!ptag || !*ptag) && !memcmp( header, tr->tag, tr->tag_length ) ) {
791 /* found a tag matching one in tagList, and not yet filled */
792 tag = buffer + bufferpos;
794 if(global_unsynch && version <= ID3_VER_2_3)
795 bytesread = read_unsynched(fd, tag, framelen);
796 else
797 bytesread = read(fd, tag, framelen);
799 if( bytesread != framelen )
800 return;
802 size -= bytesread;
804 if(unsynch || (global_unsynch && version >= ID3_VER_2_4))
805 bytesread = unsynchronize_frame(tag, bytesread);
807 /* Attempt to parse Unicode string only if the tag contents
808 aren't binary */
809 if(!tr->binary) {
810 /* UTF-8 could potentially be 3 times larger */
811 /* so we need to create a new buffer */
812 char utf8buf[(3 * bytesread) + 1];
814 unicode_munge( tag, utf8buf, &bytesread );
816 if(bytesread >= buffersize - bufferpos)
817 bytesread = buffersize - bufferpos - 1;
819 for (j = 0; j < bytesread; j++)
820 tag[j] = utf8buf[j];
822 /* remove trailing spaces */
823 while ( bytesread > 0 && isspace(tag[bytesread-1]))
824 bytesread--;
827 tag[bytesread] = 0;
828 bufferpos += bytesread + 1;
830 if (ptag)
831 *ptag = tag;
833 if( tr->ppFunc )
834 bufferpos = tr->ppFunc(entry, tag, bufferpos);
836 /* Seek to the next frame */
837 if(framelen < totframelen)
838 lseek(fd, totframelen - framelen, SEEK_CUR);
839 break;
843 if( i == TAGLIST_SIZE ) {
844 /* no tag in tagList was found, or it was a repeat.
845 skip it using the total size */
847 if(global_unsynch && version <= ID3_VER_2_3) {
848 size -= skip_unsynched(fd, totframelen);
849 } else {
850 if(data_length_ind)
851 totframelen = data_length_ind;
853 size -= totframelen;
854 if( lseek(fd, totframelen, SEEK_CUR) == -1 )
855 return;
862 * Calculates the size of the ID3v2 tag.
864 * Arguments: file - the file to search for a tag.
866 * Returns: the size of the tag or 0 if none was found
868 int getid3v2len(int fd)
870 char buf[6];
871 int offset;
873 /* Make sure file has a ID3 tag */
874 if((-1 == lseek(fd, 0, SEEK_SET)) ||
875 (read(fd, buf, 6) != 6) ||
876 (strncmp(buf, "ID3", strlen("ID3")) != 0))
877 offset = 0;
879 /* Now check what the ID3v2 size field says */
880 else
881 if(read(fd, buf, 4) != 4)
882 offset = 0;
883 else
884 offset = UNSYNC(buf[0], buf[1], buf[2], buf[3]) + 10;
886 DEBUGF("ID3V2 Length: 0x%x\n", offset);
887 return offset;
891 * Calculates the length (in milliseconds) of an MP3 file.
893 * Modified to only use integers.
895 * Arguments: file - the file to calculate the length upon
896 * entry - the entry to update with the length
898 * Returns: the song length in milliseconds,
899 * 0 means that it couldn't be calculated
901 static int getsonglength(int fd, struct mp3entry *entry)
903 unsigned long filetime = 0;
904 struct mp3info info;
905 long bytecount;
907 /* Start searching after ID3v2 header */
908 if(-1 == lseek(fd, entry->id3v2len, SEEK_SET))
909 return 0;
911 bytecount = get_mp3file_info(fd, &info);
913 DEBUGF("Space between ID3V2 tag and first audio frame: 0x%x bytes\n",
914 bytecount);
916 if(bytecount < 0)
917 return -1;
919 bytecount += entry->id3v2len;
921 /* Validate byte count, in case the file has been edited without
922 * updating the header.
924 if (info.byte_count)
926 const unsigned long expected = entry->filesize - entry->id3v1len
927 - entry->id3v2len;
928 const unsigned long diff = MAX(10240, info.byte_count / 20);
930 if ((info.byte_count > expected + diff)
931 || (info.byte_count < expected - diff))
933 DEBUGF("Note: info.byte_count differs from expected value by "
934 "%d bytes\n", labs((long) (expected - info.byte_count)));
935 info.byte_count = 0;
936 info.frame_count = 0;
937 info.file_time = 0;
938 info.enc_padding = 0;
940 /* Even if the bitrate was based on "known bad" values, it
941 * should still be better for VBR files than using the bitrate
942 * of the first audio frame.
947 entry->bitrate = info.bitrate;
948 entry->frequency = info.frequency;
949 entry->version = info.version;
950 entry->layer = info.layer;
951 switch(entry->layer) {
952 #if CONFIG_CODEC==SWCODEC
953 case 0:
954 entry->codectype=AFMT_MPA_L1;
955 break;
956 #endif
957 case 1:
958 entry->codectype=AFMT_MPA_L2;
959 break;
960 case 2:
961 entry->codectype=AFMT_MPA_L3;
962 break;
965 /* If the file time hasn't been established, this may be a fixed
966 rate MP3, so just use the default formula */
968 filetime = info.file_time;
970 if(filetime == 0)
972 filetime = (entry->filesize - bytecount) / (info.bitrate / 8);
973 /* bitrate is in kbps so this delivers milliseconds. Doing bitrate / 8
974 * instead of filesize * 8 is exact, because mpeg audio bitrates are
975 * always multiples of 8, and it avoids overflows. */
978 entry->frame_count = info.frame_count;
980 entry->vbr = info.is_vbr;
981 entry->has_toc = info.has_toc;
983 entry->lead_trim = info.enc_delay;
984 entry->tail_trim = info.enc_padding;
986 memcpy(entry->toc, info.toc, sizeof(info.toc));
988 entry->vbr_header_pos = info.vbr_header_pos;
990 /* Update the seek point for the first playable frame */
991 entry->first_frame_offset = bytecount;
992 DEBUGF("First frame is at %x\n", entry->first_frame_offset);
994 return filetime;
998 * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc)
999 * about an MP3 file and updates it's entry accordingly.
1002 bool mp3info(struct mp3entry *entry, const char *filename, bool v1first)
1004 int fd;
1005 int v1found = false;
1007 fd = open(filename, O_RDONLY);
1008 if(-1 == fd)
1009 return true;
1011 #if CONFIG_CODEC != SWCODEC
1012 memset(entry, 0, sizeof(struct mp3entry));
1013 #endif
1015 strncpy(entry->path, filename, sizeof(entry->path));
1017 entry->title = NULL;
1018 entry->filesize = filesize(fd);
1019 entry->id3v2len = getid3v2len(fd);
1020 entry->tracknum = 0;
1021 entry->genre = 0xff;
1023 if(v1first)
1024 v1found = setid3v1title(fd, entry);
1026 if (!v1found && entry->id3v2len)
1027 setid3v2title(fd, entry);
1028 entry->length = getsonglength(fd, entry);
1030 /* Subtract the meta information from the file size to get
1031 the true size of the MP3 stream */
1032 entry->filesize -= entry->first_frame_offset;
1034 /* only seek to end of file if no id3v2 tags were found,
1035 and we already haven't looked for a v1 tag */
1036 if (!v1first && !entry->id3v2len) {
1037 setid3v1title(fd, entry);
1040 close(fd);
1042 if(!entry->length || (entry->filesize < 8 ))
1043 /* no song length or less than 8 bytes is hereby considered to be an
1044 invalid mp3 and won't be played by us! */
1045 return true;
1047 return false;
1050 void adjust_mp3entry(struct mp3entry *entry, void *dest, void *orig)
1052 long offset;
1053 if (orig > dest)
1054 offset = - ((size_t)orig - (size_t)dest);
1055 else
1056 offset = (size_t)dest - (size_t)orig;
1058 if (entry->title)
1059 entry->title += offset;
1060 if (entry->artist)
1061 entry->artist += offset;
1062 if (entry->album)
1063 entry->album += offset;
1064 if (entry->genre_string)
1065 entry->genre_string += offset;
1066 if (entry->track_string)
1067 entry->track_string += offset;
1068 if (entry->year_string)
1069 entry->year_string += offset;
1070 if (entry->composer)
1071 entry->composer += offset;
1072 #if CONFIG_CODEC == SWCODEC
1073 if (entry->track_gain_string)
1074 entry->track_gain_string += offset;
1075 if (entry->album_gain_string)
1076 entry->album_gain_string += offset;
1077 #endif
1080 void copy_mp3entry(struct mp3entry *dest, struct mp3entry *orig)
1082 memcpy(dest, orig, sizeof(struct mp3entry));
1083 adjust_mp3entry(dest, dest, orig);
1086 #ifdef DEBUG_STANDALONE
1088 char *secs2str(int ms)
1090 static char buffer[32];
1091 int secs = ms/1000;
1092 ms %= 1000;
1093 snprintf(buffer, sizeof(buffer), "%d:%02d.%d", secs/60, secs%60, ms/100);
1094 return buffer;
1097 int main(int argc, char **argv)
1099 int i;
1100 for(i=1; i<argc; i++) {
1101 struct mp3entry mp3;
1102 mp3.album = "Bogus";
1103 if(mp3info(&mp3, argv[i], false)) {
1104 printf("Failed to get %s\n", argv[i]);
1105 return 0;
1108 printf("****** File: %s\n"
1109 " Title: %s\n"
1110 " Artist: %s\n"
1111 " Album: %s\n"
1112 " Genre: %s (%d) \n"
1113 " Composer: %s\n"
1114 " Year: %s (%d)\n"
1115 " Track: %s (%d)\n"
1116 " Length: %s / %d s\n"
1117 " Bitrate: %d\n"
1118 " Frequency: %d\n",
1119 argv[i],
1120 mp3.title?mp3.title:"<blank>",
1121 mp3.artist?mp3.artist:"<blank>",
1122 mp3.album?mp3.album:"<blank>",
1123 mp3.genre_string?mp3.genre_string:"<blank>",
1124 mp3.genre,
1125 mp3.composer?mp3.composer:"<blank>",
1126 mp3.year_string?mp3.year_string:"<blank>",
1127 mp3.year,
1128 mp3.track_string?mp3.track_string:"<blank>",
1129 mp3.tracknum,
1130 secs2str(mp3.length),
1131 mp3.length/1000,
1132 mp3.bitrate,
1133 mp3.frequency);
1136 return 0;
1139 #endif