diff options
author | Yoshihisa Uchida <uchida@rockbox.org> | 2010-03-10 10:55:01 +0000 |
---|---|---|
committer | Yoshihisa Uchida <uchida@rockbox.org> | 2010-03-10 10:55:01 +0000 |
commit | 207a84a3810a0a8916dc4adca7c8b3a9a4bfb929 (patch) | |
tree | 4c5938c6483344e6c613604eb19ae4d0835b457d | |
parent | 56069476be65da87604d7b006aee7008445b965f (diff) | |
download | rockbox-207a84a3810a0a8916dc4adca7c8b3a9a4bfb929.tar.gz rockbox-207a84a3810a0a8916dc4adca7c8b3a9a4bfb929.zip |
unify the wave/wave64 parser.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25106 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/metadata/wave.c | 363 |
1 files changed, 176 insertions, 187 deletions
diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c index c9291cbe54..c6bf4bdf53 100644 --- a/apps/metadata/wave.c +++ b/apps/metadata/wave.c | |||
@@ -31,6 +31,9 @@ | |||
31 | #include "metadata_parsers.h" | 31 | #include "metadata_parsers.h" |
32 | #include "logf.h" | 32 | #include "logf.h" |
33 | 33 | ||
34 | /* Wave(RIFF)/Wave64 format */ | ||
35 | |||
36 | |||
34 | # define AV_WL32(p, d) do { \ | 37 | # define AV_WL32(p, d) do { \ |
35 | ((uint8_t*)(p))[0] = (d); \ | 38 | ((uint8_t*)(p))[0] = (d); \ |
36 | ((uint8_t*)(p))[1] = (d)>>8; \ | 39 | ((uint8_t*)(p))[1] = (d)>>8; \ |
@@ -42,14 +45,36 @@ | |||
42 | ((uint8_t*)(p))[1] = (d)>>8; \ | 45 | ((uint8_t*)(p))[1] = (d)>>8; \ |
43 | } while(0) | 46 | } while(0) |
44 | 47 | ||
45 | /* Wave(RIFF)/Wave64 format */ | 48 | enum { |
49 | RIFF_CHUNK = 0, | ||
50 | WAVE_CHUNK, | ||
51 | FMT_CHUNK, | ||
52 | FACT_CHUNK, | ||
53 | DATA_CHUNK, | ||
54 | NUM_CHUNKS, | ||
55 | }; | ||
56 | |||
57 | /* Wave chunk names */ | ||
58 | static const unsigned char *wave_chunknames[NUM_CHUNKS] = | ||
59 | { | ||
60 | [RIFF_CHUNK] = "RIFF", | ||
61 | [WAVE_CHUNK] = "WAVE", | ||
62 | [FMT_CHUNK] = "fmt ", | ||
63 | [FACT_CHUNK] = "fact", | ||
64 | [DATA_CHUNK] = "data", | ||
65 | }; | ||
46 | 66 | ||
47 | /* Wave64 GUIDs */ | 67 | /* Wave64 GUIDs */ |
48 | #define WAVE64_GUID_RIFF "riff\x2e\x91\xcf\x11\xa5\xd6\x28\xdb\x04\xc1\x00\x00" | 68 | static const unsigned char *wave64_chunknames[NUM_CHUNKS] = |
49 | #define WAVE64_GUID_WAVE "wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" | 69 | { |
50 | #define WAVE64_GUID_FMT "fmt \xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" | 70 | [RIFF_CHUNK] = "riff\x2e\x91\xcf\x11\xa5\xd6\x28\xdb\x04\xc1\x00\x00", |
51 | #define WAVE64_GUID_DATA "data\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" | 71 | [WAVE_CHUNK] = "wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a", |
72 | [FMT_CHUNK] = "fmt \xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a", | ||
73 | [FACT_CHUNK] = "fact\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a", | ||
74 | [DATA_CHUNK] = "data\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a", | ||
75 | }; | ||
52 | 76 | ||
77 | /* support formats */ | ||
53 | enum | 78 | enum |
54 | { | 79 | { |
55 | WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */ | 80 | WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */ |
@@ -65,21 +90,21 @@ enum | |||
65 | IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */ | 90 | IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */ |
66 | WAVE_FORMAT_ATRAC3 = 0x0270, /* Atrac3 stream */ | 91 | WAVE_FORMAT_ATRAC3 = 0x0270, /* Atrac3 stream */ |
67 | WAVE_FORMAT_SWF_ADPCM = 0x5346, /* Adobe SWF ADPCM */ | 92 | WAVE_FORMAT_SWF_ADPCM = 0x5346, /* Adobe SWF ADPCM */ |
93 | WAVE_FORMAT_EXTENSIBLE = 0xFFFE, | ||
68 | }; | 94 | }; |
69 | 95 | ||
70 | struct wave_fmt { | 96 | struct wave_fmt { |
71 | unsigned int formattag; | 97 | unsigned int formattag; |
72 | unsigned long channels; | 98 | unsigned int channels; |
73 | unsigned int blockalign; | 99 | unsigned int blockalign; |
74 | unsigned long bitspersample; | 100 | unsigned int bitspersample; |
75 | unsigned int samplesperblock; | 101 | unsigned int samplesperblock; |
102 | uint32_t totalsamples; | ||
76 | uint64_t numbytes; | 103 | uint64_t numbytes; |
77 | }; | 104 | }; |
78 | 105 | ||
79 | static unsigned long get_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3) | 106 | static void set_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3) |
80 | { | 107 | { |
81 | unsigned long totalsamples = 0; | ||
82 | |||
83 | switch (fmt->formattag) | 108 | switch (fmt->formattag) |
84 | { | 109 | { |
85 | case WAVE_FORMAT_PCM: | 110 | case WAVE_FORMAT_PCM: |
@@ -88,39 +113,45 @@ static unsigned long get_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3 | |||
88 | case WAVE_FORMAT_MULAW: | 113 | case WAVE_FORMAT_MULAW: |
89 | case IBM_FORMAT_ALAW: | 114 | case IBM_FORMAT_ALAW: |
90 | case IBM_FORMAT_MULAW: | 115 | case IBM_FORMAT_MULAW: |
91 | totalsamples = | 116 | if (fmt->bitspersample != 0 && fmt->channels != 0) |
92 | fmt->numbytes / ((fmt->bitspersample >> 3) * fmt->channels); | 117 | fmt->totalsamples = fmt->numbytes / ((fmt->bitspersample >> 3) * fmt->channels); |
93 | break; | 118 | break; |
94 | case WAVE_FORMAT_ADPCM: | 119 | case WAVE_FORMAT_ADPCM: |
95 | case WAVE_FORMAT_DVI_ADPCM: | 120 | case WAVE_FORMAT_DVI_ADPCM: |
96 | case WAVE_FORMAT_XBOX_ADPCM: | 121 | case WAVE_FORMAT_XBOX_ADPCM: |
97 | totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; | 122 | if (fmt->blockalign != 0) |
123 | fmt->totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; | ||
98 | break; | 124 | break; |
99 | case WAVE_FORMAT_YAMAHA_ADPCM: | 125 | case WAVE_FORMAT_YAMAHA_ADPCM: |
100 | if (fmt->samplesperblock == 0) | 126 | if (fmt->blockalign != 0 && fmt->channels != 0) |
101 | { | 127 | { |
102 | if (fmt->blockalign == ((id3->frequency / 60) + 4) * fmt->channels) | 128 | if (fmt->samplesperblock == 0) |
103 | fmt->samplesperblock = id3->frequency / 30; | 129 | { |
104 | else | 130 | if (fmt->blockalign == ((id3->frequency / 60) + 4) * fmt->channels) |
105 | fmt->samplesperblock = (fmt->blockalign << 1) / fmt->channels; | 131 | fmt->samplesperblock = id3->frequency / 30; |
132 | else | ||
133 | fmt->samplesperblock = (fmt->blockalign << 1) / fmt->channels; | ||
134 | } | ||
135 | fmt->totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; | ||
106 | } | 136 | } |
107 | totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; | ||
108 | break; | 137 | break; |
109 | case WAVE_FORMAT_DIALOGIC_OKI_ADPCM: | 138 | case WAVE_FORMAT_DIALOGIC_OKI_ADPCM: |
110 | totalsamples = fmt->numbytes << 1; | 139 | fmt->totalsamples = fmt->numbytes << 1; |
111 | break; | 140 | break; |
112 | case WAVE_FORMAT_SWF_ADPCM: | 141 | case WAVE_FORMAT_SWF_ADPCM: |
113 | if (fmt->samplesperblock == 0) | 142 | if (fmt->blockalign != 0 && fmt->bitspersample != 0 && fmt->channels != 0) |
114 | fmt->samplesperblock = (((fmt->blockalign << 3) - 2) / fmt->channels - 22) | 143 | { |
115 | / fmt->bitspersample; | 144 | if (fmt->samplesperblock == 0) |
145 | fmt->samplesperblock = (((fmt->blockalign << 3) - 2) / fmt->channels - 22) | ||
146 | / fmt->bitspersample; | ||
116 | 147 | ||
117 | totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; | 148 | fmt->totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; |
149 | } | ||
118 | break; | 150 | break; |
119 | default: | 151 | default: |
120 | totalsamples = 0; | 152 | fmt->totalsamples = 0; |
121 | break; | 153 | break; |
122 | } | 154 | } |
123 | return totalsamples; | ||
124 | } | 155 | } |
125 | 156 | ||
126 | static void parse_riff_format(unsigned char* buf, int fmtsize, struct wave_fmt *fmt, | 157 | static void parse_riff_format(unsigned char* buf, int fmtsize, struct wave_fmt *fmt, |
@@ -138,33 +169,65 @@ static void parse_riff_format(unsigned char* buf, int fmtsize, struct wave_fmt * | |||
138 | fmt->blockalign = buf[12] | (buf[13] << 8); | 169 | fmt->blockalign = buf[12] | (buf[13] << 8); |
139 | /* wBitsPerSample */ | 170 | /* wBitsPerSample */ |
140 | fmt->bitspersample = buf[14] | (buf[15] << 8); | 171 | fmt->bitspersample = buf[14] | (buf[15] << 8); |
141 | if (fmtsize > 19) | 172 | |
173 | if (fmt->formattag != WAVE_FORMAT_EXTENSIBLE) | ||
142 | { | 174 | { |
143 | /* wSamplesPerBlock */ | 175 | if (fmtsize > 19) |
144 | fmt->samplesperblock = buf[18] | (buf[19] << 8); | 176 | { |
177 | /* wSamplesPerBlock */ | ||
178 | fmt->samplesperblock = buf[18] | (buf[19] << 8); | ||
179 | } | ||
180 | } | ||
181 | else if (fmtsize > 25) | ||
182 | { | ||
183 | /* wValidBitsPerSample */ | ||
184 | fmt->bitspersample = buf[18] | (buf[19] << 8); | ||
185 | /* SubFormat */ | ||
186 | fmt->formattag = buf[24] | (buf[25] << 8); | ||
187 | } | ||
188 | |||
189 | /* Check for ATRAC3 stream */ | ||
190 | if (fmt->formattag == WAVE_FORMAT_ATRAC3) | ||
191 | { | ||
192 | int jsflag = 0; | ||
193 | if(id3->bitrate == 66 || id3->bitrate == 94) | ||
194 | jsflag = 1; | ||
195 | |||
196 | id3->extradata_size = 14; | ||
197 | id3->channels = 2; | ||
198 | id3->codectype = AFMT_OMA_ATRAC3; | ||
199 | /* Store the extradata for the codec */ | ||
200 | AV_WL16(&id3->id3v2buf[0], 1); // always 1 | ||
201 | AV_WL32(&id3->id3v2buf[2], id3->frequency);// samples rate | ||
202 | AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode | ||
203 | AV_WL16(&id3->id3v2buf[8], jsflag); // coding mode | ||
204 | AV_WL16(&id3->id3v2buf[10], 1); // always 1 | ||
205 | AV_WL16(&id3->id3v2buf[12], 0); // always 0 | ||
145 | } | 206 | } |
146 | } | 207 | } |
147 | 208 | ||
148 | bool get_wave_metadata(int fd, struct mp3entry* id3) | 209 | bool read_header(int fd, struct mp3entry* id3, const unsigned char **chunknames, bool is_64) |
149 | { | 210 | { |
150 | /* Use the trackname part of the id3 structure as a temporary buffer */ | 211 | /* Use the temporary buffer */ |
151 | unsigned char* buf = (unsigned char *)id3->path; | 212 | unsigned char* buf = (unsigned char *)id3->path; |
213 | |||
152 | struct wave_fmt fmt; | 214 | struct wave_fmt fmt; |
153 | unsigned long totalsamples = 0; | 215 | |
154 | unsigned long offset = 0; | 216 | unsigned int namelen = (is_64)? 16 : 4; |
155 | int read_bytes; | 217 | unsigned int sizelen = (is_64)? 8 : 4; |
156 | int i; | 218 | unsigned int len = namelen + sizelen; |
219 | uint64_t chunksize; | ||
220 | uint64_t offset = len + namelen; | ||
221 | int read_data; | ||
157 | 222 | ||
158 | memset(&fmt, 0, sizeof(struct wave_fmt)); | 223 | memset(&fmt, 0, sizeof(struct wave_fmt)); |
159 | 224 | ||
160 | /* get RIFF chunk header */ | 225 | /* get RIFF chunk header */ |
161 | if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 12) < 12)) | 226 | lseek(fd, 0, SEEK_SET); |
162 | { | 227 | read(fd, buf, offset); |
163 | return false; | ||
164 | } | ||
165 | offset += 12; | ||
166 | 228 | ||
167 | if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) | 229 | if ((memcmp(buf, chunknames[RIFF_CHUNK], namelen) != 0) || |
230 | (memcmp(buf + len, chunknames[WAVE_CHUNK], namelen) != 0)) | ||
168 | { | 231 | { |
169 | DEBUGF("metadata error: missing riff header.\n"); | 232 | DEBUGF("metadata error: missing riff header.\n"); |
170 | return false; | 233 | return false; |
@@ -174,180 +237,106 @@ bool get_wave_metadata(int fd, struct mp3entry* id3) | |||
174 | while (true) | 237 | while (true) |
175 | { | 238 | { |
176 | /* get chunk header */ | 239 | /* get chunk header */ |
177 | if (read(fd, buf, 8) < 8) | 240 | if (read(fd, buf, len) <= 0) |
241 | { | ||
242 | DEBUGF("metadata error: read error or missing 'data' chunk.\n"); | ||
178 | return false; | 243 | return false; |
179 | offset += 8; | 244 | } |
180 | |||
181 | /* chunkSize */ | ||
182 | i = get_long_le(&buf[4]); | ||
183 | 245 | ||
184 | if (memcmp(buf, "fmt ", 4) == 0) | 246 | offset += len; |
185 | { | ||
186 | /* get rest of chunk */ | ||
187 | if (i < 16) | ||
188 | return false; | ||
189 | 247 | ||
190 | read_bytes = (i > 19)? 20 : 16; | 248 | /* get chunk size (when the header is wave64, chunksize includes GUID and data length) */ |
249 | chunksize = (is_64) ? get_uint64_le(buf + namelen) - len : | ||
250 | get_long_le(buf + namelen); | ||
191 | 251 | ||
192 | if (read(fd, buf, read_bytes) != read_bytes) | 252 | if (memcmp(buf, chunknames[DATA_CHUNK], namelen) == 0) |
193 | return false; | 253 | { |
254 | DEBUGF("find 'data' chunk\n"); | ||
255 | fmt.numbytes = chunksize; | ||
256 | if (fmt.formattag == WAVE_FORMAT_ATRAC3) | ||
257 | id3->first_frame_offset = offset; | ||
258 | break; | ||
259 | } | ||
194 | 260 | ||
195 | offset += read_bytes; | 261 | /* padded to next chunk */ |
196 | i -= read_bytes; | 262 | chunksize += ((is_64)? ((1 + ~chunksize) & 0x07) : (chunksize & 1)); |
263 | offset += chunksize; | ||
197 | 264 | ||
198 | parse_riff_format(buf, read_bytes, &fmt, id3); | 265 | read_data = 0; |
266 | if (memcmp(buf, chunknames[FMT_CHUNK], namelen) == 0) | ||
267 | { | ||
268 | DEBUGF("find 'fmt ' chunk\n"); | ||
199 | 269 | ||
200 | /* Check for ATRAC3 stream */ | 270 | if (chunksize < 16) |
201 | if (fmt.formattag == WAVE_FORMAT_ATRAC3) | ||
202 | { | 271 | { |
203 | int jsflag = 0; | 272 | DEBUGF("metadata error: 'fmt ' chunk is too small: %d\n", (int)chunksize); |
204 | if(id3->bitrate == 66 || id3->bitrate == 94) | 273 | return false; |
205 | jsflag = 1; | ||
206 | |||
207 | id3->extradata_size = 14; | ||
208 | id3->channels = 2; | ||
209 | id3->codectype = AFMT_OMA_ATRAC3; | ||
210 | /* Store the extradata for the codec */ | ||
211 | AV_WL16(&id3->id3v2buf[0], 1); // always 1 | ||
212 | AV_WL32(&id3->id3v2buf[2], id3->frequency); // samples rate | ||
213 | AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode | ||
214 | AV_WL16(&id3->id3v2buf[8], jsflag); // coding mode | ||
215 | AV_WL16(&id3->id3v2buf[10], 1); // always 1 | ||
216 | AV_WL16(&id3->id3v2buf[12], 0); // always 0 | ||
217 | } | 274 | } |
275 | |||
276 | /* get and parse format */ | ||
277 | read_data = (chunksize > 25)? 26 : chunksize; | ||
278 | |||
279 | read(fd, buf, read_data); | ||
280 | parse_riff_format(buf, read_data, &fmt, id3); | ||
218 | } | 281 | } |
219 | else if (memcmp(buf, "data", 4) == 0) | 282 | else if (memcmp(buf, chunknames[FACT_CHUNK], namelen) == 0) |
220 | { | ||
221 | fmt.numbytes = i; | ||
222 | if (fmt.formattag == WAVE_FORMAT_ATRAC3) | ||
223 | id3->first_frame_offset = offset; | ||
224 | break; | ||
225 | } | ||
226 | else if (memcmp(buf, "fact", 4) == 0) | ||
227 | { | 283 | { |
284 | DEBUGF("find 'fact' chunk\n"); | ||
285 | |||
228 | /* dwSampleLength */ | 286 | /* dwSampleLength */ |
229 | if (i >= 4) | 287 | if (chunksize >= sizelen) |
230 | { | 288 | { |
231 | /* get rest of chunk */ | 289 | /* get totalsamples */ |
232 | if (read(fd, buf, 4) < 4) | 290 | read_data = sizelen; |
233 | return false; | 291 | read(fd, buf, read_data); |
234 | offset += 4; | 292 | fmt.totalsamples = (is_64)? get_uint64_le(buf) : get_long_le(buf); |
235 | i -= 4; | ||
236 | totalsamples = get_long_le(buf); | ||
237 | } | 293 | } |
238 | } | 294 | } |
239 | 295 | ||
240 | /* seek to next chunk (even chunk sizes must be padded) */ | 296 | lseek(fd, chunksize - read_data, SEEK_CUR); |
241 | i += (i & 0x01); | ||
242 | |||
243 | if(lseek(fd, i, SEEK_CUR) < 0) | ||
244 | return false; | ||
245 | offset += i; | ||
246 | } | 297 | } |
247 | 298 | ||
248 | if ((fmt.numbytes == 0) || (fmt.channels == 0) || (fmt.blockalign == 0)) | 299 | if (fmt.totalsamples == 0) |
249 | { | 300 | set_totalsamples(&fmt, id3); |
250 | DEBUGF("metadata error: numbytes, channels, or blockalign is 0.\n"); | ||
251 | return false; | ||
252 | } | ||
253 | 301 | ||
254 | if (totalsamples == 0) | 302 | id3->vbr = false; /* All Wave/Wave64 files are CBR */ |
255 | { | ||
256 | totalsamples = get_totalsamples(&fmt, id3); | ||
257 | } | ||
258 | |||
259 | id3->vbr = false; /* All WAV files are CBR */ | ||
260 | id3->filesize = filesize(fd); | 303 | id3->filesize = filesize(fd); |
261 | 304 | ||
262 | /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ | 305 | /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ |
263 | if(id3->codectype != AFMT_OMA_ATRAC3) | 306 | if(fmt.formattag != AFMT_OMA_ATRAC3) |
264 | id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; | ||
265 | else | ||
266 | id3->length = ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate; | ||
267 | |||
268 | return true; | ||
269 | } | ||
270 | |||
271 | bool get_wave64_metadata(int fd, struct mp3entry* id3) | ||
272 | { | ||
273 | /* Use the trackname part of the id3 structure as a temporary buffer */ | ||
274 | unsigned char* buf = (unsigned char *)id3->path; | ||
275 | struct wave_fmt fmt; | ||
276 | unsigned long totalsamples = 0; | ||
277 | int read_bytes; | ||
278 | uint64_t i; | ||
279 | |||
280 | memset(&fmt, 0, sizeof(struct wave_fmt)); | ||
281 | |||
282 | /* get RIFF chunk header */ | ||
283 | if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 40) < 40)) | ||
284 | return false; | ||
285 | |||
286 | if ((memcmp(buf , WAVE64_GUID_RIFF, 16) != 0)|| | ||
287 | (memcmp(buf+24, WAVE64_GUID_WAVE, 16) != 0)) | ||
288 | { | ||
289 | DEBUGF("metadata error: does not wave64 file\n"); | ||
290 | return false; | ||
291 | } | ||
292 | |||
293 | /* iterate over WAVE chunks until 'data' chunk */ | ||
294 | while (true) | ||
295 | { | 307 | { |
296 | /* get chunk header */ | 308 | if (id3->frequency != 0) |
297 | if (read(fd, buf, 24) < 24) | 309 | id3->length = ((int64_t) fmt.totalsamples * 1000) / id3->frequency; |
298 | return false; | ||
299 | |||
300 | /* chunkSize (excludes GUID and size length) */ | ||
301 | i = get_uint64_le(buf + 16) - 24; | ||
302 | |||
303 | if (memcmp(buf, WAVE64_GUID_FMT, 16) == 0) | ||
304 | { | ||
305 | DEBUGF("find 'fmt ' chunk\n"); | ||
306 | if (i < 16) | ||
307 | return false; | ||
308 | |||
309 | read_bytes = (i > 16)? 24 : 16; | ||
310 | if ((int)i < read_bytes) | ||
311 | i = 0; | ||
312 | else | ||
313 | i -= read_bytes; | ||
314 | |||
315 | /* get rest of chunk */ | ||
316 | if (read(fd, buf, read_bytes) < read_bytes) | ||
317 | return false; | ||
318 | |||
319 | parse_riff_format(buf, read_bytes, &fmt, id3); | ||
320 | } | ||
321 | else if (memcmp(buf, WAVE64_GUID_DATA, 16) == 0) | ||
322 | { | ||
323 | DEBUGF("find 'data' chunk\n"); | ||
324 | fmt.numbytes = i; | ||
325 | break; | ||
326 | } | ||
327 | |||
328 | /* seek to next chunk (8byte bound) */ | ||
329 | i += (1 + ~i) & 0x07; | ||
330 | |||
331 | if(lseek(fd, i, SEEK_CUR) < 0) | ||
332 | return false; | ||
333 | } | 310 | } |
334 | 311 | else | |
335 | if ((fmt.numbytes == 0) || (fmt.channels == 0) || (fmt.blockalign == 0)) | ||
336 | { | 312 | { |
337 | DEBUGF("metadata error: numbytes, channels, or blockalign is 0\n"); | 313 | if (id3->bitrate != 0) |
338 | return false; | 314 | id3->length = ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate; |
339 | } | 315 | } |
340 | 316 | ||
341 | if (totalsamples == 0) | 317 | /* output header/id3 info (for debug) */ |
342 | { | 318 | DEBUGF("%s header info ----\n", (is_64)? "wave64" : "wave"); |
343 | totalsamples = get_totalsamples(&fmt, id3); | 319 | DEBUGF(" format: %04x\n", (int)fmt.formattag); |
344 | } | 320 | DEBUGF(" channels: %u\n", fmt.channels); |
321 | DEBUGF(" blockalign: %u\n", fmt.blockalign); | ||
322 | DEBUGF(" bitspersample: %u\n", fmt.bitspersample); | ||
323 | DEBUGF(" samplesperblock: %u\n", fmt.samplesperblock); | ||
324 | DEBUGF(" totalsamples: %u\n", (unsigned int)fmt.totalsamples); | ||
325 | DEBUGF(" numbytes; %u\n", (unsigned int)fmt.numbytes); | ||
326 | DEBUGF("id3 info ----\n"); | ||
327 | DEBUGF(" frquency: %u\n", (unsigned int)id3->frequency); | ||
328 | DEBUGF(" bitrate: %d\n", id3->bitrate); | ||
329 | DEBUGF(" length: %u\n", (unsigned int)id3->length); | ||
345 | 330 | ||
346 | id3->vbr = false; /* All Wave64 files are CBR */ | 331 | return true; |
347 | id3->filesize = filesize(fd); | 332 | } |
348 | 333 | ||
349 | /* Calculate track length [ms] */ | 334 | bool get_wave_metadata(int fd, struct mp3entry* id3) |
350 | id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; | 335 | { |
336 | return read_header(fd, id3, (const unsigned char **)&wave_chunknames, false); | ||
337 | } | ||
351 | 338 | ||
352 | return true; | 339 | bool get_wave64_metadata(int fd, struct mp3entry* id3) |
340 | { | ||
341 | return read_header(fd, id3, (const unsigned char **)&wave64_chunknames, true); | ||
353 | } | 342 | } |