summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoshihisa Uchida <uchida@rockbox.org>2010-05-08 12:15:15 +0000
committerYoshihisa Uchida <uchida@rockbox.org>2010-05-08 12:15:15 +0000
commit35808b70d5b466e975967727fb501e9d0db40194 (patch)
tree963953da982e21a726365dcfbf9148931abdb7e5
parent04afc139efde9ca8f1be995762b5abe581d46ef9 (diff)
downloadrockbox-35808b70d5b466e975967727fb501e9d0db40194.tar.gz
rockbox-35808b70d5b466e975967727fb501e9d0db40194.zip
wave/wave64: parse LIST chunk.
Then, title, artist, etc. (in LIST chunk data) are displayed. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25898 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/metadata/wave.c192
1 files changed, 166 insertions, 26 deletions
diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c
index eeb4f0f343..cbf628a599 100644
--- a/apps/metadata/wave.c
+++ b/apps/metadata/wave.c
@@ -27,6 +27,7 @@
27#include "metadata.h" 27#include "metadata.h"
28#include "metadata_common.h" 28#include "metadata_common.h"
29#include "metadata_parsers.h" 29#include "metadata_parsers.h"
30#include "rbunicode.h"
30#include "logf.h" 31#include "logf.h"
31 32
32/* Wave(RIFF)/Wave64 format */ 33/* Wave(RIFF)/Wave64 format */
@@ -49,6 +50,7 @@ enum {
49 FMT_CHUNK, 50 FMT_CHUNK,
50 FACT_CHUNK, 51 FACT_CHUNK,
51 DATA_CHUNK, 52 DATA_CHUNK,
53 LIST_CHUNK,
52}; 54};
53 55
54/* Wave chunk names */ 56/* Wave chunk names */
@@ -59,7 +61,8 @@ static const unsigned char *wave_chunklist = "RIFF"
59 "WAVE" 61 "WAVE"
60 "fmt " 62 "fmt "
61 "fact" 63 "fact"
62 "data"; 64 "data"
65 "LIST";
63 66
64/* Wave64 GUIDs */ 67/* Wave64 GUIDs */
65#define WAVE64_CHUNKNAME_LENGTH 16 68#define WAVE64_CHUNKNAME_LENGTH 16
@@ -70,8 +73,38 @@ static const unsigned char *wave64_chunklist
70 "wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" 73 "wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
71 "fmt \xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" 74 "fmt \xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
72 "fact\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" 75 "fact\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
73 "data\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"; 76 "data\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
77 "\xbc\x94\x5f\x92\x5a\x52\xd2\x11\x86\xdc\x00\xc0\x4f\x8e\xdb\x8a";
74 78
79enum {
80 INFO_TITLE = 0,
81 INFO_ARTIST,
82 INFO_ALBUM_ARTIST,
83 INFO_ALBUM,
84 INFO_COMPOSER,
85 INFO_COMMENT,
86 INFO_GROUPING,
87 INFO_GENRE,
88 INFO_DATE,
89 INFO_TRACK,
90 INFO_DISC,
91};
92
93/* info chunk names are common wave/wave64 */
94static const unsigned char infochunk_list[][4]
95 = {
96 "INAM", /* title */
97 "IART", /* artist */
98 "ISBJ", /* albumartist */
99 "IPRD", /* album */
100 "IWRI", /* composer */
101 "ICMT", /* comment */
102 "ISRF", /* grouping */
103 "IGNR", /* genre */
104 "ICRD", /* date */
105 "IPRT", /* track/trackcount */
106 "IFRM", /* disc/disccount */
107 };
75 108
76/* support formats */ 109/* support formats */
77enum 110enum
@@ -102,6 +135,19 @@ struct wave_fmt {
102 uint64_t numbytes; 135 uint64_t numbytes;
103}; 136};
104 137
138static unsigned char *convert_utf8(unsigned char *src, unsigned char *dst,
139 int datasize, int bufsize, bool is_64)
140{
141 int size = (datasize > bufsize)? bufsize : datasize;
142
143 if (is_64)
144 {
145 /* Note: wave64: metadata codepage is UTF-16 only */
146 return utf16LEdecode(src, dst, size);
147 }
148 return iso_decode(src, dst, -1, size);
149}
150
105static void set_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3) 151static void set_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3)
106{ 152{
107 switch (fmt->formattag) 153 switch (fmt->formattag)
@@ -197,6 +243,94 @@ static void parse_riff_format(unsigned char* buf, int fmtsize, struct wave_fmt *
197 } 243 }
198} 244}
199 245
246static bool parse_list_chunk(int fd, struct mp3entry* id3, int chunksize, bool is_64)
247{
248 unsigned char tmpbuf[ID3V2_BUF_SIZE];
249 unsigned char *bp = tmpbuf;
250 unsigned char *endp;
251 unsigned char *data_pos;
252 unsigned char *curpos = id3->id3v2buf;
253 unsigned char *nextpos;
254 int datasize;
255 int infosize;
256 int remain = ID3V2_BUF_SIZE;
257
258 if (is_64)
259 lseek(fd, 4, SEEK_CUR);
260 else if (read(fd, bp, 4) < 4 || memcmp(bp, "INFO", 4))
261 return false;
262
263 infosize = read(fd, bp, (ID3V2_BUF_SIZE > chunksize)? chunksize : ID3V2_BUF_SIZE);
264 if (infosize <= 8)
265 return false;
266
267 endp = bp + infosize;
268 while (bp < endp)
269 {
270 nextpos = curpos;
271 datasize = get_long_le(bp + 4);
272 data_pos = bp + 8;
273 remain = ID3V2_BUF_SIZE - (curpos - (unsigned char*)id3->id3v2buf);
274 if (remain <= 0)
275 break;
276
277 if (memcmp(bp, infochunk_list[INFO_TITLE], 4) == 0)
278 {
279 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
280 id3->title = curpos;
281 }
282 else if (memcmp(bp, infochunk_list[INFO_ARTIST], 4) == 0)
283 {
284 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
285 id3->artist = curpos;
286 }
287 else if (memcmp(bp, infochunk_list[INFO_ALBUM_ARTIST], 4) == 0)
288 {
289 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
290 id3->albumartist = curpos;
291 }
292 else if (memcmp(bp, infochunk_list[INFO_COMPOSER], 4) == 0)
293 {
294 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
295 id3->composer = curpos;
296 }
297 else if (memcmp(bp, infochunk_list[INFO_COMMENT], 4) == 0)
298 {
299 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
300 id3->comment = curpos;
301 }
302 else if (memcmp(bp, infochunk_list[INFO_GROUPING], 4) == 0)
303 {
304 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
305 id3->grouping = curpos;
306 }
307 else if (memcmp(bp, infochunk_list[INFO_GENRE], 4) == 0)
308 {
309 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
310 id3->genre_string = curpos;
311 }
312 else if (memcmp(bp, infochunk_list[INFO_DATE], 4) == 0)
313 {
314 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
315 id3->year_string = curpos;
316 }
317 else if (memcmp(bp, infochunk_list[INFO_TRACK], 4) == 0)
318 {
319 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
320 id3->track_string = curpos;
321 }
322 else if (memcmp(bp, infochunk_list[INFO_DISC], 4) == 0)
323 {
324 nextpos = convert_utf8(data_pos, curpos, datasize, remain, is_64);
325 id3->disc_string = curpos;
326 }
327
328 bp = data_pos + datasize + (datasize & 1);
329 curpos = nextpos;
330 };
331 return true;
332}
333
200static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunknames, 334static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunknames,
201 bool is_64) 335 bool is_64)
202{ 336{
@@ -213,6 +347,9 @@ static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunk
213 int read_data; 347 int read_data;
214 348
215 memset(&fmt, 0, sizeof(struct wave_fmt)); 349 memset(&fmt, 0, sizeof(struct wave_fmt));
350
351 id3->vbr = false; /* All Wave/Wave64 files are CBR */
352 id3->filesize = filesize(fd);
216 353
217 /* get RIFF chunk header */ 354 /* get RIFF chunk header */
218 lseek(fd, 0, SEEK_SET); 355 lseek(fd, 0, SEEK_SET);
@@ -226,34 +363,14 @@ static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunk
226 } 363 }
227 364
228 /* iterate over WAVE chunks until 'data' chunk */ 365 /* iterate over WAVE chunks until 'data' chunk */
229 while (true) 366 while (read(fd, buf, len) > 0)
230 { 367 {
231 /* get chunk header */
232 if (read(fd, buf, len) <= 0)
233 {
234 DEBUGF("metadata error: read error or missing 'data' chunk.\n");
235 return false;
236 }
237
238 offset += len; 368 offset += len;
239 369
240 /* get chunk size (when the header is wave64, chunksize includes GUID and data length) */ 370 /* get chunk size (when the header is wave64, chunksize includes GUID and data length) */
241 chunksize = (is_64) ? get_uint64_le(buf + namelen) - len : 371 chunksize = (is_64) ? get_uint64_le(buf + namelen) - len :
242 get_long_le(buf + namelen); 372 get_long_le(buf + namelen);
243 373
244 if (memcmp(buf, chunknames + DATA_CHUNK * namelen, namelen) == 0)
245 {
246 DEBUGF("find 'data' chunk\n");
247 fmt.numbytes = chunksize;
248 if (fmt.formattag == WAVE_FORMAT_ATRAC3)
249 id3->first_frame_offset = offset;
250 break;
251 }
252
253 /* padded to next chunk */
254 chunksize += ((is_64)? ((1 + ~chunksize) & 0x07) : (chunksize & 1));
255 offset += chunksize;
256
257 read_data = 0; 374 read_data = 0;
258 if (memcmp(buf, chunknames + FMT_CHUNK * namelen, namelen) == 0) 375 if (memcmp(buf, chunknames + FMT_CHUNK * namelen, namelen) == 0)
259 { 376 {
@@ -284,10 +401,36 @@ static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunk
284 fmt.totalsamples = (is_64)? get_uint64_le(buf) : get_long_le(buf); 401 fmt.totalsamples = (is_64)? get_uint64_le(buf) : get_long_le(buf);
285 } 402 }
286 } 403 }
404 else if (memcmp(buf, chunknames + DATA_CHUNK * namelen, namelen) == 0)
405 {
406 DEBUGF("find 'data' chunk\n");
407 fmt.numbytes = chunksize;
408 if (fmt.formattag == WAVE_FORMAT_ATRAC3)
409 id3->first_frame_offset = offset;
410 }
411 else if (memcmp(buf, chunknames + LIST_CHUNK * namelen, namelen) == 0)
412 {
413 DEBUGF("find 'LIST' chunk\n");
414 parse_list_chunk(fd, id3, chunksize, is_64);
415 lseek(fd, offset, SEEK_SET);
416 }
417
418 /* padded to next chunk */
419 chunksize += ((is_64)? ((1 + ~chunksize) & 0x07) : (chunksize & 1));
420
421 offset += chunksize;
422 if (offset >= id3->filesize)
423 break;
287 424
288 lseek(fd, chunksize - read_data, SEEK_CUR); 425 lseek(fd, chunksize - read_data, SEEK_CUR);
289 } 426 }
290 427
428 if (fmt.numbytes == 0)
429 {
430 DEBUGF("metadata error: read error or missing 'data' chunk.\n");
431 return false;
432 }
433
291 if (fmt.totalsamples == 0) 434 if (fmt.totalsamples == 0)
292 set_totalsamples(&fmt, id3); 435 set_totalsamples(&fmt, id3);
293 436
@@ -297,9 +440,6 @@ static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunk
297 return false; 440 return false;
298 } 441 }
299 442
300 id3->vbr = false; /* All Wave/Wave64 files are CBR */
301 id3->filesize = filesize(fd);
302
303 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ 443 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */
304 id3->length = (fmt.formattag != WAVE_FORMAT_ATRAC3)? 444 id3->length = (fmt.formattag != WAVE_FORMAT_ATRAC3)?
305 (uint64_t)fmt.totalsamples * 1000 / id3->frequency : 445 (uint64_t)fmt.totalsamples * 1000 / id3->frequency :