9087721d17ef3dfc3fdac6c9c638e72bd95f0950
[fdkaac.git] / src / pcm_readhelper.c
1 /*
2 * Copyright (C) 2013 nu774
3 * For conditions of distribution and use, see copyright notice in COPYING
4 */
5
6 #if HAVE_CONFIG_H
7 # include "config.h"
8 #endif
9
10 #if HAVE_STDINT_H
11 # include <stdint.h>
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdarg.h>
18 #include "pcm_reader.h"
19 #include "m4af_endian.h"
20 #include "catypes.h"
21
22 int pcm_read(pcm_io_context_t *io, void *buffer, uint32_t size)
23 {
24 int rc;
25 uint32_t count = 0;
26
27 do {
28 rc = io->vtbl->read(io->cookie, buffer, size - count);
29 if (rc > 0)
30 count += rc;
31 } while (rc > 0 && count < size);
32 return count > 0 ? count : rc;
33 }
34
35 int pcm_skip(pcm_io_context_t *io, int64_t count)
36 {
37 char buff[8192];
38 int rc;
39 pcm_io_vtbl_t *vp = io->vtbl;
40
41 if (count == 0 || pcm_seek(io, count, SEEK_CUR) >= 0)
42 return 0;
43 do {
44 if ((rc = vp->read(io->cookie, buff, count > 8192 ? 8192 : count)) > 0)
45 count -= rc;
46 } while (rc > 0 && count > 0);
47
48 return count == 0 ? 0 : -1;
49 }
50
51 int pcm_read16le(pcm_io_context_t *io, uint16_t *value)
52 {
53 if (pcm_read(io, value, 2) == 2) {
54 *value = m4af_ltoh16(*value);
55 return 0;
56 }
57 return -1;
58 }
59
60 int pcm_read16be(pcm_io_context_t *io, uint16_t *value)
61 {
62 if (pcm_read(io, value, 2) == 2) {
63 *value = m4af_btoh16(*value);
64 return 0;
65 }
66 return -1;
67 }
68
69 int pcm_read32le(pcm_io_context_t *io, uint32_t *value)
70 {
71 if (pcm_read(io, value, 4) == 4) {
72 *value = m4af_ltoh32(*value);
73 return 0;
74 }
75 return -1;
76 }
77
78 int pcm_read32be(pcm_io_context_t *io, uint32_t *value)
79 {
80 if (pcm_read(io, value, 4) == 4) {
81 *value = m4af_btoh32(*value);
82 return 0;
83 }
84 return -1;
85 }
86
87 int pcm_read64le(pcm_io_context_t *io, uint64_t *value)
88 {
89 if (pcm_read(io, value, 8) == 8) {
90 *value = m4af_ltoh64(*value);
91 return 0;
92 }
93 return -1;
94 }
95
96 int pcm_read64be(pcm_io_context_t *io, uint64_t *value)
97 {
98 if (pcm_read(io, value, 8) == 8) {
99 *value = m4af_btoh64(*value);
100 return 0;
101 }
102 return -1;
103 }
104
105 int pcm_scanl(pcm_io_context_t *io, const char *fmt, ...)
106 {
107 int c, count = 0;
108 va_list ap;
109
110 va_start(ap, fmt);
111 while ((c = *fmt++)) {
112 switch (c) {
113 case 'S':
114 TRY_IO(pcm_read16le(io, va_arg(ap, uint16_t*)));
115 ++count;
116 break;
117 case 'L':
118 TRY_IO(pcm_read32le(io, va_arg(ap, uint32_t*)));
119 ++count;
120 break;
121 case 'Q':
122 TRY_IO(pcm_read64le(io, va_arg(ap, uint64_t*)));
123 ++count;
124 break;
125 }
126 }
127 FAIL:
128 va_end(ap);
129 return count;
130 }
131
132 int pcm_scanb(pcm_io_context_t *io, const char *fmt, ...)
133 {
134 int c, count = 0;
135 va_list ap;
136
137 va_start(ap, fmt);
138 while ((c = *fmt++)) {
139 switch (c) {
140 case 'S':
141 TRY_IO(pcm_read16be(io, va_arg(ap, uint16_t*)));
142 ++count;
143 break;
144 case 'L':
145 TRY_IO(pcm_read32be(io, va_arg(ap, uint32_t*)));
146 ++count;
147 break;
148 case 'Q':
149 TRY_IO(pcm_read64be(io, va_arg(ap, uint64_t*)));
150 ++count;
151 break;
152 }
153 }
154 FAIL:
155 va_end(ap);
156 return count;
157 }
158
159 static
160 int channel_compare(const void *a, const void *b)
161 {
162 return (*(const uint8_t **)a)[0] - (*(const uint8_t **)b)[0];
163 }
164
165 void apple_translate_channel_labels(uint8_t *channels, unsigned n)
166 {
167 unsigned i;
168 char *has_side = strpbrk((char*)channels, "\x0A\x0B");
169
170 for (i = 0; i < n; ++i) {
171 switch (channels[i]) {
172 case kAudioChannelLabel_LeftSurround:
173 case kAudioChannelLabel_RightSurround:
174 if (!has_side) channels[i] += 5; // map to SL/SR
175 break;
176 case kAudioChannelLabel_RearSurroundLeft:
177 case kAudioChannelLabel_RearSurroundRight:
178 if (!has_side) channels[i] -= 28; // map to BL/BR
179 break;
180 case kAudioChannelLabel_Mono:
181 channels[i] = kAudioChannelLabel_Center;
182 break;
183 }
184 }
185 }
186
187 int apple_chan_chunk(pcm_io_context_t *io, uint32_t chunk_size,
188 pcm_sample_description_t *fmt, uint8_t *mapping)
189 {
190 /*
191 * Although FDK encoder supports upto 5.1ch, we handle upto
192 * 8 channels here.
193 */
194 uint32_t i, mChannelLayoutTag, mChannelBitmap, mNumberChannelDescriptions;
195 uint32_t mask = 0;
196 const uint32_t nchannels = fmt->channels_per_frame;
197 uint8_t channels[9] = { 0 };
198 uint8_t *index[8] = { 0 };
199 const char *layout = 0;
200
201 ENSURE(chunk_size >= 12);
202 TRY_IO(pcm_scanb(io, "LLL", &mChannelLayoutTag, &mChannelBitmap,
203 &mNumberChannelDescriptions) != 3);
204
205 switch (mChannelLayoutTag) {
206 case kAudioChannelLayoutTag_UseChannelBitmap:
207 ENSURE(bitcount(mChannelBitmap) == nchannels);
208 TRY_IO(pcm_skip(io, chunk_size - 12));
209 fmt->channel_mask = mChannelBitmap;
210 for (i = 0; i < nchannels; ++i)
211 mapping[i] = i;
212 return 0;
213 case kAudioChannelLayoutTag_UseChannelDescriptions:
214 ENSURE(mNumberChannelDescriptions == nchannels);
215 ENSURE(chunk_size >= 12 + nchannels * 20);
216 for (i = 0; i < mNumberChannelDescriptions; ++i) {
217 uint32_t mChannelLabel;
218 TRY_IO(pcm_read32be(io, &mChannelLabel));
219 ENSURE(mChannelLabel && mChannelLabel <= 0xff);
220 channels[i] = mChannelLabel;
221 TRY_IO(pcm_skip(io, 16));
222 }
223 TRY_IO(pcm_skip(io, chunk_size - 12 - nchannels * 20));
224 apple_translate_channel_labels(channels, nchannels);
225 for (i = 0; i < nchannels; ++i)
226 if (channels[i] > kAudioChannelLabel_TopBackLeft)
227 goto FAIL;
228 break;
229 default:
230 ENSURE((mChannelLayoutTag & 0xffff) == nchannels);
231 TRY_IO(pcm_skip(io, chunk_size - 12));
232
233 switch (mChannelLayoutTag) {
234 /* 1ch */
235 case kAudioChannelLayoutTag_Mono:
236 layout = "\x03"; break;
237 /* 1.1ch */
238 case kAudioChannelLayoutTag_AC3_1_0_1:
239 layout = "\x03\x04"; break;
240 /* 2ch */
241 case kAudioChannelLayoutTag_Stereo:
242 case kAudioChannelLayoutTag_MatrixStereo:
243 case kAudioChannelLayoutTag_Binaural:
244 layout = "\x01\x02"; break;
245 /* 2.1ch */
246 case kAudioChannelLayoutTag_DVD_4:
247 layout = "\x01\x02\x04"; break;
248 /* 3ch */
249 case kAudioChannelLayoutTag_MPEG_3_0_A:
250 layout = "\x01\x02\x03"; break;
251 case kAudioChannelLayoutTag_AC3_3_0:
252 layout = "\x01\x03\x02"; break;
253 case kAudioChannelLayoutTag_MPEG_3_0_B:
254 layout = "\x03\x01\x02"; break;
255 case kAudioChannelLayoutTag_ITU_2_1:
256 layout = "\x01\x02\x09"; break;
257 /* 3.1ch */
258 case kAudioChannelLayoutTag_DVD_10:
259 layout = "\x01\x02\x03\x04"; break;
260 case kAudioChannelLayoutTag_AC3_3_0_1:
261 layout = "\x01\x03\x02\x04"; break;
262 case kAudioChannelLayoutTag_DVD_5:
263 layout = "\x01\x02\x04\x09"; break;
264 case kAudioChannelLayoutTag_AC3_2_1_1:
265 layout = "\x01\x02\x09\x04"; break;
266 /* 4ch */
267 case kAudioChannelLayoutTag_Quadraphonic:
268 case kAudioChannelLayoutTag_ITU_2_2:
269 layout = "\x01\x02\x0A\x0B"; break;
270 case kAudioChannelLayoutTag_MPEG_4_0_A:
271 layout = "\x01\x02\x03\x09"; break;
272 case kAudioChannelLayoutTag_MPEG_4_0_B:
273 layout = "\x03\x01\x02\x09"; break;
274 case kAudioChannelLayoutTag_AC3_3_1:
275 layout = "\x01\x03\x02\x09"; break;
276 /* 4.1ch */
277 case kAudioChannelLayoutTag_DVD_6:
278 layout = "\x01\x02\x04\x0A\x0B"; break;
279 case kAudioChannelLayoutTag_DVD_18:
280 layout = "\x01\x02\x0A\x0B\x04"; break;
281 case kAudioChannelLayoutTag_DVD_11:
282 layout = "\x01\x02\x03\x04\x09"; break;
283 case kAudioChannelLayoutTag_AC3_3_1_1:
284 layout = "\x01\x03\x02\x09\x04"; break;
285 /* 5ch */
286 case kAudioChannelLayoutTag_MPEG_5_0_A:
287 layout = "\x01\x02\x03\x0A\x0B"; break;
288 case kAudioChannelLayoutTag_Pentagonal:
289 case kAudioChannelLayoutTag_MPEG_5_0_B:
290 layout = "\x01\x02\x0A\x0B\x03"; break;
291 case kAudioChannelLayoutTag_MPEG_5_0_C:
292 layout = "\x01\x03\x02\x0A\x0B"; break;
293 case kAudioChannelLayoutTag_MPEG_5_0_D:
294 layout = "\x03\x01\x02\x0A\x0B"; break;
295 /* 5.1ch */
296 case kAudioChannelLayoutTag_MPEG_5_1_A:
297 layout = "\x01\x02\x03\x04\x0A\x0B"; break;
298 case kAudioChannelLayoutTag_MPEG_5_1_B:
299 layout = "\x01\x02\x0A\x0B\x03\x04"; break;
300 case kAudioChannelLayoutTag_MPEG_5_1_C:
301 layout = "\x01\x03\x02\x0A\x0B\x04"; break;
302 case kAudioChannelLayoutTag_MPEG_5_1_D:
303 layout = "\x03\x01\x02\x0A\x0B\x04"; break;
304 /* 6ch */
305 case kAudioChannelLayoutTag_Hexagonal:
306 case kAudioChannelLayoutTag_AudioUnit_6_0:
307 layout = "\x01\x02\x0A\x0B\x03\x09"; break;
308 case kAudioChannelLayoutTag_AAC_6_0:
309 layout = "\x03\x01\x02\x0A\x0B\x09"; break;
310 /* 6.1ch */
311 case kAudioChannelLayoutTag_MPEG_6_1_A:
312 layout = "\x01\x02\x03\x04\x0A\x0B\x09"; break;
313 case kAudioChannelLayoutTag_AAC_6_1:
314 layout = "\x03\x01\x02\x0A\x0B\x09\x04"; break;
315 /* 7ch */
316 case kAudioChannelLayoutTag_AudioUnit_7_0:
317 layout = "\x01\x02\x0A\x0B\x03\x05\x06"; break;
318 case kAudioChannelLayoutTag_AudioUnit_7_0_Front:
319 layout = "\x01\x02\x0A\x0B\x03\x07\x08"; break;
320 case kAudioChannelLayoutTag_AAC_7_0:
321 layout = "\x03\x01\x02\x0A\x0B\x05\x06"; break;
322 /* 7.1ch */
323 case kAudioChannelLayoutTag_MPEG_7_1_A:
324 layout = "\x01\x02\x03\x04\x0A\x0B\x07\x08"; break;
325 case kAudioChannelLayoutTag_MPEG_7_1_B:
326 layout = "\x03\x07\x08\x01\x02\x05\x06\x04"; break;
327 case kAudioChannelLayoutTag_MPEG_7_1_C:
328 layout = "\x01\x02\x03\x04\x0A\x0B\x05\x06"; break;
329 case kAudioChannelLayoutTag_Emagic_Default_7_1:
330 layout = "\x01\x02\x0A\x0B\x03\x04\x07\x08"; break;
331 /* 8ch */
332 case kAudioChannelLayoutTag_Octagonal:
333 layout = "\x01\x02\x05\x06\x03\x09\x0A\x0B"; break;
334 case kAudioChannelLayoutTag_AAC_Octagonal:
335 layout = "\x03\x01\x02\x0A\x0B\x05\x06\x09"; break;
336 default:
337 goto FAIL;
338 }
339 strcpy((char*)channels, layout);
340 }
341
342 for (i = 0; i < nchannels; ++i)
343 mask |= 1 << (channels[i] - 1);
344 fmt->channel_mask = mask;
345 ENSURE(bitcount(mask) == nchannels);
346
347 for (i = 0; i < nchannels; ++i)
348 index[i] = channels + i;
349 qsort(index, nchannels, sizeof(char*), channel_compare);
350 for (i = 0; i < nchannels; ++i)
351 mapping[i] = index[i] - channels;
352
353 return 0;
354 FAIL:
355 return -1;
356 }
This page took 0.031201 seconds and 3 git commands to generate.