]> iEval git - fdkaac.git/blame_incremental - src/wav_reader.c
bump version
[fdkaac.git] / src / wav_reader.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
4 */
5#if HAVE_CONFIG_H
6# include "config.h"
7#endif
8
9#if HAVE_STDINT_H
10# include <stdint.h>
11#endif
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <stdarg.h>
17#include "wav_reader.h"
18#include "m4af_endian.h"
19
20#define RIFF_FOURCC(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24))
21
22#define TRY_IO(expr) \
23 do { \
24 if (expr) \
25 goto FAIL; \
26 } while (0)
27
28#define ASSERT_FORMAT(ctx, expr) \
29 do { \
30 if (!expr) { \
31 if (!ctx->last_error) \
32 ctx->last_error = WAV_INVALID_FORMAT; \
33 goto FAIL;\
34 } \
35 } while (0)
36
37struct wav_reader_t {
38 pcm_sample_description_t sample_format;
39 int64_t length;
40 int64_t position;
41 int32_t data_offset;
42 int ignore_length;
43 int last_error;
44 wav_io_context_t io;
45 void *io_cookie;
46};
47
48static const uint8_t WAV_GUID_PCM[] = {
49 1, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71
50};
51static const uint8_t WAV_GUID_FLOAT[] = {
52 3, 0, 0, 0, 0, 0, 0x10, 0, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71
53};
54
55const pcm_sample_description_t *wav_get_format(wav_reader_t *reader)
56{
57 return &reader->sample_format;
58}
59
60int64_t wav_get_length(wav_reader_t *reader)
61{
62 return reader->length;
63}
64
65int64_t wav_get_position(wav_reader_t *reader)
66{
67 return reader->position;
68}
69
70void wav_teardown(wav_reader_t **reader)
71{
72 free(*reader);
73 *reader = 0;
74}
75
76static
77int riff_read(wav_reader_t *reader, void *buffer, uint32_t size)
78{
79 int rc;
80 uint32_t count = 0;
81
82 if (reader->last_error)
83 return -1;
84 do {
85 rc = reader->io.read(reader->io_cookie, buffer, size - count);
86 if (rc > 0)
87 count += rc;
88 else if (rc < 0)
89 reader->last_error = WAV_IO_ERROR;
90 } while (rc > 0 && count < size);
91 return count > 0 ? count : rc;
92}
93
94static
95int riff_skip(wav_reader_t *reader, int64_t count)
96{
97 char buff[8192];
98 int rc;
99
100 if (reader->last_error)
101 return -1;
102 if (count == 0)
103 return 0;
104 if (reader->io.seek &&
105 reader->io.seek(reader->io_cookie, count, SEEK_CUR) >= 0)
106 return 0;
107
108 do {
109 if ((rc = riff_read(reader, buff, count > 8192 ? 8192 : count)) > 0)
110 count -= rc;
111 } while (rc > 0 && count > 0);
112
113 if (count > 0)
114 reader->last_error = WAV_IO_ERROR;
115 return reader->last_error ? -1 : 0;
116}
117
118static
119int riff_seek(wav_reader_t *reader, int64_t off, int whence)
120{
121 int rc;
122 if (reader->last_error)
123 return -1;
124 if (!reader->io.seek)
125 goto FAIL;
126 if ((rc = reader->io.seek(reader->io_cookie, off, whence)) < 0)
127 goto FAIL;
128 return 0;
129FAIL:
130 reader->last_error = WAV_IO_ERROR;
131 return -1;
132}
133
134static
135int64_t riff_tell(wav_reader_t *reader)
136{
137 int64_t off;
138
139 if (reader->last_error || !reader->io.tell)
140 return -1;
141 off = reader->io.tell(reader->io_cookie);
142 if (off < 0) {
143 reader->last_error = WAV_IO_ERROR;
144 return -1;
145 }
146 return off;
147}
148
149static
150int riff_read16(wav_reader_t *reader, uint16_t *value)
151{
152 TRY_IO(riff_read(reader, value, 2) != 2);
153 *value = m4af_ltoh16(*value);
154 return 0;
155FAIL:
156 return -1;
157}
158
159static
160int riff_read32(wav_reader_t *reader, uint32_t *value)
161{
162 TRY_IO(riff_read(reader, value, 4) != 4);
163 *value = m4af_ltoh32(*value);
164 return 0;
165FAIL:
166 return -1;
167}
168
169static
170int riff_read64(wav_reader_t *reader, uint64_t *value)
171{
172 TRY_IO(riff_read(reader, value, 8) != 8);
173 *value = m4af_ltoh64(*value);
174 return 0;
175FAIL:
176 return -1;
177}
178
179static
180int riff_scan(wav_reader_t *reader, const char *fmt, ...)
181{
182 int c, count = 0;
183 va_list ap;
184
185 va_start(ap, fmt);
186 while ((c = *fmt++)) {
187 switch (c) {
188 case 'S':
189 TRY_IO(riff_read16(reader, va_arg(ap, uint16_t*)));
190 ++count;
191 break;
192 case 'L':
193 TRY_IO(riff_read32(reader, va_arg(ap, uint32_t*)));
194 ++count;
195 break;
196 case 'Q':
197 TRY_IO(riff_read64(reader, va_arg(ap, uint64_t*)));
198 ++count;
199 break;
200 }
201 }
202FAIL:
203 va_end(ap);
204 return count;
205}
206
207static
208uint32_t riff_next_chunk(wav_reader_t *reader, uint32_t *chunk_size)
209{
210 uint32_t fcc;
211 if (riff_scan(reader, "LL", &fcc, chunk_size) == 2)
212 return fcc;
213 return 0;
214}
215
216int wav_read_frames(wav_reader_t *reader, void *buffer, unsigned nframes)
217{
218 int rc;
219 unsigned nbytes;
220
221 if (!reader->ignore_length && nframes > reader->length - reader->position)
222 nframes = reader->length - reader->position;
223 nbytes = nframes * reader->sample_format.bytes_per_frame;
224 if (nbytes) {
225 if ((rc = riff_read(reader, buffer, nbytes)) < 0)
226 return -1;
227 nframes = rc / reader->sample_format.bytes_per_frame;
228 reader->position += nframes;
229 }
230 return nframes;
231}
232
233static
234int riff_ds64(wav_reader_t *reader, int64_t *length)
235{
236 uint32_t fcc, chunk_size, table_size;
237 uint64_t riff_size, sample_count;
238
239 fcc = riff_next_chunk(reader, &chunk_size);
240 ASSERT_FORMAT(reader,
241 fcc == RIFF_FOURCC('d','s','6','4') && chunk_size >= 28);
242 TRY_IO(riff_scan(reader, "QQQL",
243 &riff_size, length, &sample_count, &table_size) != 4);
244 TRY_IO(riff_skip(reader, (chunk_size - 27) & ~1));
245 reader->data_offset += (chunk_size + 9) & ~1;
246FAIL:
247 return -1;
248}
249
250static
251int wav_fmt(wav_reader_t *reader, uint32_t size)
252{
253 uint16_t wFormatTag, nChannels, nBlockAlign, wBitsPerSample, cbSize;
254 uint32_t nSamplesPerSec, nAvgBytesPerSec, dwChannelMask = 0;
255 uint16_t wValidBitsPerSample;
256 uint8_t guid[16];
257 int is_float = 0;
258
259 ASSERT_FORMAT(reader, size >= 16);
260 TRY_IO(riff_scan(reader, "SSLLSS", &wFormatTag, &nChannels,
261 &nSamplesPerSec, &nAvgBytesPerSec, &nBlockAlign,
262 &wBitsPerSample) != 6);
263 wValidBitsPerSample = wBitsPerSample;
264
265 if (wFormatTag != 1 && wFormatTag != 3 && wFormatTag != 0xfffe) {
266 reader->last_error = WAV_UNSUPPORTED_FORMAT;
267 goto FAIL;
268 }
269 ASSERT_FORMAT(reader,
270 nChannels && nSamplesPerSec && nAvgBytesPerSec &&
271 nBlockAlign && wBitsPerSample && !(wBitsPerSample & 7) &&
272 nBlockAlign == nChannels * wBitsPerSample / 8);
273 if (wFormatTag == 3)
274 is_float = 1;
275
276 if (wFormatTag != 0xfffe)
277 TRY_IO(riff_skip(reader, (size - 15) & ~1));
278 else {
279 ASSERT_FORMAT(reader, size >= 40);
280 TRY_IO(riff_scan(reader, "SSL",
281 &cbSize, &wValidBitsPerSample, &dwChannelMask) != 3);
282 TRY_IO(riff_read(reader, guid, 16) != 16);
283
284 if (memcmp(guid, WAV_GUID_FLOAT, 16) == 0)
285 is_float = 1;
286 else if (memcmp(guid, WAV_GUID_PCM, 16) != 0) {
287 reader->last_error = WAV_UNSUPPORTED_FORMAT;
288 goto FAIL;
289 }
290 ASSERT_FORMAT(reader,
291 wValidBitsPerSample &&
292 wValidBitsPerSample <= wBitsPerSample);
293 TRY_IO(riff_skip(reader, (size - 39) & ~1));
294 }
295 reader->sample_format.sample_rate = nSamplesPerSec;
296 reader->sample_format.bits_per_channel = wValidBitsPerSample;
297 reader->sample_format.bytes_per_frame = nBlockAlign;
298 reader->sample_format.channels_per_frame = nChannels;
299 reader->sample_format.channel_mask = dwChannelMask;
300 if (is_float)
301 reader->sample_format.sample_type = PCM_TYPE_FLOAT;
302 else if (wBitsPerSample == 8)
303 reader->sample_format.sample_type = PCM_TYPE_UINT;
304 else
305 reader->sample_format.sample_type = PCM_TYPE_SINT;
306 return 0;
307FAIL:
308 return -1;
309}
310
311static
312int wav_parse(wav_reader_t *reader, int64_t *data_length)
313{
314 uint32_t container, fcc, chunk_size;
315
316 *data_length = 0;
317 container = riff_next_chunk(reader, &chunk_size);
318 if (container != RIFF_FOURCC('R','I','F','F') &&
319 container != RIFF_FOURCC('R','F','6','4'))
320 goto FAIL;
321 TRY_IO(riff_read32(reader, &fcc));
322 if (fcc != RIFF_FOURCC('W','A','V','E'))
323 goto FAIL;
324 reader->data_offset = 12;
325
326 if (container == RIFF_FOURCC('R','F','6','4'))
327 riff_ds64(reader, data_length);
328 while ((fcc = riff_next_chunk(reader, &chunk_size)) != 0) {
329 if (fcc == RIFF_FOURCC('f','m','t',' ')) {
330 if (wav_fmt(reader, chunk_size) < 0)
331 goto FAIL;
332 } else if (fcc == RIFF_FOURCC('d','a','t','a')) {
333 if (container == RIFF_FOURCC('R','I','F','F'))
334 *data_length = chunk_size;
335 reader->data_offset += 8;
336 break;
337 } else {
338 TRY_IO(riff_skip(reader, (chunk_size + 1) & ~1));
339 }
340 reader->data_offset += (chunk_size + 9) & ~1;
341 }
342 if (fcc == RIFF_FOURCC('d','a','t','a'))
343 return 0;
344FAIL:
345 return -1;
346}
347
348wav_reader_t *wav_open(wav_io_context_t *io_ctx, void *io_cookie,
349 int ignore_length)
350{
351 wav_reader_t *reader = 0;
352 int64_t data_length;
353 unsigned bpf;
354
355 if ((reader = calloc(1, sizeof(wav_reader_t))) == 0)
356 return 0;
357 memcpy(&reader->io, io_ctx, sizeof(wav_io_context_t));
358 reader->io_cookie = io_cookie;
359 reader->ignore_length = ignore_length;
360 if (wav_parse(reader, &data_length) < 0) {
361 free(reader);
362 return 0;
363 }
364 bpf = reader->sample_format.bytes_per_frame;
365 if (ignore_length || !data_length || data_length % bpf)
366 reader->length = INT64_MAX;
367 else
368 reader->length = data_length / bpf;
369
370 if (reader->length == INT64_MAX && reader->io.seek && reader->io.tell) {
371 if (reader->io.seek(reader->io_cookie, 0, SEEK_END) >= 0) {
372 int64_t size = reader->io.tell(reader->io_cookie);
373 if (size > 0)
374 reader->length = (size - reader->data_offset) / bpf;
375 reader->io.seek(reader->io_cookie, reader->data_offset, SEEK_SET);
376 }
377 }
378 return reader;
379}
380
381wav_reader_t *raw_open(wav_io_context_t *io_ctx, void *io_cookie,
382 const pcm_sample_description_t *desc)
383{
384 wav_reader_t *reader = 0;
385
386 if ((reader = calloc(1, sizeof(wav_reader_t))) == 0)
387 return 0;
388 memcpy(&reader->io, io_ctx, sizeof(wav_io_context_t));
389 memcpy(&reader->sample_format, desc, sizeof(pcm_sample_description_t));
390 reader->io_cookie = io_cookie;
391 if (io_ctx->seek && io_ctx->tell) {
392 if (reader->io.seek(reader->io_cookie, 0, SEEK_END) >= 0) {
393 int64_t size = reader->io.tell(reader->io_cookie);
394 if (size > 0)
395 reader->length = size / desc->bytes_per_frame;
396 reader->io.seek(reader->io_cookie, reader->data_offset, SEEK_SET);
397 }
398 } else
399 reader->length = INT64_MAX;
400 return reader;
401}
402
403
This page took 0.028824 seconds and 4 git commands to generate.