1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Daniel Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 * Parts of this code has been stolen from the Ample project and was written
23 * by David H�deman. It has since been extended and enhanced pretty much by
24 * all sorts of friendly Rockbox people.
28 /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach
37 #include "string-extra.h"
44 #include "replaygain.h"
45 #include "rbunicode.h"
46 #include "metadata_parsers.h"
47 #if CONFIG_CODEC == SWCODEC
48 #include "metadata_common.h"
51 static unsigned long unsync(unsigned long b0
,
56 return (((long)(b0
& 0x7F) << (3*7)) |
57 ((long)(b1
& 0x7F) << (2*7)) |
58 ((long)(b2
& 0x7F) << (1*7)) |
59 ((long)(b3
& 0x7F) << (0*7)));
62 static const char* const genres
[] = {
63 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
64 "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
65 "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
66 "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
67 "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
68 "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock",
69 "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
70 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
71 "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
72 "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
73 "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
74 "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
75 "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
77 /* winamp extensions */
78 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob",
79 "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
80 "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
81 "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
82 "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
83 "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
84 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
85 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
86 "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
87 "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap",
88 "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
89 "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop",
93 char* id3_get_num_genre(unsigned int genre_num
)
95 if (genre_num
< ARRAYLEN(genres
))
96 return (char*)genres
[genre_num
];
101 HOW TO ADD ADDITIONAL ID3 VERSION 2 TAGS
102 Code and comments by Thomas Paul Diffenbach
104 To add another ID3v2 Tag, do the following:
105 1. add a char* named for the tag to struct mp3entry in id3.h,
106 (I (tpd) prefer to use char* rather than ints, even for what seems like
107 numerical values, for cases where a number won't do, e.g.,
108 YEAR: "circa 1765", "1790/1977" (composed/performed), "28 Feb 1969"
109 TRACK: "1/12", "1 of 12", GENRE: "Freeform genre name"
110 Text is more flexible, and as the main use of id3 data is to
111 display it, converting it to an int just means reconverting to
112 display it, at a runtime cost.)
114 2. If any special processing beyond copying the tag value from the Id3
115 block to the struct mp3entry is rrequired (such as converting to an
116 int), write a function to perform this special processing.
118 This function's prototype must match that of
119 typedef tagPostProcessFunc, that is it must be:
120 int func( struct mp3entry*, char* tag, int bufferpos )
121 the first argument is a pointer to the current mp3entry structure the
122 second argument is a pointer to the null terminated string value of the
123 tag found the third argument is the offset of the next free byte in the
124 mp3entry's buffer your function should return the corrected offset; if
125 you don't lengthen or shorten the tag string, you can return the third
128 Unless you have a good reason no to, make the function static.
129 TO JUST COPY THE TAG NO SPECIAL PROCESSING FUNCTION IS NEEDED.
131 3. add one or more entries to the tagList array, using the format:
132 char* ID3 Tag symbolic name -- see the ID3 specification for these,
133 sizeof() that name minus 1,
134 offsetof( struct mp3entry, variable_name_in_struct_mp3entry ),
135 pointer to your special processing function or NULL
136 if you need no special processing
137 flag indicating if this tag is binary or textual
138 Many ID3 symbolic names come in more than one form. You can add both
139 forms, each referencing the same variable in struct mp3entry.
140 If both forms are present, the last found will be used.
141 Note that the offset can be zero, in which case no entry will be set
142 in the mp3entry struct; the frame is still read into the buffer and
143 the special processing function is called (several times, if there
144 are several frames with the same name).
146 4. Alternately, use the TAG_LIST_ENTRY macro with
147 ID3 tag symbolic name,
148 variable in struct mp3entry,
149 special processing function address
151 5. Add code to wps-display.c function get_tag to assign a printf-like
152 format specifier for the tag */
154 /* Structure for ID3 Tag extraction information */
155 struct tag_resolver
{
159 int (*ppFunc
)(struct mp3entry
*, char* tag
, int bufferpos
);
163 static bool global_ff_found
;
165 static int unsynchronize(char* tag
, int len
, bool *ff_found
)
169 unsigned char *rp
, *wp
;
171 wp
= rp
= (unsigned char *)tag
;
173 rp
= (unsigned char *)tag
;
174 for(i
= 0;i
< len
;i
++) {
175 /* Read the next byte and write it back, but don't increment the
180 /* Increment the write pointer if it isn't an unsynch pattern */
190 return (long)wp
- (long)tag
;
193 static int unsynchronize_frame(char* tag
, int len
)
195 bool ff_found
= false;
197 return unsynchronize(tag
, len
, &ff_found
);
200 static int read_unsynched(int fd
, void *buf
, int len
)
212 rc
= read(fd
, rp
, remaining
);
216 i
= unsynchronize(wp
, remaining
, &global_ff_found
);
224 static int skip_unsynched(int fd
, int len
)
232 rlen
= MIN(sizeof(buf
), (unsigned int)remaining
);
233 rc
= read(fd
, buf
, rlen
);
237 remaining
-= unsynchronize(buf
, rlen
, &global_ff_found
);
243 /* parse numeric value from string */
244 static int parsetracknum( struct mp3entry
* entry
, char* tag
, int bufferpos
)
246 entry
->tracknum
= atoi( tag
);
250 /* parse numeric value from string */
251 static int parsediscnum( struct mp3entry
* entry
, char* tag
, int bufferpos
)
253 entry
->discnum
= atoi( tag
);
257 /* parse numeric value from string */
258 static int parseyearnum( struct mp3entry
* entry
, char* tag
, int bufferpos
)
260 entry
->year
= atoi( tag
);
264 /* parse numeric genre from string, version 2.2 and 2.3 */
265 static int parsegenre( struct mp3entry
* entry
, char* tag
, int bufferpos
)
267 if(entry
->id3version
>= ID3_VER_2_4
) {
268 /* In version 2.4 and up, there are no parentheses, and the genre frame
269 is a list of strings, either numbers or text. */
271 /* Is it a number? */
272 if(isdigit(tag
[0])) {
273 entry
->genre_string
= id3_get_num_genre(atoi( tag
));
274 return tag
- entry
->id3v2buf
;
276 entry
->genre_string
= tag
;
280 if( tag
[0] == '(' && tag
[1] != '(' ) {
281 entry
->genre_string
= id3_get_num_genre(atoi( tag
+ 1 ));
282 return tag
- entry
->id3v2buf
;
285 entry
->genre_string
= tag
;
291 /* parse user defined text, looking for album artist and replaygain
294 static int parseuser( struct mp3entry
* entry
, char* tag
, int bufferpos
)
297 int desc_len
= strlen(tag
);
300 if ((tag
- entry
->id3v2buf
+ desc_len
+ 2) < bufferpos
) {
301 /* At least part of the value was read, so we can safely try to
304 value
= tag
+ desc_len
+ 1;
305 value_len
= bufferpos
- (tag
- entry
->id3v2buf
);
307 if (!strcasecmp(tag
, "ALBUM ARTIST")) {
308 strlcpy(tag
, value
, value_len
);
309 entry
->albumartist
= tag
;
310 #if CONFIG_CODEC == SWCODEC
312 value_len
= parse_replaygain(tag
, value
, entry
, tag
,
318 return tag
- entry
->id3v2buf
+ value_len
;
321 #if CONFIG_CODEC == SWCODEC
322 /* parse RVA2 binary data and convert to replaygain information. */
323 static int parserva2( struct mp3entry
* entry
, char* tag
, int bufferpos
)
325 int desc_len
= strlen(tag
);
326 int start_pos
= tag
- entry
->id3v2buf
;
327 int end_pos
= start_pos
+ desc_len
+ 5;
329 unsigned char* value
= tag
+ desc_len
+ 1;
331 /* Only parse RVA2 replaygain tags if tag version == 2.4 and channel
332 * type is master volume.
334 if (entry
->id3version
== ID3_VER_2_4
&& end_pos
< bufferpos
342 /* The RVA2 specification is unclear on some things (id string and
343 * peak volume), but this matches how Quod Libet use them.
346 gain
= (int16_t) ((value
[0] << 8) | value
[1]);
349 peakbytes
= (peakbits
+ 7) / 8;
351 /* Only use the topmost 24 bits for peak volume */
356 /* Make sure the peak bits were read */
357 if (end_pos
+ peakbytes
< bufferpos
) {
358 long shift
= ((8 - (peakbits
& 7)) & 7) + (3 - peakbytes
) * 8;
360 for ( ; peakbytes
; peakbytes
--) {
368 peak
+= *value
>> (8 - shift
);
372 if (strcasecmp(tag
, "album") == 0) {
374 } else if (strcasecmp(tag
, "track") != 0) {
375 /* Only accept non-track values if we don't have any previous
378 if (entry
->track_gain
!= 0) {
383 value_len
= parse_replaygain_int(album
, gain
, peak
* 2, entry
,
384 tag
, sizeof(entry
->id3v2buf
) - start_pos
);
387 return start_pos
+ value_len
;
391 static int parsembtid( struct mp3entry
* entry
, char* tag
, int bufferpos
)
394 int desc_len
= strlen(tag
);
395 /*DEBUGF("MBID len: %d\n", desc_len);*/
396 /* Musicbrainz track IDs are always 36 chars long */
397 const size_t mbtid_len
= 36;
399 if ((tag
- entry
->id3v2buf
+ desc_len
+ 2) < bufferpos
)
401 value
= tag
+ desc_len
+ 1;
403 if (strcasecmp(tag
, "http://musicbrainz.org") == 0)
405 if (mbtid_len
== strlen(value
))
407 entry
->mb_track_id
= value
;
408 return bufferpos
+ mbtid_len
+ 1;
416 static const struct tag_resolver taglist
[] = {
417 { "TPE1", 4, offsetof(struct mp3entry
, artist
), NULL
, false },
418 { "TP1", 3, offsetof(struct mp3entry
, artist
), NULL
, false },
419 { "TIT2", 4, offsetof(struct mp3entry
, title
), NULL
, false },
420 { "TT2", 3, offsetof(struct mp3entry
, title
), NULL
, false },
421 { "TALB", 4, offsetof(struct mp3entry
, album
), NULL
, false },
422 { "TAL", 3, offsetof(struct mp3entry
, album
), NULL
, false },
423 { "TRK", 3, offsetof(struct mp3entry
, track_string
), &parsetracknum
, false },
424 { "TPOS", 4, offsetof(struct mp3entry
, disc_string
), &parsediscnum
, false },
425 { "TRCK", 4, offsetof(struct mp3entry
, track_string
), &parsetracknum
, false },
426 { "TDRC", 4, offsetof(struct mp3entry
, year_string
), &parseyearnum
, false },
427 { "TYER", 4, offsetof(struct mp3entry
, year_string
), &parseyearnum
, false },
428 { "TYE", 3, offsetof(struct mp3entry
, year_string
), &parseyearnum
, false },
429 { "TCOM", 4, offsetof(struct mp3entry
, composer
), NULL
, false },
430 { "TPE2", 4, offsetof(struct mp3entry
, albumartist
), NULL
, false },
431 { "TP2", 3, offsetof(struct mp3entry
, albumartist
), NULL
, false },
432 { "TIT1", 4, offsetof(struct mp3entry
, grouping
), NULL
, false },
433 { "TT1", 3, offsetof(struct mp3entry
, grouping
), NULL
, false },
434 { "COMM", 4, offsetof(struct mp3entry
, comment
), NULL
, false },
435 { "COM", 3, offsetof(struct mp3entry
, comment
), NULL
, false },
436 { "TCON", 4, offsetof(struct mp3entry
, genre_string
), &parsegenre
, false },
437 { "TCO", 3, offsetof(struct mp3entry
, genre_string
), &parsegenre
, false },
438 { "TXXX", 4, 0, &parseuser
, false },
439 #if CONFIG_CODEC == SWCODEC
440 { "RVA2", 4, 0, &parserva2
, true },
442 { "UFID", 4, 0, &parsembtid
, false },
445 #define TAGLIST_SIZE ((int)ARRAYLEN(taglist))
447 /* Get the length of an ID3 string in the given encoding. Returns the length
448 * in bytes, including end nil, or -1 if the encoding is unknown.
450 static int unicode_len(char encoding
, const void* string
)
454 if (encoding
== 0x01 || encoding
== 0x02) {
456 const char *s
= string
;
457 /* string might be unaligned, so using short* can crash on ARM and SH1 */
460 } while ((first
| *s
++) != 0);
462 len
= s
- (const char*) string
;
464 len
= strlen((char*) string
) + 1;
470 /* Checks to see if the passed in string is a 16-bit wide Unicode v2
471 string. If it is, we convert it to a UTF-8 string. If it's not unicode,
472 we convert from the default codepage */
473 static int unicode_munge(char* string
, char* utf8buf
, int *len
) {
477 unsigned char *str
= (unsigned char *)string
;
479 unsigned char* utf8
= (unsigned char *)utf8buf
;
482 case 0x00: /* Type 0x00 is ordinary ISO 8859-1 */
485 utf8
= iso_decode(str
, utf8
, -1, *len
);
487 *len
= (unsigned long)utf8
- (unsigned long)utf8buf
;
490 case 0x01: /* Unicode with or without BOM */
495 /* Handle frames with more than one string
496 (needed for TXXX frames).*/
498 tmp
= bytes2int(0, 0, str
[0], str
[1]);
500 /* Now check if there is a BOM
501 (zero-width non-breaking space, 0xfeff)
502 and if it is in little or big endian format */
503 if(tmp
== 0xfffe) { /* Little endian? */
507 } else if(tmp
== 0xfeff) { /* Big endian? */
511 /* If there is no BOM (which is a specification violation),
512 let's try to guess it. If one of the bytes is 0x00, it is
513 probably the most significant one. */
519 utf8
= utf16LEdecode(str
, utf8
, 1);
521 utf8
= utf16BEdecode(str
, utf8
, 1);
525 } while((str
[0] || str
[1]) && (i
< *len
));
527 *utf8
++ = 0; /* Terminate the string */
528 templen
+= (strlen(&utf8buf
[templen
]) + 1);
535 case 0x03: /* UTF-8 encoded string */
536 for(i
=0; i
< *len
; i
++)
541 default: /* Plain old string */
542 utf8
= iso_decode(str
, utf8
, -1, *len
);
544 *len
= (unsigned long)utf8
- (unsigned long)utf8buf
;
551 * Sets the title of an MP3 entry based on its ID3v1 tag.
553 * Arguments: file - the MP3 file to scen for a ID3v1 tag
554 * entry - the entry to set the title in
556 * Returns: true if a title was found and created, else false
558 bool setid3v1title(int fd
, struct mp3entry
*entry
)
560 unsigned char buffer
[128];
561 static const char offsets
[] = {3, 33, 63, 97, 93, 125, 127};
565 if (-1 == lseek(fd
, -128, SEEK_END
))
568 if (read(fd
, buffer
, sizeof buffer
) != sizeof buffer
)
571 if (strncmp((char *)buffer
, "TAG", 3))
574 entry
->id3v1len
= 128;
575 entry
->id3version
= ID3_VER_1_0
;
577 for (i
=0; i
< (int)sizeof offsets
; i
++) {
578 unsigned char* ptr
= (unsigned char *)buffer
+ offsets
[i
];
584 /* kill trailing space in strings */
585 for (j
=29; j
&& (ptr
[j
]==0 || ptr
[j
]==' '); j
--)
587 /* convert string to utf8 */
588 utf8
= (unsigned char *)entry
->id3v1buf
[i
];
589 utf8
= iso_decode(ptr
, utf8
, -1, 30);
590 /* make sure string is terminated */
595 /* kill trailing space in strings */
596 for (j
=27; j
&& (ptr
[j
]==0 || ptr
[j
]==' '); j
--)
598 /* convert string to utf8 */
599 utf8
= (unsigned char *)entry
->id3v1buf
[3];
600 utf8
= iso_decode(ptr
, utf8
, -1, 28);
601 /* make sure string is terminated */
607 entry
->year
= atoi((char *)ptr
);
611 /* id3v1.1 uses last two bytes of comment field for track
612 number: first must be 0 and second is track num */
613 if (!ptr
[0] && ptr
[1]) {
614 entry
->tracknum
= ptr
[1];
615 entry
->id3version
= ID3_VER_1_1
;
621 entry
->genre_string
= id3_get_num_genre(ptr
[0]);
626 entry
->title
= entry
->id3v1buf
[0];
627 entry
->artist
= entry
->id3v1buf
[1];
628 entry
->album
= entry
->id3v1buf
[2];
629 entry
->comment
= entry
->id3v1buf
[3];
636 * Sets the title of an MP3 entry based on its ID3v2 tag.
638 * Arguments: file - the MP3 file to scan for a ID3v2 tag
639 * entry - the entry to set the title in
641 * Returns: true if a title was found and created, else false
643 void setid3v2title(int fd
, struct mp3entry
*entry
)
647 long bufferpos
= 0, totframelen
, framelen
;
650 unsigned char version
;
651 char *buffer
= entry
->id3v2buf
;
653 int buffersize
= sizeof(entry
->id3v2buf
);
654 unsigned char global_flags
;
657 bool global_unsynch
= false;
658 bool unsynch
= false;
661 #if CONFIG_CODEC == SWCODEC
662 bool itunes_gapless
= false;
665 global_ff_found
= false;
667 /* Bail out if the tag is shorter than 10 bytes */
668 if(entry
->id3v2len
< 10)
671 /* Read the ID3 tag version from the header */
672 lseek(fd
, 0, SEEK_SET
);
673 if(10 != read(fd
, header
, 10))
676 /* Get the total ID3 tag size */
677 size
= entry
->id3v2len
- 10;
682 version
= ID3_VER_2_2
;
687 version
= ID3_VER_2_3
;
692 version
= ID3_VER_2_4
;
697 /* unsupported id3 version */
700 entry
->id3version
= version
;
701 entry
->tracknum
= entry
->year
= entry
->discnum
= 0;
702 entry
->title
= entry
->artist
= entry
->album
= NULL
; /* FIXME incomplete */
704 global_flags
= header
[5];
706 /* Skip the extended header if it is present */
707 if(global_flags
& 0x40) {
708 if(version
== ID3_VER_2_3
) {
709 if(10 != read(fd
, header
, 10))
711 /* The 2.3 extended header size doesn't include the header size
712 field itself. Also, it is not unsynched. */
714 bytes2int(header
[0], header
[1], header
[2], header
[3]) + 4;
716 /* Skip the rest of the header */
717 lseek(fd
, framelen
- 10, SEEK_CUR
);
720 if(version
>= ID3_VER_2_4
) {
721 if(4 != read(fd
, header
, 4))
724 /* The 2.4 extended header size does include the entire header,
725 so here we can just skip it. This header is unsynched. */
726 framelen
= unsync(header
[0], header
[1],
727 header
[2], header
[3]);
729 lseek(fd
, framelen
- 4, SEEK_CUR
);
733 /* Is unsynchronization applied? */
734 if(global_flags
& 0x80) {
735 global_unsynch
= true;
739 * We must have at least minframesize bytes left for the
740 * remaining frames to be interesting
742 while (size
>= minframesize
&& bufferpos
< buffersize
- 1) {
745 /* Read frame header and check length */
746 if(version
>= ID3_VER_2_3
) {
747 if(global_unsynch
&& version
<= ID3_VER_2_3
)
748 rc
= read_unsynched(fd
, header
, 10);
750 rc
= read(fd
, header
, 10);
753 /* Adjust for the 10 bytes we read */
756 flags
= bytes2int(0, 0, header
[8], header
[9]);
758 if (version
>= ID3_VER_2_4
) {
759 framelen
= unsync(header
[4], header
[5],
760 header
[6], header
[7]);
762 /* version .3 files don't use synchsafe ints for
764 framelen
= bytes2int(header
[4], header
[5],
765 header
[6], header
[7]);
768 if(6 != read(fd
, header
, 6))
770 /* Adjust for the 6 bytes we read */
773 framelen
= bytes2int(0, header
[3], header
[4], header
[5]);
776 logf("framelen = %ld, flags = 0x%04x", framelen
, flags
);
778 if (header
[0] == 0 && header
[1] == 0 && header
[2] == 0)
790 if (version
>= ID3_VER_2_4
) {
791 if(flags
& 0x0040) { /* Grouping identity */
792 lseek(fd
, 1, SEEK_CUR
); /* Skip 1 byte */
796 if(flags
& 0x0020) { /* Grouping identity */
797 lseek(fd
, 1, SEEK_CUR
); /* Skip 1 byte */
802 if(flags
& 0x000c) /* Compression or encryption */
806 lseek(fd
, framelen
, SEEK_CUR
);
810 if(flags
& 0x0002) /* Unsynchronization */
813 if (version
>= ID3_VER_2_4
) {
814 if(flags
& 0x0001) { /* Data length indicator */
815 if(4 != read(fd
, tmp
, 4))
818 /* We don't need the data length */
830 /* Keep track of the remaining frame size */
831 totframelen
= framelen
;
833 /* If the frame is larger than the remaining buffer space we try
834 to read as much as would fit in the buffer */
835 if(framelen
>= buffersize
- bufferpos
)
836 framelen
= buffersize
- bufferpos
- 1;
838 logf("id3v2 frame: %.4s", header
);
840 /* Check for certain frame headers
842 'size' is the amount of frame bytes remaining. We decrement it by
843 the amount of bytes we read. If we fail to read as many bytes as
844 we expect, we assume that we can't read from this file, and bail
847 For each frame. we will iterate over the list of supported tags,
848 and read the tag into entry's buffer. All tags will be kept as
849 strings, for cases where a number won't do, e.g., YEAR: "circa
850 1765", "1790/1977" (composed/performed), "28 Feb 1969" TRACK:
851 "1/12", "1 of 12", GENRE: "Freeform genre name" Text is more
852 flexible, and as the main use of id3 data is to display it,
853 converting it to an int just means reconverting to display it, at a
856 For tags that the current code does convert to ints, a post
857 processing function will be called via a pointer to function. */
859 for (i
=0; i
<TAGLIST_SIZE
; i
++) {
860 const struct tag_resolver
* tr
= &taglist
[i
];
861 char** ptag
= tr
->offset
? (char**) (((char*)entry
) + tr
->offset
)
865 /* Only ID3_VER_2_2 uses frames with three-character names. */
866 if (((version
== ID3_VER_2_2
) && (tr
->tag_length
!= 3))
867 || ((version
> ID3_VER_2_2
) && (tr
->tag_length
!= 4))) {
871 if( !memcmp( header
, tr
->tag
, tr
->tag_length
) ) {
873 /* found a tag matching one in tagList, and not yet filled */
874 tag
= buffer
+ bufferpos
;
876 if(global_unsynch
&& version
<= ID3_VER_2_3
)
877 bytesread
= read_unsynched(fd
, tag
, framelen
);
879 bytesread
= read(fd
, tag
, framelen
);
881 if( bytesread
!= framelen
)
886 if(unsynch
|| (global_unsynch
&& version
>= ID3_VER_2_4
))
887 bytesread
= unsynchronize_frame(tag
, bytesread
);
889 /* the COMM frame has a 3 char field to hold an ISO-639-1
890 * language string and an optional short description;
891 * remove them so unicode_munge can work correctly
894 if((tr
->tag_length
== 4 && !memcmp( header
, "COMM", 4)) ||
895 (tr
->tag_length
== 3 && !memcmp( header
, "COM", 3))) {
897 if(!strncmp(tag
+4, "iTun", 4)) {
898 #if CONFIG_CODEC == SWCODEC
899 /* check for iTunes gapless information */
900 if(!strncmp(tag
+4, "iTunSMPB", 8))
901 itunes_gapless
= true;
904 /* ignore other with iTunes tags */
908 offset
= 3 + unicode_len(*tag
, tag
+ 4);
909 if(bytesread
> offset
) {
911 memmove(tag
+ 1, tag
+ 1 + offset
, bytesread
- 1);
915 /* Attempt to parse Unicode string only if the tag contents
918 /* UTF-8 could potentially be 3 times larger */
919 /* so we need to create a new buffer */
920 char utf8buf
[(3 * bytesread
) + 1];
922 unicode_munge( tag
, utf8buf
, &bytesread
);
924 if(bytesread
>= buffersize
- bufferpos
)
925 bytesread
= buffersize
- bufferpos
- 1;
927 for (j
= 0; j
< bytesread
; j
++)
930 /* remove trailing spaces */
931 while ( bytesread
> 0 && isspace(tag
[bytesread
-1]))
936 bufferpos
+= bytesread
+ 1;
938 #if CONFIG_CODEC == SWCODEC
939 /* parse the tag if it contains iTunes gapless info */
942 itunes_gapless
= false;
943 entry
->lead_trim
= get_itunes_int32(tag
, 1);
944 entry
->tail_trim
= get_itunes_int32(tag
, 2);
948 /* Note that parser functions sometimes set *ptag to NULL, so
949 * the "!*ptag" check here doesn't always have the desired
950 * effect. Should the parser functions (parsegenre in
951 * particular) be updated to handle the case of being called
952 * multiple times, or should the "*ptag" check be removed?
958 bufferpos
= tr
->ppFunc(entry
, tag
, bufferpos
);
960 /* Seek to the next frame */
961 if(framelen
< totframelen
)
962 lseek(fd
, totframelen
- framelen
, SEEK_CUR
);
967 if( i
== TAGLIST_SIZE
) {
968 /* no tag in tagList was found, or it was a repeat.
969 skip it using the total size */
971 if(global_unsynch
&& version
<= ID3_VER_2_3
) {
972 size
-= skip_unsynched(fd
, totframelen
);
975 if( lseek(fd
, totframelen
, SEEK_CUR
) == -1 )
983 * Calculates the size of the ID3v2 tag.
985 * Arguments: file - the file to search for a tag.
987 * Returns: the size of the tag or 0 if none was found
989 int getid3v2len(int fd
)
994 /* Make sure file has a ID3 tag */
995 if((-1 == lseek(fd
, 0, SEEK_SET
)) ||
996 (read(fd
, buf
, 6) != 6) ||
997 (strncmp(buf
, "ID3", strlen("ID3")) != 0))
1000 /* Now check what the ID3v2 size field says */
1002 if(read(fd
, buf
, 4) != 4)
1005 offset
= unsync(buf
[0], buf
[1], buf
[2], buf
[3]) + 10;
1007 logf("ID3V2 Length: 0x%x", offset
);
1012 * Calculates the length (in milliseconds) of an MP3 file.
1014 * Modified to only use integers.
1016 * Arguments: file - the file to calculate the length upon
1017 * entry - the entry to update with the length
1019 * Returns: the song length in milliseconds,
1020 * 0 means that it couldn't be calculated
1022 static int getsonglength(int fd
, struct mp3entry
*entry
)
1024 unsigned long filetime
= 0;
1025 struct mp3info info
;
1028 /* Start searching after ID3v2 header */
1029 if(-1 == lseek(fd
, entry
->id3v2len
, SEEK_SET
))
1032 bytecount
= get_mp3file_info(fd
, &info
);
1034 logf("Space between ID3V2 tag and first audio frame: 0x%lx bytes",
1040 bytecount
+= entry
->id3v2len
;
1042 /* Validate byte count, in case the file has been edited without
1043 * updating the header.
1045 if (info
.byte_count
)
1047 const unsigned long expected
= entry
->filesize
- entry
->id3v1len
1049 const unsigned long diff
= MAX(10240, info
.byte_count
/ 20);
1051 if ((info
.byte_count
> expected
+ diff
)
1052 || (info
.byte_count
< expected
- diff
))
1054 logf("Note: info.byte_count differs from expected value by "
1055 "%ld bytes", labs((long) (expected
- info
.byte_count
)));
1056 info
.byte_count
= 0;
1057 info
.frame_count
= 0;
1059 info
.enc_padding
= 0;
1061 /* Even if the bitrate was based on "known bad" values, it
1062 * should still be better for VBR files than using the bitrate
1063 * of the first audio frame.
1068 entry
->bitrate
= info
.bitrate
;
1069 entry
->frequency
= info
.frequency
;
1070 entry
->version
= info
.version
;
1071 entry
->layer
= info
.layer
;
1072 switch(entry
->layer
) {
1073 #if CONFIG_CODEC==SWCODEC
1075 entry
->codectype
=AFMT_MPA_L1
;
1079 entry
->codectype
=AFMT_MPA_L2
;
1082 entry
->codectype
=AFMT_MPA_L3
;
1086 /* If the file time hasn't been established, this may be a fixed
1087 rate MP3, so just use the default formula */
1089 filetime
= info
.file_time
;
1093 /* Prevent a division by zero */
1094 if (info
.bitrate
< 8)
1097 filetime
= (entry
->filesize
- bytecount
) / (info
.bitrate
/ 8);
1098 /* bitrate is in kbps so this delivers milliseconds. Doing bitrate / 8
1099 * instead of filesize * 8 is exact, because mpeg audio bitrates are
1100 * always multiples of 8, and it avoids overflows. */
1103 entry
->frame_count
= info
.frame_count
;
1105 entry
->vbr
= info
.is_vbr
;
1106 entry
->has_toc
= info
.has_toc
;
1108 #if CONFIG_CODEC==SWCODEC
1109 if (!entry
->lead_trim
)
1110 entry
->lead_trim
= info
.enc_delay
;
1111 if (!entry
->tail_trim
)
1112 entry
->tail_trim
= info
.enc_padding
;
1115 memcpy(entry
->toc
, info
.toc
, sizeof(info
.toc
));
1117 entry
->vbr_header_pos
= info
.vbr_header_pos
;
1119 /* Update the seek point for the first playable frame */
1120 entry
->first_frame_offset
= bytecount
;
1121 logf("First frame is at %lx", entry
->first_frame_offset
);
1127 * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc)
1128 * about an MP3 file and updates it's entry accordingly.
1130 Note, that this returns true for successful, false for error! */
1131 bool get_mp3_metadata(int fd
, struct mp3entry
*entry
, const char *filename
)
1133 #if CONFIG_CODEC != SWCODEC
1134 memset(entry
, 0, sizeof(struct mp3entry
));
1137 strlcpy(entry
->path
, filename
, sizeof(entry
->path
));
1139 entry
->title
= NULL
;
1140 entry
->filesize
= filesize(fd
);
1141 entry
->id3v2len
= getid3v2len(fd
);
1142 entry
->tracknum
= 0;
1145 if (entry
->id3v2len
)
1146 setid3v2title(fd
, entry
);
1147 int len
= getsonglength(fd
, entry
);
1150 entry
->length
= len
;
1152 /* Subtract the meta information from the file size to get
1153 the true size of the MP3 stream */
1154 entry
->filesize
-= entry
->first_frame_offset
;
1156 /* only seek to end of file if no id3v2 tags were found */
1157 if (!entry
->id3v2len
) {
1158 setid3v1title(fd
, entry
);
1161 if(!entry
->length
|| (entry
->filesize
< 8 ))
1162 /* no song length or less than 8 bytes is hereby considered to be an
1163 invalid mp3 and won't be played by us! */
1169 #ifdef DEBUG_STANDALONE
1171 char *secs2str(int ms
)
1173 static char buffer
[32];
1176 snprintf(buffer
, sizeof(buffer
), "%d:%02d.%d", secs
/60, secs
%60, ms
/100);
1180 int main(int argc
, char **argv
)
1183 for(i
=1; i
<argc
; i
++) {
1184 struct mp3entry mp3
;
1185 mp3
.album
= "Bogus";
1186 if(mp3info(&mp3
, argv
[i
], false)) {
1187 printf("Failed to get %s\n", argv
[i
]);
1191 printf("****** File: %s\n"
1195 " Genre: %s (%d) \n"
1199 " Length: %s / %d s\n"
1203 mp3
.title
?mp3
.title
:"<blank>",
1204 mp3
.artist
?mp3
.artist
:"<blank>",
1205 mp3
.album
?mp3
.album
:"<blank>",
1206 mp3
.genre_string
?mp3
.genre_string
:"<blank>",
1208 mp3
.composer
?mp3
.composer
:"<blank>",
1209 mp3
.year_string
?mp3
.year_string
:"<blank>",
1211 mp3
.track_string
?mp3
.track_string
:"<blank>",
1213 secs2str(mp3
.length
),