diff options
Diffstat (limited to 'apps/metadata/wave.c')
-rw-r--r-- | apps/metadata/wave.c | 146 |
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 | |||
44 | enum | 54 | enum |
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 | ||
70 | static unsigned long get_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3) | 80 | static 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 | ||
127 | static 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 | |||
117 | bool get_wave_metadata(int fd, struct mp3entry* id3) | 149 | bool 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 | |||
275 | bool 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 | } | ||