diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/metadata.c | 1643 |
1 files changed, 866 insertions, 777 deletions
diff --git a/apps/metadata.c b/apps/metadata.c index 03ecf00186..b57bf0fbc7 100644 --- a/apps/metadata.c +++ b/apps/metadata.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <string.h> | 20 | #include <string.h> |
21 | #include <stdlib.h> | 21 | #include <stdlib.h> |
22 | #include <ctype.h> | 22 | #include <ctype.h> |
23 | #include <inttypes.h> | ||
23 | 24 | ||
24 | #include "metadata.h" | 25 | #include "metadata.h" |
25 | #include "mp3_playback.h" | 26 | #include "mp3_playback.h" |
@@ -27,912 +28,1000 @@ | |||
27 | #include "atoi.h" | 28 | #include "atoi.h" |
28 | #include "replaygain.h" | 29 | #include "replaygain.h" |
29 | #include "debug.h" | 30 | #include "debug.h" |
31 | #include "system.h" | ||
30 | 32 | ||
31 | /* Simple file type probing by looking filename extension. */ | 33 | enum tagtype { TAGTYPE_APE = 1, TAGTYPE_VORBIS }; |
32 | unsigned int probe_file_format(const char *filename) | ||
33 | { | ||
34 | char *suffix; | ||
35 | |||
36 | suffix = strrchr(filename, '.'); | ||
37 | if (suffix == NULL) | ||
38 | return AFMT_UNKNOWN; | ||
39 | suffix += 1; | ||
40 | |||
41 | if (!strcasecmp("mp1", suffix)) | ||
42 | return AFMT_MPA_L1; | ||
43 | else if (!strcasecmp("mp2", suffix)) | ||
44 | return AFMT_MPA_L2; | ||
45 | else if (!strcasecmp("mpa", suffix)) | ||
46 | return AFMT_MPA_L2; | ||
47 | else if (!strcasecmp("mp3", suffix)) | ||
48 | return AFMT_MPA_L3; | ||
49 | else if (!strcasecmp("ogg", suffix)) | ||
50 | return AFMT_OGG_VORBIS; | ||
51 | else if (!strcasecmp("wav", suffix)) | ||
52 | return AFMT_PCM_WAV; | ||
53 | else if (!strcasecmp("flac", suffix)) | ||
54 | return AFMT_FLAC; | ||
55 | else if (!strcasecmp("mpc", suffix)) | ||
56 | return AFMT_MPC; | ||
57 | else if ((!strcasecmp("a52", suffix)) || (!strcasecmp("ac3", suffix))) | ||
58 | return AFMT_A52; | ||
59 | else if (!strcasecmp("wv", suffix)) | ||
60 | return AFMT_WAVPACK; | ||
61 | |||
62 | return AFMT_UNKNOWN; | ||
63 | } | ||
64 | 34 | ||
65 | unsigned short a52_bitrates[]={32,40,48,56,64,80,96, | 35 | #define APETAG_HEADER_LENGTH 32 |
66 | 112,128,160,192,224,256,320, | 36 | #define APETAG_HEADER_FORMAT "8LLLL" |
67 | 384,448,512,576,640}; | 37 | #define APETAG_ITEM_HEADER_FORMAT "LL" |
38 | #define APETAG_ITEM_TYPE_MASK 3 | ||
68 | 39 | ||
69 | /* Only store frame sizes for 44.1KHz - others are simply multiples | 40 | #define TAG_NAME_LENGTH 32 |
70 | of the bitrate */ | 41 | #define TAG_VALUE_LENGTH 128 |
71 | unsigned short a52_441framesizes[]= | 42 | |
72 | {69*2,70*2,87*2,88*2,104*2,105*2,121*2,122*2, | 43 | struct apetag_header |
73 | 139*2,140*2,174*2,175*2,208*2,209*2,243*2,244*2, | 44 | { |
74 | 278*2,279*2,348*2,349*2,417*2,418*2,487*2,488*2, | 45 | char id[8]; |
75 | 557*2,558*2,696*2,697*2,835*2,836*2,975*2,976*2, | 46 | long version; |
76 | 1114*2,1115*2,1253*2,1254*2,1393*2,1394*2}; | 47 | long length; |
48 | long item_count; | ||
49 | long flags; | ||
50 | char reserved[8]; | ||
51 | }; | ||
77 | 52 | ||
78 | const long wavpack_sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, | 53 | struct apetag_item_header |
79 | 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 }; | 54 | { |
55 | long length; | ||
56 | long flags; | ||
57 | }; | ||
80 | 58 | ||
81 | /* Get metadata for track - return false if parsing showed problems with the | 59 | struct format_list |
82 | file that would prevent playback. */ | 60 | { |
61 | char format; | ||
62 | char extension[5]; | ||
63 | }; | ||
83 | 64 | ||
84 | static bool get_apetag_info (struct mp3entry *entry, int fd); | 65 | static const struct format_list formats[] = |
66 | { | ||
67 | { AFMT_MPA_L1, "mp1" }, | ||
68 | { AFMT_MPA_L2, "mp2" }, | ||
69 | { AFMT_MPA_L2, "mpa" }, | ||
70 | { AFMT_MPA_L3, "mp3" }, | ||
71 | { AFMT_OGG_VORBIS, "ogg" }, | ||
72 | { AFMT_PCM_WAV, "wav" }, | ||
73 | { AFMT_FLAC, "flac" }, | ||
74 | { AFMT_MPC, "mpc" }, | ||
75 | { AFMT_A52, "a52" }, | ||
76 | { AFMT_A52, "ac3" }, | ||
77 | { AFMT_WAVPACK, "wv" }, | ||
78 | }; | ||
85 | 79 | ||
86 | static bool get_vorbis_comments (struct mp3entry *entry, size_t bytes_remaining, int fd); | 80 | static const unsigned short a52_bitrates[] = |
81 | { | ||
82 | 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, | ||
83 | 192, 224, 256, 320, 384, 448, 512, 576, 640 | ||
84 | }; | ||
87 | 85 | ||
88 | static void little_endian_to_native (void *data, char *format); | 86 | /* Only store frame sizes for 44.1KHz - others are simply multiples |
87 | of the bitrate */ | ||
88 | static const unsigned short a52_441framesizes[] = | ||
89 | { | ||
90 | 69 * 2, 70 * 2, 87 * 2, 88 * 2, 104 * 2, 105 * 2, 121 * 2, | ||
91 | 122 * 2, 139 * 2, 140 * 2, 174 * 2, 175 * 2, 208 * 2, 209 * 2, | ||
92 | 243 * 2, 244 * 2, 278 * 2, 279 * 2, 348 * 2, 349 * 2, 417 * 2, | ||
93 | 418 * 2, 487 * 2, 488 * 2, 557 * 2, 558 * 2, 696 * 2, 697 * 2, | ||
94 | 835 * 2, 836 * 2, 975 * 2, 976 * 2, 1114 * 2, 1115 * 2, 1253 * 2, | ||
95 | 1254 * 2, 1393 * 2, 1394 * 2 | ||
96 | }; | ||
89 | 97 | ||
90 | bool get_metadata(struct track_info* track, int fd, const char* trackname, | 98 | static const long wavpack_sample_rates [] = |
91 | bool v1first) { | 99 | { |
92 | unsigned long totalsamples,bytespersample,channels,bitspersample,numbytes; | 100 | 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, |
93 | unsigned long serialno=0, last_serialno=0; | 101 | 32000, 44100, 48000, 64000, 88200, 96000, 192000 |
94 | int bytesperframe; | 102 | }; |
95 | unsigned char* buf; | ||
96 | int i,j,eof; | ||
97 | int rc; | ||
98 | int segments; /* for Vorbis*/ | ||
99 | size_t bytes_remaining = 0; /* for Vorbis */ | ||
100 | 103 | ||
104 | /* Read a string from the file. Read up to size bytes, or, if eos != -1, | ||
105 | * until the eos character is found (eos is not stored in buf, unless it is | ||
106 | * nil). Writes up to buf_size chars to buf, always terminating with a nil. | ||
107 | * Returns number of chars read or -1 on read error. | ||
108 | */ | ||
109 | static long read_string(int fd, char* buf, long buf_size, int eos, long size) | ||
110 | { | ||
111 | long read_bytes = 0; | ||
112 | char c; | ||
101 | 113 | ||
102 | /* Load codec specific track tag information. */ | 114 | while (size != 0) |
103 | switch (track->id3.codectype) { | 115 | { |
104 | case AFMT_MPA_L1: | 116 | if (read(fd, &c, 1) != 1) |
105 | case AFMT_MPA_L2: | 117 | { |
106 | case AFMT_MPA_L3: | 118 | read_bytes = -1; |
107 | /* Should check the return value. */ | 119 | break; |
108 | mp3info(&track->id3, trackname, v1first); | 120 | } |
109 | lseek(fd, 0, SEEK_SET); | 121 | |
110 | 122 | read_bytes++; | |
111 | /* | 123 | size--; |
112 | logf("T:%s", track->id3.title); | 124 | |
113 | logf("L:%d", track->id3.length); | 125 | if ((eos != -1) && (eos == (unsigned char) c)) |
114 | logf("O:%d", track->id3.first_frame_offset); | 126 | { |
115 | logf("F:%d", track->id3.frequency); | 127 | break; |
116 | */ | 128 | } |
117 | track->taginfo_ready = true; | 129 | |
118 | break ; | 130 | if (buf_size > 1) |
119 | 131 | { | |
120 | case AFMT_PCM_WAV: | 132 | *buf++ = c; |
121 | /* Use the trackname part of the id3 structure as a temporary buffer */ | 133 | buf_size--; |
122 | buf=track->id3.path; | 134 | } |
123 | 135 | } | |
124 | lseek(fd, 0, SEEK_SET); | 136 | |
125 | 137 | *buf = 0; | |
126 | rc = read(fd, buf, 44); | 138 | return read_bytes; |
127 | if (rc < 44) { | 139 | } |
128 | return false; | ||
129 | } | ||
130 | 140 | ||
131 | if ((memcmp(buf,"RIFF",4)!=0) || | 141 | /* Convert a little-endian structure to native format using a format string. |
132 | (memcmp(&buf[8],"WAVEfmt",7)!=0)) { | 142 | * Does nothing on a little-endian machine. |
133 | logf("%s is not a WAV file\n",trackname); | 143 | */ |
134 | return(false); | 144 | static void convert_endian(void *data, const char *format) |
135 | } | 145 | { |
146 | while (*format) | ||
147 | { | ||
148 | switch (*format) | ||
149 | { | ||
150 | case 'L': | ||
151 | { | ||
152 | long* d = (long*) data; | ||
153 | |||
154 | *d = SWAB32(*d); | ||
155 | data = d + 1; | ||
156 | } | ||
157 | |||
158 | break; | ||
136 | 159 | ||
137 | /* FIX: Correctly parse WAV header - we assume canonical | 160 | case 'S': |
138 | 44-byte header */ | 161 | { |
162 | short* d = (short*) data; | ||
163 | |||
164 | *d = SWAB16(*d); | ||
165 | data = d + 1; | ||
166 | } | ||
167 | |||
168 | break; | ||
139 | 169 | ||
140 | bitspersample=buf[34]; | 170 | default: |
141 | channels=buf[22]; | 171 | if (isdigit(*format)) |
172 | { | ||
173 | data = ((char*) data) + *format - '0'; | ||
174 | } | ||
175 | |||
176 | break; | ||
177 | } | ||
142 | 178 | ||
143 | if ((bitspersample!=16) || (channels != 2)) { | 179 | format++; |
144 | logf("Unsupported WAV file - %d bitspersample, %d channels\n", | 180 | } |
145 | bitspersample,channels); | 181 | } |
146 | return(false); | ||
147 | } | ||
148 | 182 | ||
149 | bytespersample=((bitspersample/8)*channels); | 183 | /* Read an unaligned 32-bit little endian long from buffer. */ |
150 | numbytes=(buf[40]|(buf[41]<<8)|(buf[42]<<16)|(buf[43]<<24)); | 184 | static unsigned long get_long(void* buf) |
151 | totalsamples=numbytes/bytespersample; | 185 | { |
186 | unsigned char* p = (unsigned char*) buf; | ||
152 | 187 | ||
153 | track->id3.vbr=false; /* All WAV files are CBR */ | 188 | return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); |
154 | track->id3.filesize=filesize(fd); | 189 | } |
155 | track->id3.frequency=buf[24]|(buf[25]<<8)|(buf[26]<<16)|(buf[27]<<24); | ||
156 | 190 | ||
157 | /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ | 191 | /* Convert an UTF-8 string to Latin-1, overwriting the old string (the new |
158 | track->id3.length=(totalsamples/track->id3.frequency)*1000; | 192 | * string is never longer than the original, so this is safe). Non-latin-1 |
159 | track->id3.bitrate=(track->id3.frequency*bytespersample)/(1000/8); | 193 | * chars are replaced with '?'. |
194 | */ | ||
195 | static void convert_utf8(char* utf8) | ||
196 | { | ||
197 | char* dest = utf8; | ||
198 | long code = 0; | ||
199 | unsigned char c; | ||
200 | int tail = 0; | ||
201 | int size = 0; | ||
202 | |||
203 | while ((c = *utf8++) != 0) | ||
204 | { | ||
205 | if ((tail <= 0) && ((c <= 0x7f) || (c >= 0xc2))) | ||
206 | { | ||
207 | /* Start of new character. */ | ||
208 | if (c < 0x80) | ||
209 | { | ||
210 | size = 1; | ||
211 | } | ||
212 | else if (c < 0xe0) | ||
213 | { | ||
214 | size = 2; | ||
215 | c &= 0x1f; | ||
216 | } | ||
217 | else if (c < 0xf0) | ||
218 | { | ||
219 | size = 3; | ||
220 | c &= 0x0f; | ||
221 | } | ||
222 | else if (c < 0xf5) | ||
223 | { | ||
224 | size = 4; | ||
225 | c &= 0x07; | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | /* Invalid size. */ | ||
230 | size = 0; | ||
231 | } | ||
160 | 232 | ||
161 | lseek(fd, 0, SEEK_SET); | 233 | code = c; |
162 | strncpy(track->id3.path,trackname,sizeof(track->id3.path)); | 234 | tail = size - 1; |
163 | track->taginfo_ready = true; | 235 | } |
236 | else if ((tail > 0) && ((c & 0xc0) == 0x80)) | ||
237 | { | ||
238 | /* Valid continuation character. */ | ||
239 | code = (code << 6) | (c & 0x3f); | ||
240 | tail--; | ||
241 | |||
242 | if (tail == 0) | ||
243 | { | ||
244 | if (((size == 2) && (code < 0x80)) | ||
245 | || ((size == 3) && (code < 0x800)) | ||
246 | || ((size == 4) && (code < 0x10000))) | ||
247 | { | ||
248 | /* Invalid encoding. */ | ||
249 | code = 0; | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | tail = -1; | ||
256 | } | ||
164 | 257 | ||
165 | break; | 258 | if ((tail == 0) && (code > 0)) |
259 | { | ||
260 | *dest++ = (code <= 0xff) ? (char) (code & 0xff) : '?'; | ||
261 | } | ||
262 | } | ||
166 | 263 | ||
167 | case AFMT_FLAC: | 264 | *dest = 0; |
168 | /* A simple parser to read vital metadata from a FLAC file - length, frequency, bitrate etc. */ | 265 | } |
169 | /* This code should either be moved to a seperate file, or discarded in favour of the libFLAC code */ | ||
170 | /* The FLAC stream specification can be found at http://flac.sourceforge.net/format.html#stream */ | ||
171 | 266 | ||
172 | /* Use the trackname part of the id3 structure as a temporary buffer */ | 267 | /* Parse the tag (the name-value pair) and fill id3 and buffer accordingly. |
173 | buf=track->id3.path; | 268 | * String values to keep are written to buf. Returns number of bytes written |
269 | * to buf (including end nil). | ||
270 | */ | ||
271 | static long parse_tag(const char* name, char* value, struct mp3entry* id3, | ||
272 | char* buf, long buf_remaining, enum tagtype type) | ||
273 | { | ||
274 | long len = 0; | ||
275 | char** p; | ||
276 | |||
277 | if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE))) | ||
278 | || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS))) | ||
279 | { | ||
280 | id3->tracknum = atoi(value); | ||
281 | p = &(id3->track_string); | ||
282 | } | ||
283 | else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE)) | ||
284 | || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS))) | ||
285 | { | ||
286 | /* Date can be in more any format in a Vorbis tag, so don't try to | ||
287 | * parse it. | ||
288 | */ | ||
289 | if (type != TAGTYPE_VORBIS) | ||
290 | { | ||
291 | id3->year = atoi(value); | ||
292 | } | ||
293 | |||
294 | p = &(id3->year_string); | ||
295 | } | ||
296 | else if (strcasecmp(name, "title") == 0) | ||
297 | { | ||
298 | p = &(id3->title); | ||
299 | } | ||
300 | else if (strcasecmp(name, "artist") == 0) | ||
301 | { | ||
302 | p = &(id3->artist); | ||
303 | } | ||
304 | else if (strcasecmp(name, "album") == 0) | ||
305 | { | ||
306 | p = &(id3->album); | ||
307 | } | ||
308 | else if (strcasecmp(name, "genre") == 0) | ||
309 | { | ||
310 | p = &(id3->genre_string); | ||
311 | } | ||
312 | else if (strcasecmp(name, "composer") == 0) | ||
313 | { | ||
314 | p = &(id3->composer); | ||
315 | } | ||
316 | else | ||
317 | { | ||
318 | len = parse_replaygain(name, value, id3, buf, buf_remaining); | ||
319 | p = NULL; | ||
320 | } | ||
321 | |||
322 | if (p) | ||
323 | { | ||
324 | len = strlen(value); | ||
325 | len = MIN(len, buf_remaining - 1); | ||
326 | |||
327 | if (len > 0) | ||
328 | { | ||
329 | strncpy(buf, value, len); | ||
330 | buf[len] = 0; | ||
331 | *p = buf; | ||
332 | len++; | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | len = 0; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | return len; | ||
341 | } | ||
174 | 342 | ||
175 | lseek(fd, 0, SEEK_SET); | 343 | /* Read the items in an APEV2 tag. Only looks for a tag at the end of a |
344 | * file. Returns true if a tag was found and fully read, false otherwise. | ||
345 | */ | ||
346 | static bool read_ape_tags(int fd, struct mp3entry* id3) | ||
347 | { | ||
348 | struct apetag_header header; | ||
176 | 349 | ||
177 | rc = read(fd, buf, 4); | 350 | if ((lseek(fd, -APETAG_HEADER_LENGTH, SEEK_END) < 0) |
178 | if (rc < 4) { | 351 | || (read(fd, &header, APETAG_HEADER_LENGTH) != APETAG_HEADER_LENGTH) |
352 | || (memcmp(header.id, "APETAGEX", sizeof(header.id)))) | ||
353 | { | ||
179 | return false; | 354 | return false; |
180 | } | 355 | } |
181 | |||
182 | if (memcmp(buf,"fLaC",4)!=0) { | ||
183 | logf("%s is not a FLAC file\n",trackname); | ||
184 | return(false); | ||
185 | } | ||
186 | 356 | ||
187 | while (1) { | 357 | convert_endian(&header, APETAG_HEADER_FORMAT); |
188 | rc = read(fd, buf, 4); | 358 | id3->genre = 0xff; |
189 | i = (buf[1]<<16)|(buf[2]<<8)|buf[3]; /* The length of the block */ | ||
190 | 359 | ||
191 | if ((buf[0]&0x7f)==0) { /* 0 is the STREAMINFO block */ | 360 | if ((header.version == 2000) && (header.item_count > 0) |
192 | rc = read(fd, buf, i); /* FIXME: Don't trust the value of i */ | 361 | && (header.length > APETAG_HEADER_LENGTH)) |
193 | if (rc < 0) { | 362 | { |
363 | char *buf = id3->id3v2buf; | ||
364 | unsigned int buf_remaining = sizeof(id3->id3v2buf) | ||
365 | + sizeof(id3->id3v1buf); | ||
366 | unsigned int tag_remaining = header.length - APETAG_HEADER_LENGTH; | ||
367 | int i; | ||
368 | |||
369 | if (lseek(fd, -header.length, SEEK_END) < 0) | ||
370 | { | ||
194 | return false; | 371 | return false; |
195 | } | 372 | } |
196 | track->id3.vbr=true; /* All FLAC files are VBR */ | ||
197 | track->id3.filesize=filesize(fd); | ||
198 | |||
199 | track->id3.frequency=(buf[10]<<12)|(buf[11]<<4)|((buf[12]&0xf0)>>4); | ||
200 | 373 | ||
201 | /* NOT NEEDED: bitspersample=(((buf[12]&0x01)<<4)|((buf[13]&0xf0)>>4))+1; */ | 374 | for (i = 0; i < header.item_count; i++) |
375 | { | ||
376 | struct apetag_item_header item; | ||
377 | char name[TAG_NAME_LENGTH]; | ||
378 | char value[TAG_VALUE_LENGTH]; | ||
379 | long r; | ||
202 | 380 | ||
203 | /* totalsamples is a 36-bit field, but we assume <= 32 bits are used */ | 381 | if (tag_remaining < sizeof(item)) |
204 | totalsamples=(buf[14]<<24)|(buf[15]<<16)|(buf[16]<<8)|buf[17]; | 382 | { |
383 | break; | ||
384 | } | ||
385 | |||
386 | if (read(fd, &item, sizeof(item)) < (long) sizeof(item)) | ||
387 | { | ||
388 | return false; | ||
389 | } | ||
390 | |||
391 | convert_endian(&item, APETAG_ITEM_HEADER_FORMAT); | ||
392 | tag_remaining -= sizeof(item); | ||
393 | r = read_string(fd, name, sizeof(name), 0, tag_remaining); | ||
394 | |||
395 | if (r == -1) | ||
396 | { | ||
397 | return false; | ||
398 | } | ||
205 | 399 | ||
206 | /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ | 400 | tag_remaining -= r + item.length; |
207 | track->id3.length=(totalsamples/track->id3.frequency)*1000; | ||
208 | track->id3.bitrate=(filesize(fd)*8)/track->id3.length; | ||
209 | } else if ((buf[0]&0x7f)==4) { /* 4 is the VORBIS_COMMENT block */ | ||
210 | 401 | ||
211 | /* The next i bytes of the file contain the VORBIS COMMENTS - just skip them for now. */ | 402 | if ((item.flags & APETAG_ITEM_TYPE_MASK) == 0) |
212 | //lseek(fd, i, SEEK_CUR); | 403 | { |
213 | if (!get_vorbis_comments(&(track->id3), i, fd)) { | 404 | long len; |
214 | return false; | 405 | |
215 | } | 406 | if (read_string(fd, value, sizeof(value), -1, item.length) |
407 | != item.length) | ||
408 | { | ||
409 | return false; | ||
410 | } | ||
216 | 411 | ||
217 | } else { | 412 | convert_utf8(value); |
218 | if (buf[0]&0x80) { /* If we have reached the last metadata block, abort. */ | 413 | len = parse_tag(name, value, id3, buf, buf_remaining, |
219 | break; | 414 | TAGTYPE_APE); |
220 | } else { | 415 | buf += len; |
221 | lseek(fd, i, SEEK_CUR); /* Skip to next metadata block */ | 416 | buf_remaining -= len; |
222 | } | 417 | } |
418 | else | ||
419 | { | ||
420 | if (lseek(fd, item.length, SEEK_CUR) < 0) | ||
421 | { | ||
422 | return false; | ||
423 | } | ||
424 | } | ||
223 | } | 425 | } |
224 | } | 426 | } |
225 | |||
226 | lseek(fd, 0, SEEK_SET); | ||
227 | strncpy(track->id3.path,trackname,sizeof(track->id3.path)); | ||
228 | track->taginfo_ready = true; | ||
229 | break; | ||
230 | 427 | ||
231 | case AFMT_OGG_VORBIS: | 428 | return true; |
232 | /* A simple parser to read vital metadata from an Ogg Vorbis file */ | 429 | } |
233 | 430 | ||
234 | /* An Ogg File is split into pages, each starting with the string | 431 | /* Read the items in a Vorbis comment packet. Returns true the items were |
235 | "OggS". Each page has a timestamp (in PCM samples) referred to as | 432 | * fully read, false otherwise. |
236 | the "granule position". | 433 | */ |
434 | static bool read_vorbis_tags(int fd, struct mp3entry *id3, | ||
435 | long tag_remaining) | ||
436 | { | ||
437 | char *buf = id3->id3v2buf; | ||
438 | long comment_count; | ||
439 | long len; | ||
440 | int buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf); | ||
441 | int i; | ||
237 | 442 | ||
238 | An Ogg Vorbis has the following structure: | 443 | id3->genre = 255; |
239 | 1) Identification header (containing samplerate, numchannels, etc) | ||
240 | 2) Comment header - containing the Vorbis Comments | ||
241 | 3) Setup header - containing codec setup information | ||
242 | 4) Many audio packets... | ||
243 | 444 | ||
244 | */ | 445 | if (read(fd, &len, sizeof(len)) < (long) sizeof(len)) |
446 | { | ||
447 | return false; | ||
448 | } | ||
449 | |||
450 | convert_endian(&len, "L"); | ||
451 | |||
452 | if ((lseek(fd, len, SEEK_CUR) < 0) | ||
453 | || (read(fd, &comment_count, sizeof(comment_count)) | ||
454 | < (long) sizeof(comment_count))) | ||
455 | { | ||
456 | return false; | ||
457 | } | ||
458 | |||
459 | convert_endian(&comment_count, "L"); | ||
460 | tag_remaining -= len + sizeof(len) + sizeof(comment_count); | ||
245 | 461 | ||
246 | /* Use the trackname part of the id3 structure as a temporary buffer */ | 462 | if (tag_remaining <= 0) |
247 | buf=track->id3.path; | 463 | { |
464 | return true; | ||
465 | } | ||
248 | 466 | ||
249 | lseek(fd, 0, SEEK_SET); | 467 | for (i = 0; i < comment_count; i++) |
468 | { | ||
469 | char name[TAG_NAME_LENGTH]; | ||
470 | char value[TAG_VALUE_LENGTH]; | ||
471 | long read_len; | ||
250 | 472 | ||
251 | rc = read(fd, buf, 58); | 473 | if (tag_remaining < 4) |
252 | if (rc < 4) { | 474 | { |
253 | return false; | 475 | break; |
254 | } | ||
255 | |||
256 | if ((memcmp(buf,"OggS",4)!=0) || (memcmp(&buf[29],"vorbis",6)!=0)) { | ||
257 | logf("%s is not an Ogg Vorbis file\n",trackname); | ||
258 | return(false); | ||
259 | } | ||
260 | |||
261 | /* We need to ensure the serial number from this page is the | ||
262 | * same as the one from the last page (since we only support | ||
263 | * a single bitstream). | ||
264 | */ | ||
265 | serialno = buf[14]|(buf[15]<<8)|(buf[16]<<16)|(buf[17]<<24); | ||
266 | |||
267 | /* Ogg stores integers in little-endian format. */ | ||
268 | track->id3.filesize=filesize(fd); | ||
269 | track->id3.frequency=buf[40]|(buf[41]<<8)|(buf[42]<<16)|(buf[43]<<24); | ||
270 | channels=buf[39]; | ||
271 | |||
272 | /* Comments are in second Ogg page */ | ||
273 | if ( lseek(fd, 58, SEEK_SET) < 0 ) { | ||
274 | return false; | ||
275 | } | ||
276 | |||
277 | /* Minimum header length for Ogg pages is 27 */ | ||
278 | if (read(fd, buf, 27) < 27) { | ||
279 | return false; | ||
280 | } | ||
281 | |||
282 | if (memcmp(buf,"OggS",4)!=0) { | ||
283 | logf("1: Not an Ogg Vorbis file"); | ||
284 | return(false); | ||
285 | } | ||
286 | |||
287 | segments=buf[26]; | ||
288 | /* read in segment table */ | ||
289 | if (read(fd, buf, segments) < segments) { | ||
290 | return false; | ||
291 | } | ||
292 | |||
293 | /* The second packet in a vorbis stream is the comment packet. It *may* | ||
294 | * extend beyond the second page, but usually does not. Here we find the | ||
295 | * length of the comment packet (or the rest of the page if the comment | ||
296 | * packet extends to the third page). | ||
297 | */ | ||
298 | for (i = 0; i < segments; i++) { | ||
299 | bytes_remaining += buf[i]; | ||
300 | /* The last segment of a packet is always < 255 bytes */ | ||
301 | if (buf[i] < 255) { | ||
302 | break; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* Now read in packet header (type and id string) */ | ||
307 | if(read(fd, buf, 7) < 7) { | ||
308 | return false; | ||
309 | } | ||
310 | |||
311 | /* The first byte of a packet is the packet type; comment packets are | ||
312 | * type 3. | ||
313 | */ | ||
314 | if ((buf[0] != 3) || (memcmp(buf + 1,"vorbis",6)!=0)) { | ||
315 | logf("Not a vorbis comment packet"); | ||
316 | return false; | ||
317 | } | ||
318 | |||
319 | bytes_remaining -= 7; | ||
320 | |||
321 | if ( !get_vorbis_comments(&(track->id3), bytes_remaining, fd) ) { | ||
322 | logf("get_vorbis_comments failed"); | ||
323 | return(false); | ||
324 | } | ||
325 | |||
326 | /* We now need to search for the last page in the file - identified by | ||
327 | by ('O','g','g','S',0) and retrieve totalsamples */ | ||
328 | |||
329 | lseek(fd, -64*1024, SEEK_END); /* A page is always < 64 kB */ | ||
330 | eof=0; | ||
331 | j=0; /* The number of bytes currently in buffer */ | ||
332 | i=0; | ||
333 | totalsamples=0; | ||
334 | while (!eof) { | ||
335 | rc = read(fd, &buf[j], MAX_PATH-j); | ||
336 | if (rc <= 0) { | ||
337 | eof=1; | ||
338 | } else { | ||
339 | j+=rc; | ||
340 | } | 476 | } |
341 | /* Inefficient (but simple) search */ | ||
342 | i=0; | ||
343 | while (i < (j-5)) { | ||
344 | if (memcmp(&buf[i],"OggS",5)==0) { | ||
345 | if (i < (j-17)) { | ||
346 | /* Note that this only reads the low 32 bits of a 64 bit value */ | ||
347 | totalsamples=(buf[i+6])|(buf[i+7]<<8)|(buf[i+8]<<16)|(buf[i+9]<<24); | ||
348 | last_serialno=(buf[i+14])|(buf[i+15]<<8)|(buf[i+16]<<16)|(buf[i+17]<<24); | ||
349 | j=0; /* We can discard the rest of the buffer */ | ||
350 | } else { | ||
351 | break; | ||
352 | } | ||
353 | } else { | ||
354 | i++; | ||
355 | } | ||
356 | } | ||
357 | if (i < (j-5)) { | ||
358 | /* Move OggS to start of buffer */ | ||
359 | while(i>0) buf[i--]=buf[j--]; | ||
360 | } else { | ||
361 | j=0; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | /* This file has mutiple vorbis bitstreams (or is corrupt) */ | ||
366 | /* FIXME we should display an error here */ | ||
367 | if (serialno != last_serialno) { | ||
368 | track->taginfo_ready=false; | ||
369 | logf("serialno mismatch"); | ||
370 | logf("%ld", serialno); | ||
371 | logf("%ld", last_serialno); | ||
372 | return false; | ||
373 | } | ||
374 | |||
375 | track->id3.samples=totalsamples; | ||
376 | track->id3.length=(totalsamples/track->id3.frequency)*1000; | ||
377 | |||
378 | /* The following calculation should use datasize, not filesize (i.e. exclude comments etc) */ | ||
379 | track->id3.bitrate=(filesize(fd)*8)/track->id3.length; | ||
380 | track->id3.vbr=true; | ||
381 | |||
382 | lseek(fd, 0, SEEK_SET); | ||
383 | strncpy(track->id3.path,trackname,sizeof(track->id3.path)); | ||
384 | track->taginfo_ready = true; | ||
385 | break; | ||
386 | |||
387 | case AFMT_WAVPACK: | ||
388 | /* A simple parser to read basic information from a WavPack file. | ||
389 | * This will fail on WavPack files that don't have the WavPack header | ||
390 | * as the first thing (i.e. self-extracting WavPack files) or WavPack | ||
391 | * files that have so much extra RIFF data stored in the first block | ||
392 | * that they don't have samples (very rare, I would think). | ||
393 | */ | ||
394 | |||
395 | /* Use the trackname part of the id3 structure as a temporary buffer */ | ||
396 | buf=track->id3.path; | ||
397 | |||
398 | lseek(fd, 0, SEEK_SET); | ||
399 | |||
400 | rc = read(fd, buf, 32); | ||
401 | if (rc < 32) { | ||
402 | return false; | ||
403 | } | ||
404 | |||
405 | if (memcmp (buf, "wvpk", 4) != 0 || buf [9] != 4 || buf [8] < 2) { | ||
406 | logf ("%s is not a WavPack file\n", trackname); | ||
407 | return (false); | ||
408 | } | ||
409 | |||
410 | track->id3.vbr = true; /* All WavPack files are VBR */ | ||
411 | track->id3.filesize = filesize (fd); | ||
412 | |||
413 | if ((buf [20] | buf [21] | buf [22] | buf [23]) && | ||
414 | (buf [12] & buf [13] & buf [14] & buf [15]) != 0xff) { | ||
415 | int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14); | ||
416 | |||
417 | if (srindx == 15) | ||
418 | track->id3.frequency = 44100; | ||
419 | else | ||
420 | track->id3.frequency = wavpack_sample_rates [srindx]; | ||
421 | |||
422 | totalsamples = (buf[15] << 24) | (buf[14] << 16) | (buf[13] << 8) | buf[12]; | ||
423 | track->id3.length = totalsamples / (track->id3.frequency / 100) * 10; | ||
424 | track->id3.bitrate = filesize (fd) / | ||
425 | (track->id3.length / 8); | ||
426 | } | ||
427 | |||
428 | get_apetag_info (&track->id3, fd); /* use any apetag info we find */ | ||
429 | lseek (fd, 0, SEEK_SET); | ||
430 | strncpy (track->id3.path, trackname, sizeof (track->id3.path)); | ||
431 | track->taginfo_ready = true; | ||
432 | break; | ||
433 | |||
434 | case AFMT_A52: | ||
435 | /* Use the trackname part of the id3 structure as a temporary buffer */ | ||
436 | buf=track->id3.path; | ||
437 | |||
438 | lseek(fd, 0, SEEK_SET); | ||
439 | |||
440 | /* We just need the first 5 bytes */ | ||
441 | rc = read(fd, buf, 5); | ||
442 | if (rc < 5) { | ||
443 | return false; | ||
444 | } | ||
445 | 477 | ||
446 | if ((buf[0]!=0x0b) || (buf[1]!=0x77)) { | 478 | if (read(fd, &len, sizeof(len)) < (long) sizeof(len)) |
447 | logf("%s is not an A52/AC3 file\n",trackname); | 479 | { |
448 | return false; | 480 | return false; |
449 | } | 481 | } |
450 | 482 | ||
451 | i = buf[4]&0x3e; | 483 | convert_endian(&len, "L"); |
452 | if (i > 36) { | 484 | tag_remaining -= 4; |
453 | logf("A52: Invalid frmsizecod: %d\n",i); | ||
454 | return false; | ||
455 | } | ||
456 | track->id3.bitrate=a52_bitrates[i>>1]; | ||
457 | 485 | ||
458 | track->id3.vbr=false; | 486 | /* Quit if we've passed the end of the page */ |
459 | track->id3.filesize = filesize (fd); | 487 | if (tag_remaining < len) |
488 | { | ||
489 | break; | ||
490 | } | ||
460 | 491 | ||
461 | switch (buf[4]&0xc0) { | 492 | tag_remaining -= len; |
462 | case 0x00: | 493 | read_len = read_string(fd, name, sizeof(name), '=', len); |
463 | track->id3.frequency=48000; | 494 | |
464 | bytesperframe=track->id3.bitrate*2*2; | 495 | if (read_len < 0) |
465 | break; | 496 | { |
466 | case 0x40: | 497 | return false; |
467 | track->id3.frequency=44100; | 498 | } |
468 | bytesperframe=a52_441framesizes[i]; | ||
469 | break; | ||
470 | case 0x80: | ||
471 | track->id3.frequency=32000; | ||
472 | bytesperframe=track->id3.bitrate*3*2; | ||
473 | break; | ||
474 | default: | ||
475 | logf("A52: Invalid samplerate code: 0x%02x\n",buf[4]&0xc0); | ||
476 | return false; | ||
477 | break; | ||
478 | } | ||
479 | 499 | ||
480 | /* One A52 frame contains 6 blocks, each containing 256 samples */ | 500 | len -= read_len; |
481 | totalsamples=(track->filesize/bytesperframe)*6*256; | ||
482 | 501 | ||
483 | track->id3.length=(totalsamples/track->id3.frequency)*1000; | 502 | if (read_string(fd, value, sizeof(value), -1, len) < 0) |
503 | { | ||
504 | return false; | ||
505 | } | ||
484 | 506 | ||
485 | lseek(fd, 0, SEEK_SET); | 507 | convert_utf8(value); |
486 | strncpy(track->id3.path,trackname,sizeof(track->id3.path)); | 508 | len = parse_tag(name, value, id3, buf, buf_remaining, |
487 | track->taginfo_ready = true; | 509 | TAGTYPE_VORBIS); |
488 | break; | 510 | buf += len; |
511 | buf_remaining -= len; | ||
512 | } | ||
489 | 513 | ||
490 | /* If we don't know how to read the metadata, just store the filename */ | 514 | /* Skip to the end of the block */ |
491 | default: | 515 | if (tag_remaining) |
492 | strncpy(track->id3.path,trackname,sizeof(track->id3.path)); | 516 | { |
493 | track->taginfo_ready = true; | 517 | if (lseek(fd, tag_remaining, SEEK_CUR) < 0) |
494 | break; | 518 | { |
495 | } | 519 | return false; |
520 | } | ||
521 | } | ||
496 | 522 | ||
497 | return true; | 523 | return true; |
498 | } | 524 | } |
499 | 525 | ||
500 | /************************* APE TAG HANDLING CODE ****************************/ | 526 | /* A simple parser to read vital metadata from an Ogg Vorbis file. Returns |
501 | 527 | * false if metadata needed by the Vorbis codec couldn't be read. | |
502 | /* | ||
503 | * This is a first pass at APEv2 tag handling. I'm not sure if this should | ||
504 | * reside here, but I wanted to modify as little as possible since I don't | ||
505 | * have a feel for the complete system. It may be that APEv2 tags should be | ||
506 | * added to the ID3 handling code in the firmware directory. APEv2 tags are | ||
507 | * used in WavPack files and Musepack files by default, however they are | ||
508 | * also used in MP3 files sometimes (by Foobar2000). Also, WavPack files can | ||
509 | * also use ID3v1 tags (but not ID3v2), so it seems like some universal tag | ||
510 | * handler might be a reasonable approach. | ||
511 | * | ||
512 | * This code does not currently handle APEv1 tags, but I believe that this | ||
513 | * is not a problem because they were only used in Monkey's Audio files which | ||
514 | * will probably never be playable in RockBox (and certainly not by this CPU). | ||
515 | */ | 528 | */ |
516 | 529 | static bool get_vorbis_metadata(int fd, struct mp3entry* id3) | |
517 | #define APETAG_HEADER_FORMAT "8LLLL" | ||
518 | #define APETAG_HEADER_LENGTH 32 | ||
519 | #define APETAG_DATA_LIMIT 4096 | ||
520 | |||
521 | struct apetag_header { | ||
522 | char id [8]; | ||
523 | long version, length, item_count, flags; | ||
524 | char res [8]; | ||
525 | }; | ||
526 | |||
527 | static struct apetag { | ||
528 | struct apetag_header header; | ||
529 | char data [APETAG_DATA_LIMIT]; | ||
530 | } temp_apetag; | ||
531 | |||
532 | static int get_apetag_item (struct apetag *tag, | ||
533 | const char *item, | ||
534 | char *value, | ||
535 | int size); | ||
536 | |||
537 | static int load_apetag (int fd, struct apetag *tag); | ||
538 | static void UTF8ToAnsi (unsigned char *pUTF8); | ||
539 | |||
540 | /* | ||
541 | * This function searches the specified file for an APEv2 tag and uses any | ||
542 | * information found there to populate the appropriate fields in the specified | ||
543 | * mp3entry structure. A temporary buffer is used to hold the tag during this | ||
544 | * operation. For now, the actual string data that needs to be held during the | ||
545 | * life of the track entry is stored in the "id3v2buf" field (which should not | ||
546 | * be used for any file that has an APEv2 tag). This limits the total space | ||
547 | * for the artist, title, album, composer and genre strings to 300 characters. | ||
548 | */ | ||
549 | |||
550 | static bool get_apetag_info (struct mp3entry *entry, int fd) | ||
551 | { | 530 | { |
552 | int rem_space = sizeof (entry->id3v2buf), str_space; | 531 | /* An Ogg File is split into pages, each starting with the string |
553 | char *temp_buffer = entry->id3v2buf; | 532 | * "OggS". Each page has a timestamp (in PCM samples) referred to as |
533 | * the "granule position". | ||
534 | * | ||
535 | * An Ogg Vorbis has the following structure: | ||
536 | * 1) Identification header (containing samplerate, numchannels, etc) | ||
537 | * 2) Comment header - containing the Vorbis Comments | ||
538 | * 3) Setup header - containing codec setup information | ||
539 | * 4) Many audio packets... | ||
540 | */ | ||
554 | 541 | ||
555 | if (rem_space <= 1 || !load_apetag (fd, &temp_apetag)) | 542 | /* Use the path name of the id3 structure as a temporary buffer. */ |
543 | unsigned char* buf = id3->path; | ||
544 | long comment_size; | ||
545 | long remaining = 0; | ||
546 | long last_serial = 0; | ||
547 | long serial; | ||
548 | int segments; | ||
549 | int i; | ||
550 | bool eof = false; | ||
551 | |||
552 | if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 58) < 4)) | ||
553 | { | ||
556 | return false; | 554 | return false; |
555 | } | ||
556 | |||
557 | if ((memcmp(buf, "OggS", 4) != 0) || (memcmp(&buf[29], "vorbis", 6) != 0)) | ||
558 | { | ||
559 | return false; | ||
560 | } | ||
561 | |||
562 | /* We need to ensure the serial number from this page is the same as the | ||
563 | * one from the last page (since we only support a single bitstream). | ||
564 | */ | ||
565 | serial = get_long(&buf[14]); | ||
566 | id3->frequency = get_long(&buf[40]); | ||
567 | id3->filesize = filesize(fd); | ||
557 | 568 | ||
558 | if (get_apetag_item (&temp_apetag, "year", temp_buffer, rem_space)) | 569 | /* Comments are in second Ogg page */ |
559 | entry->year = atoi (temp_buffer); | 570 | if (lseek(fd, 58, SEEK_SET) < 0) |
560 | 571 | { | |
561 | if (get_apetag_item (&temp_apetag, "track", temp_buffer, rem_space)) | 572 | return false; |
562 | entry->tracknum = atoi (temp_buffer); | ||
563 | |||
564 | if (get_apetag_item (&temp_apetag, "replaygain_track_peak", temp_buffer, rem_space)) | ||
565 | entry->track_peak = get_replaypeak (temp_buffer); | ||
566 | |||
567 | if (get_apetag_item (&temp_apetag, "replaygain_album_peak", temp_buffer, rem_space)) | ||
568 | entry->album_peak = get_replaypeak (temp_buffer); | ||
569 | |||
570 | if (rem_space > 1 && | ||
571 | get_apetag_item (&temp_apetag, "replaygain_track_gain", temp_buffer, rem_space)) { | ||
572 | entry->track_gain = get_replaygain (entry->track_gain_string = temp_buffer); | ||
573 | str_space = strlen (temp_buffer) + 1; | ||
574 | temp_buffer += str_space; | ||
575 | rem_space -= str_space; | ||
576 | } | 573 | } |
577 | 574 | ||
578 | if (rem_space > 1 && | 575 | /* Minimum header length for Ogg pages is 27. */ |
579 | get_apetag_item (&temp_apetag, "replaygain_album_gain", temp_buffer, rem_space)) { | 576 | if (read(fd, buf, 27) < 27) |
580 | entry->album_gain = get_replaygain (entry->album_gain_string = temp_buffer); | 577 | { |
581 | str_space = strlen (temp_buffer) + 1; | 578 | return false; |
582 | temp_buffer += str_space; | ||
583 | rem_space -= str_space; | ||
584 | } | 579 | } |
585 | 580 | ||
586 | if (rem_space > 1 && | 581 | if (memcmp(buf, "OggS", 4) !=0 ) |
587 | get_apetag_item (&temp_apetag, "artist", temp_buffer, rem_space)) { | 582 | { |
588 | UTF8ToAnsi (entry->artist = temp_buffer); | 583 | return false; |
589 | str_space = strlen (temp_buffer) + 1; | ||
590 | temp_buffer += str_space; | ||
591 | rem_space -= str_space; | ||
592 | } | 584 | } |
593 | 585 | ||
594 | if (rem_space > 1 && | 586 | segments = buf[26]; |
595 | get_apetag_item (&temp_apetag, "title", temp_buffer, rem_space)) { | 587 | |
596 | UTF8ToAnsi (entry->title = temp_buffer); | 588 | /* read in segment table */ |
597 | str_space = strlen (temp_buffer) + 1; | 589 | if (read(fd, buf, segments) < segments) |
598 | temp_buffer += str_space; | 590 | { |
599 | rem_space -= str_space; | 591 | return false; |
600 | } | 592 | } |
601 | 593 | ||
602 | if (rem_space > 1 && | 594 | /* The second packet in a vorbis stream is the comment packet. It *may* |
603 | get_apetag_item (&temp_apetag, "album", temp_buffer, rem_space)) { | 595 | * extend beyond the second page, but usually does not. Here we find the |
604 | UTF8ToAnsi (entry->album = temp_buffer); | 596 | * length of the comment packet (or the rest of the page if the comment |
605 | str_space = strlen (temp_buffer) + 1; | 597 | * packet extends to the third page). |
606 | temp_buffer += str_space; | 598 | */ |
607 | rem_space -= str_space; | 599 | for (i = 0; i < segments; i++) |
600 | { | ||
601 | remaining += buf[i]; | ||
602 | |||
603 | /* The last segment of a packet is always < 255 bytes */ | ||
604 | if (buf[i] < 255) | ||
605 | { | ||
606 | break; | ||
607 | } | ||
608 | } | 608 | } |
609 | 609 | ||
610 | if (rem_space > 1 && | 610 | /* Now read in packet header (type and id string) */ |
611 | get_apetag_item (&temp_apetag, "genre", temp_buffer, rem_space)) { | 611 | if (read(fd, buf, 7) < 7) |
612 | UTF8ToAnsi (entry->genre_string = temp_buffer); | 612 | { |
613 | str_space = strlen (temp_buffer) + 1; | 613 | return false; |
614 | temp_buffer += str_space; | ||
615 | rem_space -= str_space; | ||
616 | } | 614 | } |
617 | 615 | ||
618 | if (rem_space > 1 && | 616 | comment_size = remaining; |
619 | get_apetag_item (&temp_apetag, "composer", temp_buffer, rem_space)) | 617 | remaining -= 7; |
620 | UTF8ToAnsi (entry->composer = temp_buffer); | ||
621 | 618 | ||
622 | return true; | 619 | /* The first byte of a packet is the packet type; comment packets are |
623 | } | 620 | * type 3. |
621 | */ | ||
622 | if ((buf[0] != 3) || (memcmp(buf + 1, "vorbis", 6) !=0)) | ||
623 | { | ||
624 | return false; | ||
625 | } | ||
624 | 626 | ||
625 | /* | 627 | /* Failure to read the tags isn't fatal. */ |
626 | * Helper function to convert little-endian structures to easily usable native | 628 | read_vorbis_tags(fd, id3, remaining); |
627 | * format using a format string (this does nothing on a little-endian machine). | ||
628 | */ | ||
629 | 629 | ||
630 | static void little_endian_to_native (void *data, char *format) | 630 | /* We now need to search for the last page in the file - identified by |
631 | { | 631 | * by ('O','g','g','S',0) and retrieve totalsamples. |
632 | unsigned char *cp = (unsigned char *) data; | 632 | */ |
633 | long temp; | ||
634 | |||
635 | while (*format) { | ||
636 | switch (*format) { | ||
637 | case 'L': | ||
638 | temp = cp [0] + ((long) cp [1] << 8) + ((long) cp [2] << 16) + ((long) cp [3] << 24); | ||
639 | * (long *) cp = temp; | ||
640 | cp += 4; | ||
641 | break; | ||
642 | 633 | ||
643 | case 'S': | 634 | if (lseek(fd, -64 * 1024, SEEK_END) < 0) /* A page is always < 64 kB */ |
644 | temp = cp [0] + (cp [1] << 8); | 635 | { |
645 | * (short *) cp = (short) temp; | 636 | return false; |
646 | cp += 2; | 637 | } |
647 | break; | ||
648 | 638 | ||
649 | default: | 639 | remaining = 0; |
650 | if (*format >= '0' && *format <= '9') | ||
651 | cp += *format - '0'; | ||
652 | 640 | ||
653 | break; | 641 | while (!eof) |
642 | { | ||
643 | long r = read(fd, &buf[remaining], MAX_PATH - remaining); | ||
644 | |||
645 | if (r <= 0) | ||
646 | { | ||
647 | eof = true; | ||
648 | } | ||
649 | else | ||
650 | { | ||
651 | remaining += r; | ||
652 | } | ||
653 | |||
654 | /* Inefficient (but simple) search */ | ||
655 | i = 0; | ||
656 | |||
657 | while (i < (remaining - 5)) | ||
658 | { | ||
659 | if ((buf[i] == 'O') && (memcmp(&buf[i], "OggS", 4) == 0)) | ||
660 | { | ||
661 | if (i < (remaining - 17)) | ||
662 | { | ||
663 | /* Note that this only reads the low 32 bits of a | ||
664 | * 64 bit value. | ||
665 | */ | ||
666 | id3->samples = get_long(&buf[i + 6]); | ||
667 | last_serial = get_long(&buf[i + 14]); | ||
668 | /* We can discard the rest of the buffer */ | ||
669 | remaining = 0; | ||
670 | } | ||
671 | else | ||
672 | { | ||
673 | break; | ||
674 | } | ||
675 | } | ||
676 | else | ||
677 | { | ||
678 | i++; | ||
679 | } | ||
654 | } | 680 | } |
655 | 681 | ||
656 | format++; | 682 | if (i < (remaining - 5)) |
683 | { | ||
684 | /* Move OggS to start of buffer. */ | ||
685 | while (i >0) | ||
686 | { | ||
687 | buf[i--] = buf[remaining--]; | ||
688 | } | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | remaining = 0; | ||
693 | } | ||
657 | } | 694 | } |
658 | } | ||
659 | |||
660 | /* | ||
661 | * Attempt to obtain the named string-type item from the specified APEv2 tag. | ||
662 | * The tag value will be copied to "value" (including an appended terminating | ||
663 | * NULL) and the length of the string (including the NULL) will be returned. | ||
664 | * If the data will not fit in the specified "size" then it will be truncated | ||
665 | * early (but still terminated). If the specified item is not found then 0 is | ||
666 | * returned and written to the first character of "value". If "value" is | ||
667 | * passed in as NULL, then the specified size is ignored and the actual size | ||
668 | * required to store the value is returned. | ||
669 | * | ||
670 | * Note that this function does not work on binary tag data; only UTF-8 | ||
671 | * encoded strings. However, numeric data (like ReplayGain) is usually stored | ||
672 | * as strings. | ||
673 | * | ||
674 | * Also, APEv2 tags may have multiple values for a given item and these will | ||
675 | * all be copied to "value" with NULL separators (this is why the total data | ||
676 | * size is returned). Of course, it is possible to ignore any additional | ||
677 | * values by simply using up to the first NULL. | ||
678 | */ | ||
679 | 695 | ||
680 | static int get_apetag_item (struct apetag *tag, | 696 | /* This file has mutiple vorbis bitstreams (or is corrupt). */ |
681 | const char *item, | 697 | /* FIXME we should display an error here. */ |
682 | char *value, | 698 | if (serial != last_serial) |
683 | int size) | 699 | { |
684 | { | 700 | logf("serialno mismatch"); |
685 | if (value && size) | 701 | logf("%ld", serial); |
686 | *value = 0; | 702 | logf("%ld", last_serial); |
687 | 703 | return false; | |
688 | if (tag->header.id [0] == 'A') { | 704 | } |
689 | char *p = tag->data; | ||
690 | char *q = p + tag->header.length - APETAG_HEADER_LENGTH; | ||
691 | int i; | ||
692 | 705 | ||
693 | for (i = 0; i < tag->header.item_count; ++i) { | 706 | id3->length = (id3->samples / id3->frequency) * 1000; |
694 | int vsize, flags, isize; | 707 | id3->bitrate = (((int64_t) id3->filesize - comment_size) * 8) / id3->length; |
708 | id3->vbr = true; | ||
709 | |||
710 | return true; | ||
711 | } | ||
695 | 712 | ||
696 | vsize = * (long *) p; p += 4; | 713 | static bool get_flac_metadata(int fd, struct mp3entry* id3) |
697 | flags = * (long *) p; p += 4; | 714 | { |
698 | isize = strlen (p); | 715 | /* A simple parser to read vital metadata from a FLAC file - length, |
716 | * frequency, bitrate etc. This code should either be moved to a | ||
717 | * seperate file, or discarded in favour of the libFLAC code. | ||
718 | * The FLAC stream specification can be found at | ||
719 | * http://flac.sourceforge.net/format.html#stream | ||
720 | */ | ||
699 | 721 | ||
700 | little_endian_to_native (&vsize, "L"); | 722 | /* Use the trackname part of the id3 structure as a temporary buffer */ |
701 | little_endian_to_native (&flags, "L"); | 723 | unsigned char* buf = id3->path; |
724 | bool rc = false; | ||
702 | 725 | ||
703 | if (p + isize + vsize + 1 > q) | 726 | if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 4) < 4)) |
704 | break; | 727 | { |
728 | return rc; | ||
729 | } | ||
705 | 730 | ||
706 | if (isize && vsize && !stricmp (item, p) && !(flags & 6)) { | 731 | if (memcmp(buf,"fLaC",4) != 0) |
732 | { | ||
733 | return rc; | ||
734 | } | ||
707 | 735 | ||
708 | if (value) { | 736 | while (true) |
709 | if (vsize + 1 > size) | 737 | { |
710 | vsize = size - 1; | 738 | long i; |
739 | |||
740 | if (read(fd, buf, 4) < 0) | ||
741 | { | ||
742 | return rc; | ||
743 | } | ||
744 | |||
745 | /* The length of the block */ | ||
746 | i = (buf[1] << 16) | (buf[2] << 8) | buf[3]; | ||
711 | 747 | ||
712 | memcpy (value, p + isize + 1, vsize); | 748 | if ((buf[0] & 0x7f) == 0) /* 0 is the STREAMINFO block */ |
713 | value [vsize] = 0; | 749 | { |
714 | } | 750 | unsigned long totalsamples; |
715 | 751 | ||
716 | return vsize + 1; | 752 | /* FIXME: Don't trust the value of i */ |
753 | if (read(fd, buf, i) < 0) | ||
754 | { | ||
755 | return rc; | ||
756 | } | ||
757 | |||
758 | id3->vbr = true; /* All FLAC files are VBR */ | ||
759 | id3->filesize = filesize(fd); | ||
760 | id3->frequency = (buf[10] << 12) | (buf[11] << 4) | ||
761 | | ((buf[12] & 0xf0) >> 4); | ||
762 | rc = true; /* Got vital metadata */ | ||
763 | |||
764 | /* totalsamples is a 36-bit field, but we assume <= 32 bits are used */ | ||
765 | totalsamples = (buf[14] << 24) | (buf[15] << 16) | ||
766 | | (buf[16] << 8) | buf[17]; | ||
767 | |||
768 | /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ | ||
769 | id3->length = (totalsamples / id3->frequency) * 1000; | ||
770 | id3->bitrate = (id3->filesize * 8) / id3->length; | ||
771 | } | ||
772 | else if ((buf[0] & 0x7f) == 4) /* 4 is the VORBIS_COMMENT block */ | ||
773 | { | ||
774 | /* The next i bytes of the file contain the VORBIS COMMENTS. */ | ||
775 | if (!read_vorbis_tags(fd, id3, i)) | ||
776 | { | ||
777 | return rc; | ||
778 | } | ||
779 | } | ||
780 | else | ||
781 | { | ||
782 | if (buf[0] & 0x80) | ||
783 | { | ||
784 | /* If we have reached the last metadata block, abort. */ | ||
785 | break; | ||
717 | } | 786 | } |
718 | else | 787 | else |
719 | p += isize + vsize + 1; | 788 | { |
789 | /* Skip to next metadata block */ | ||
790 | if (lseek(fd, i, SEEK_CUR) < 0) | ||
791 | { | ||
792 | return rc; | ||
793 | } | ||
794 | } | ||
720 | } | 795 | } |
721 | } | 796 | } |
722 | 797 | ||
723 | return 0; | 798 | return true; |
724 | } | 799 | } |
725 | 800 | ||
726 | /* | 801 | /* Simple file type probing by looking at the filename extension. */ |
727 | * Attempt to load an APEv2 tag from the specified file into the specified | 802 | unsigned int probe_file_format(const char *filename) |
728 | * structure. If the APEv2 tag will not fit into the predefined data size, | ||
729 | * then the tag is not loaded. A return value of TRUE indicates success. | ||
730 | */ | ||
731 | |||
732 | static int load_apetag (int fd, struct apetag *tag) | ||
733 | { | 803 | { |
734 | if (lseek (fd, -APETAG_HEADER_LENGTH, SEEK_END) == -1 || | 804 | char *suffix; |
735 | read (fd, &tag->header, APETAG_HEADER_LENGTH) != APETAG_HEADER_LENGTH || | 805 | unsigned int i; |
736 | strncmp (tag->header.id, "APETAGEX", 8)) { | 806 | |
737 | tag->header.id [0] = 0; | 807 | suffix = strrchr(filename, '.'); |
738 | return false; | ||
739 | } | ||
740 | |||
741 | little_endian_to_native (&tag->header, APETAG_HEADER_FORMAT); | ||
742 | |||
743 | if (tag->header.version == 2000 && tag->header.item_count && | ||
744 | tag->header.length > APETAG_HEADER_LENGTH && | ||
745 | tag->header.length < APETAG_DATA_LIMIT) { | ||
746 | |||
747 | int data_size = tag->header.length - APETAG_HEADER_LENGTH; | ||
748 | 808 | ||
749 | if (lseek (fd, -tag->header.length, SEEK_END) == -1 || | 809 | if (suffix == NULL) |
750 | read (fd, tag->data, data_size) != data_size) { | 810 | { |
751 | tag->header.id [0] = 0; | 811 | return AFMT_UNKNOWN; |
752 | return false; | ||
753 | } | ||
754 | else | ||
755 | return true; | ||
756 | } | 812 | } |
813 | |||
814 | suffix += 1; | ||
757 | 815 | ||
758 | tag->header.id [0] = 0; | 816 | for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) |
759 | return false; | 817 | { |
818 | if (strcasecmp(suffix, formats[i].extension) == 0) | ||
819 | { | ||
820 | return formats[i].format; | ||
821 | } | ||
822 | } | ||
823 | |||
824 | return AFMT_UNKNOWN; | ||
760 | } | 825 | } |
761 | 826 | ||
762 | /* | 827 | /* Get metadata for track - return false if parsing showed problems with the |
763 | * This is a *VERY* boneheaded attempt to convert UTF-8 unicode character | 828 | * file that would prevent playback. |
764 | * strings to ANSI. It simply maps the 16-bit Unicode characters that are | ||
765 | * less than 0x100 directly to an 8-bit value, and turns all the rest into | ||
766 | * question marks. This can be done "in-place" because the resulting string | ||
767 | * can only get smaller. | ||
768 | */ | 829 | */ |
769 | 830 | bool get_metadata(struct track_info* track, int fd, const char* trackname, | |
770 | static void UTF8ToAnsi (unsigned char *pUTF8) | 831 | bool v1first) |
771 | { | 832 | { |
772 | unsigned char *pAnsi = pUTF8; | 833 | unsigned char* buf; |
773 | unsigned short widechar = 0; | 834 | unsigned long totalsamples; |
774 | int trail_bytes = 0; | 835 | unsigned long bytespersample; |
775 | 836 | unsigned long channels; | |
776 | while (*pUTF8) { | 837 | unsigned long bitspersample; |
777 | if (*pUTF8 & 0x80) { | 838 | unsigned long numbytes; |
778 | if (*pUTF8 & 0x40) { | 839 | int bytesperframe; |
779 | if (trail_bytes) { | 840 | int i; |
780 | trail_bytes = 0; | 841 | |
781 | *pAnsi++ = widechar < 0x100 ? widechar : '?'; | 842 | /* Load codec specific track tag information. */ |
782 | } | 843 | |
783 | else { | 844 | switch (track->id3.codectype) |
784 | char temp = *pUTF8; | 845 | { |
846 | case AFMT_MPA_L1: | ||
847 | case AFMT_MPA_L2: | ||
848 | case AFMT_MPA_L3: | ||
849 | if (mp3info(&track->id3, trackname, v1first)) | ||
850 | { | ||
851 | return false; | ||
852 | } | ||
785 | 853 | ||
786 | while (temp & 0x80) { | 854 | break; |
787 | trail_bytes++; | ||
788 | temp <<= 1; | ||
789 | } | ||
790 | 855 | ||
791 | widechar = temp >> trail_bytes--; | 856 | case AFMT_FLAC: |
792 | } | 857 | if (!get_flac_metadata(fd, &(track->id3))) |
793 | } | 858 | { |
794 | else if (trail_bytes) { | 859 | return false; |
795 | widechar = (widechar << 6) | (*pUTF8 & 0x3f); | 860 | } |
796 | 861 | ||
797 | if (!--trail_bytes) | 862 | break; |
798 | *pAnsi++ = widechar < 0x100 ? widechar : '?'; | 863 | |
799 | } | 864 | case AFMT_OGG_VORBIS: |
865 | if (!get_vorbis_metadata(fd, &(track->id3))) | ||
866 | { | ||
867 | return false; | ||
800 | } | 868 | } |
801 | else | ||
802 | *pAnsi++ = *pUTF8; | ||
803 | 869 | ||
804 | pUTF8++; | 870 | break; |
805 | } | ||
806 | 871 | ||
807 | *pAnsi = 0; | 872 | case AFMT_PCM_WAV: |
808 | } | 873 | /* Use the trackname part of the id3 structure as a temporary buffer */ |
874 | buf = track->id3.path; | ||
875 | |||
876 | if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 44) < 44)) | ||
877 | { | ||
878 | return false; | ||
879 | } | ||
809 | 880 | ||
810 | /* This function extracts the information stored in the Vorbis comment header | 881 | if ((memcmp(buf,"RIFF",4) !=0 ) |
811 | * and stores it in id3v2buf of the current track. Currently the combined | 882 | || (memcmp(&buf[8], "WAVEfmt", 7) !=0 )) |
812 | * lengths of title, genre, album, and artist must be no longer than 296 bytes | 883 | { |
813 | * (the remaining 4 bytes are the null bytes at the end of the strings). This | 884 | logf("Not a WAV: %s\n", trackname); |
814 | * is wrong, since vorbis comments can be up to 2^32 - 1 bytes long. In | 885 | return false; |
815 | * practice I don't think this limitation will cause a problem. | 886 | } |
816 | * | ||
817 | * According to the docs, a vorbis bitstream *must* have a comment packet even | ||
818 | * if that packet is empty. Therefore if this function returns false the | ||
819 | * bitstream is corrupt and shouldn't be used. | ||
820 | * | ||
821 | * Additionally, vorbis comments *may* take up more than one Ogg page, and this | ||
822 | * only looks at the first page of comments. | ||
823 | */ | ||
824 | static bool get_vorbis_comments (struct mp3entry *entry, size_t bytes_remaining, int fd) | ||
825 | { | ||
826 | int vendor_length; | ||
827 | int comment_count; | ||
828 | int comment_length; | ||
829 | int i = 0; | ||
830 | unsigned char temp[300]; | ||
831 | int buffer_remaining = sizeof(entry->id3v2buf) + sizeof(entry->id3v1buf); | ||
832 | char *buffer = entry->id3v2buf; | ||
833 | char **p = NULL; | ||
834 | |||
835 | /* We've read in all header info, now start reading comments */ | ||
836 | |||
837 | /* Set id3v1 genre to 255 (effectively 'none'), otherwise tracks | ||
838 | * without genre tags will show up as 'Blues' | ||
839 | */ | ||
840 | entry->genre=255; | ||
841 | 887 | ||
842 | if (read(fd, &vendor_length, 4) < 4) { | 888 | /* FIX: Correctly parse WAV header - we assume canonical |
843 | return false; | 889 | * 44-byte header |
844 | } | 890 | */ |
845 | little_endian_to_native(&vendor_length, "L"); | ||
846 | lseek(fd, vendor_length, SEEK_CUR); | ||
847 | 891 | ||
848 | if (read(fd, &comment_count, 4) < 4) { | 892 | bitspersample = buf[34]; |
849 | return false; | 893 | channels = buf[22]; |
850 | } | ||
851 | little_endian_to_native(&comment_count, "L"); | ||
852 | bytes_remaining -= (vendor_length + 8); | ||
853 | if ( bytes_remaining <= 0 ) { | ||
854 | return true; | ||
855 | } | ||
856 | 894 | ||
857 | for ( i = 0; i < comment_count; i++ ) { | 895 | if ((bitspersample != 16) || (channels != 2)) |
858 | int name_length = 0; | 896 | { |
897 | logf("Unsupported WAV - %d bps, %d channels\n", | ||
898 | bitspersample, channels); | ||
899 | return false; | ||
900 | } | ||
859 | 901 | ||
860 | if (bytes_remaining < 4) { | 902 | bytespersample = ((bitspersample / 8) * channels); |
861 | break; | 903 | numbytes = get_long(&buf[40]); |
904 | totalsamples = numbytes / bytespersample; | ||
905 | |||
906 | track->id3.vbr = false; /* All WAV files are CBR */ | ||
907 | track->id3.filesize = filesize(fd); | ||
908 | track->id3.frequency = get_long(&buf[24]); | ||
909 | |||
910 | /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ | ||
911 | track->id3.length = (totalsamples / track->id3.frequency) * 1000; | ||
912 | track->id3.bitrate = (track->id3.frequency * bytespersample) / (1000 / 8); | ||
913 | break; | ||
914 | |||
915 | case AFMT_WAVPACK: | ||
916 | /* A simple parser to read basic information from a WavPack file. | ||
917 | * This will fail on WavPack files that don't have the WavPack header | ||
918 | * as the first thing (i.e. self-extracting WavPack files) or WavPack | ||
919 | * files that have so much extra RIFF data stored in the first block | ||
920 | * that they don't have samples (very rare, I would think). | ||
921 | */ | ||
922 | |||
923 | /* Use the trackname part of the id3 structure as a temporary buffer */ | ||
924 | buf = track->id3.path; | ||
925 | |||
926 | if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 32) < 32)) | ||
927 | { | ||
928 | return false; | ||
862 | } | 929 | } |
863 | bytes_remaining -= 4; | ||
864 | 930 | ||
865 | if (read(fd, &comment_length, 4) < 4) { | 931 | if (memcmp (buf, "wvpk", 4) != 0 || buf [9] != 4 || buf [8] < 2) |
932 | { | ||
933 | logf ("%s is not a WavPack file\n", trackname); | ||
866 | return false; | 934 | return false; |
867 | } | 935 | } |
868 | 936 | ||
869 | little_endian_to_native(&comment_length, "L"); | 937 | track->id3.vbr = true; /* All WavPack files are VBR */ |
938 | track->id3.filesize = filesize (fd); | ||
870 | 939 | ||
871 | /* Quit if we've passed the end of the page */ | 940 | if ((buf [20] | buf [21] | buf [22] | buf [23]) && |
872 | if ( bytes_remaining < (unsigned)comment_length ) { | 941 | (buf [12] & buf [13] & buf [14] & buf [15]) != 0xff) |
873 | break; | 942 | { |
943 | int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14); | ||
944 | |||
945 | if (srindx == 15) | ||
946 | { | ||
947 | track->id3.frequency = 44100; | ||
948 | } | ||
949 | else | ||
950 | { | ||
951 | track->id3.frequency = wavpack_sample_rates[srindx]; | ||
952 | } | ||
953 | |||
954 | totalsamples = get_long(&buf[12]); | ||
955 | track->id3.length = totalsamples / (track->id3.frequency / 100) * 10; | ||
956 | track->id3.bitrate = filesize (fd) / (track->id3.length / 8); | ||
874 | } | 957 | } |
875 | bytes_remaining -= (comment_length); | ||
876 | 958 | ||
877 | /* Skip comment if it won't fit in buffer */ | 959 | read_ape_tags(fd, &track->id3); /* use any apetag info we find */ |
878 | if ( (unsigned int)comment_length >= sizeof(temp) ) { | 960 | break; |
879 | lseek(fd, comment_length, SEEK_CUR); | 961 | |
880 | continue; | 962 | case AFMT_A52: |
963 | /* Use the trackname part of the id3 structure as a temporary buffer */ | ||
964 | buf = track->id3.path; | ||
965 | |||
966 | if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 5) < 5)) | ||
967 | { | ||
968 | return false; | ||
881 | } | 969 | } |
882 | 970 | ||
883 | if ( read(fd, temp, comment_length) < comment_length ) { | 971 | if ((buf[0] != 0x0b) || (buf[1] != 0x77)) |
972 | { | ||
973 | logf("%s is not an A52/AC3 file\n",trackname); | ||
884 | return false; | 974 | return false; |
885 | } | 975 | } |
886 | 976 | ||
887 | temp[comment_length] = '\0'; | 977 | i = buf[4] & 0x3e; |
888 | UTF8ToAnsi(temp); | 978 | |
889 | comment_length = strlen(temp); | 979 | if (i > 36) |
890 | 980 | { | |
891 | if (strncasecmp(temp, "TITLE=", 6) == 0) { | 981 | logf("A52: Invalid frmsizecod: %d\n",i); |
892 | name_length = 5; | 982 | return false; |
893 | p = &(entry->title); | ||
894 | } else if (strncasecmp(temp, "ALBUM=", 6) == 0) { | ||
895 | name_length = 5; | ||
896 | p = &(entry->album); | ||
897 | } else if (strncasecmp(temp, "ARTIST=", 7) == 0) { | ||
898 | name_length = 6; | ||
899 | p = &(entry->artist); | ||
900 | } else if (strncasecmp(temp, "COMPOSER=", 9) == 0) { | ||
901 | name_length = 8; | ||
902 | p = &(entry->composer); | ||
903 | } else if (strncasecmp(temp, "GENRE=", 6) == 0) { | ||
904 | name_length = 5; | ||
905 | p = &(entry->genre_string); | ||
906 | } else if (strncasecmp(temp, "DATE=", 5) == 0) { | ||
907 | name_length = 4; | ||
908 | p = &(entry->year_string); | ||
909 | } else if (strncasecmp(temp, "TRACKNUMBER=", 12) == 0) { | ||
910 | name_length = 11; | ||
911 | p = &(entry->track_string); | ||
912 | } else { | ||
913 | int value_length = parse_replaygain(temp, NULL, entry, buffer, | ||
914 | buffer_remaining); | ||
915 | buffer_remaining -= value_length; | ||
916 | buffer += value_length; | ||
917 | p = NULL; | ||
918 | } | ||
919 | |||
920 | if (p) { | ||
921 | comment_length -= (name_length + 1); | ||
922 | if ( comment_length < buffer_remaining ) { | ||
923 | strncpy(buffer, temp + name_length + 1, comment_length); | ||
924 | buffer[comment_length] = '\0'; | ||
925 | *p = buffer; | ||
926 | buffer += comment_length + 1; | ||
927 | buffer_remaining -= comment_length + 1; | ||
928 | } | ||
929 | } | 983 | } |
930 | } | 984 | |
985 | track->id3.bitrate = a52_bitrates[i >> 1]; | ||
986 | track->id3.vbr = false; | ||
987 | track->id3.filesize = filesize(fd); | ||
931 | 988 | ||
932 | /* Skip to the end of the block */ | 989 | switch (buf[4] & 0xc0) |
933 | if (bytes_remaining) { | 990 | { |
934 | lseek(fd, bytes_remaining, SEEK_CUR); | 991 | case 0x00: |
992 | track->id3.frequency = 48000; | ||
993 | bytesperframe=track->id3.bitrate * 2 * 2; | ||
994 | break; | ||
995 | |||
996 | case 0x40: | ||
997 | track->id3.frequency = 44100; | ||
998 | bytesperframe = a52_441framesizes[i]; | ||
999 | break; | ||
1000 | |||
1001 | case 0x80: | ||
1002 | track->id3.frequency = 32000; | ||
1003 | bytesperframe = track->id3.bitrate * 3 * 2; | ||
1004 | break; | ||
1005 | |||
1006 | default: | ||
1007 | logf("A52: Invalid samplerate code: 0x%02x\n", buf[4] & 0xc0); | ||
1008 | return false; | ||
1009 | break; | ||
1010 | } | ||
1011 | |||
1012 | /* One A52 frame contains 6 blocks, each containing 256 samples */ | ||
1013 | totalsamples = (track->filesize / bytesperframe) * 6 * 256; | ||
1014 | track->id3.length = (totalsamples / track->id3.frequency) * 1000; | ||
1015 | break; | ||
1016 | |||
1017 | /* If we don't know how to read the metadata, just store the filename */ | ||
1018 | default: | ||
1019 | break; | ||
935 | } | 1020 | } |
936 | 1021 | ||
1022 | lseek(fd, 0, SEEK_SET); | ||
1023 | strncpy(track->id3.path, trackname, sizeof(track->id3.path)); | ||
1024 | track->taginfo_ready = true; | ||
1025 | |||
937 | return true; | 1026 | return true; |
938 | } | 1027 | } |