summaryrefslogtreecommitdiff
path: root/apps/metadata/wave.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/metadata/wave.c')
-rw-r--r--apps/metadata/wave.c146
1 files changed, 127 insertions, 19 deletions
diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c
index 79bb8178bd..8fe755735d 100644
--- a/apps/metadata/wave.c
+++ b/apps/metadata/wave.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2005 Dave Chapman 10 * Copyright (C) 2005 Dave Chapman
11 * Copyright (C) 2010 Yoshihisa Uchida
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -41,6 +42,15 @@
41 ((uint8_t*)(p))[1] = (d)>>8; \ 42 ((uint8_t*)(p))[1] = (d)>>8; \
42 } while(0) 43 } while(0)
43 44
45/* Wave(RIFF)/Wave64 format */
46
47/* Wave64 GUIDs */
48#define WAVE64_GUID_RIFF "riff\x2e\x91\xcf\x11\xa5\xd6\x28\xdb\x04\xc1\x00\x00"
49#define WAVE64_GUID_WAVE "wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
50#define WAVE64_GUID_FMT "fmt \xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
51#define WAVE64_GUID_FACT "fact\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
52#define WAVE64_GUID_DATA "data\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
53
44enum 54enum
45{ 55{
46 WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */ 56 WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */
@@ -64,7 +74,7 @@ struct wave_fmt {
64 unsigned int blockalign; 74 unsigned int blockalign;
65 unsigned long bitspersample; 75 unsigned long bitspersample;
66 unsigned int samplesperblock; 76 unsigned int samplesperblock;
67 unsigned long numbytes; 77 uint64_t numbytes;
68}; 78};
69 79
70static unsigned long get_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3) 80static unsigned long get_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3)
@@ -114,6 +124,28 @@ static unsigned long get_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3
114 return totalsamples; 124 return totalsamples;
115} 125}
116 126
127static void parse_riff_format(unsigned char* buf, int fmtsize, struct wave_fmt *fmt,
128 struct mp3entry* id3)
129{
130 /* wFormatTag */
131 fmt->formattag = buf[0] | (buf[1] << 8);
132 /* wChannels */
133 fmt->channels = buf[2] | (buf[3] << 8);
134 /* dwSamplesPerSec */
135 id3->frequency = get_long_le(&buf[4]);
136 /* dwAvgBytesPerSec */
137 id3->bitrate = (get_long_le(&buf[8]) * 8) / 1000;
138 /* wBlockAlign */
139 fmt->blockalign = buf[12] | (buf[13] << 8);
140 /* wBitsPerSample */
141 fmt->bitspersample = buf[14] | (buf[15] << 8);
142 if (fmtsize > 19)
143 {
144 /* wSamplesPerBlock */
145 fmt->samplesperblock = buf[18] | (buf[19] << 8);
146 }
147}
148
117bool get_wave_metadata(int fd, struct mp3entry* id3) 149bool get_wave_metadata(int fd, struct mp3entry* id3)
118{ 150{
119 /* Use the trackname part of the id3 structure as a temporary buffer */ 151 /* Use the trackname part of the id3 structure as a temporary buffer */
@@ -166,24 +198,7 @@ bool get_wave_metadata(int fd, struct mp3entry* id3)
166 offset += read_bytes; 198 offset += read_bytes;
167 i -= read_bytes; 199 i -= read_bytes;
168 200
169 /* wFormatTag */ 201 parse_riff_format(buf, i, &fmt, id3);
170 fmt.formattag = buf[0] | (buf[1] << 8);
171 /* wChannels */
172 fmt.channels = buf[2] | (buf[3] << 8);
173 /* dwSamplesPerSec */
174 id3->frequency = get_long_le(&buf[4]);
175 /* dwAvgBytesPerSec */
176 id3->bitrate = (get_long_le(&buf[8]) * 8) / 1000;
177 /* wBlockAlign */
178 fmt.blockalign = buf[12] | (buf[13] << 8);
179 id3->bytesperframe = fmt.blockalign;
180 /* wBitsPerSample */
181 fmt.bitspersample = buf[14] | (buf[15] << 8);
182 if (read_bytes > 19)
183 {
184 /* wSamplesPerBlock */
185 fmt.samplesperblock = buf[18] | (buf[19] << 8);
186 }
187 202
188 /* Check for ATRAC3 stream */ 203 /* Check for ATRAC3 stream */
189 if (fmt.formattag == WAVE_FORMAT_ATRAC3) 204 if (fmt.formattag == WAVE_FORMAT_ATRAC3)
@@ -256,3 +271,96 @@ bool get_wave_metadata(int fd, struct mp3entry* id3)
256 271
257 return true; 272 return true;
258} 273}
274
275bool get_wave64_metadata(int fd, struct mp3entry* id3)
276{
277 /* Use the trackname part of the id3 structure as a temporary buffer */
278 unsigned char* buf = (unsigned char *)id3->path;
279 struct wave_fmt fmt;
280 unsigned long totalsamples = 0;
281 int read_bytes;
282 uint64_t i;
283
284 memset(&fmt, 0, sizeof(struct wave_fmt));
285
286 /* get RIFF chunk header */
287 if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 40) < 40))
288 return false;
289
290 if ((memcmp(buf , WAVE64_GUID_RIFF, 16) != 0)||
291 (memcmp(buf+24, WAVE64_GUID_WAVE, 16) != 0))
292 {
293 DEBUGF("metada error: does not wave64 file\n");
294 return false;
295 }
296
297 /* iterate over WAVE chunks until 'data' chunk */
298 while (true)
299 {
300 /* get chunk header */
301 if (read(fd, buf, 24) < 24)
302 return false;
303
304 /* chunkSize (excludes GUID and size length) */
305 i = get_uint64_le(&buf[16]) - 24;
306
307 if (memcmp(buf, WAVE64_GUID_FMT, 16) == 0)
308 {
309 DEBUGF("find 'fmt ' chunk\n");
310 if (i < 16)
311 return false;
312
313 read_bytes = 16;
314 if (i > 16)
315 {
316 read_bytes = 24;
317 if (i < 24)
318 i = 24;
319 }
320
321 /* get rest of chunk */
322 if (read(fd, buf, read_bytes) < read_bytes)
323 return false;
324
325 i -= read_bytes;
326 parse_riff_format(buf, read_bytes, &fmt, id3);
327 }
328 else if (memcmp(buf, WAVE64_GUID_DATA, 16) == 0)
329 {
330 DEBUGF("find 'data' chunk\n");
331 fmt.numbytes = i;
332 break;
333 }
334 else if (memcmp(buf, WAVE64_GUID_FACT, 16) == 0)
335 {
336 /* Skip 'fact' chunk */
337 DEBUGF("find 'fact' chunk\n");
338 }
339
340 /* seek to next chunk (8byte bound) */
341 if (i & 0x07)
342 i += 8 - (i & 0x7);
343
344 if(lseek(fd, i, SEEK_CUR) < 0)
345 return false;
346 }
347
348 if ((fmt.numbytes == 0) || (fmt.channels == 0) || (fmt.blockalign == 0))
349 {
350 DEBUGF("metadata error: numbytes, channels, or blockalign is 0\n");
351 return false;
352 }
353
354 if (totalsamples == 0)
355 {
356 totalsamples = get_totalsamples(&fmt, id3);
357 }
358
359 id3->vbr = false; /* All Wave64 files are CBR */
360 id3->filesize = filesize(fd);
361
362 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */
363 id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
364
365 return true;
366}