diff options
Diffstat (limited to 'lib/rbcodec/codecs/libopus/opus_multistream_decoder.c')
-rw-r--r-- | lib/rbcodec/codecs/libopus/opus_multistream_decoder.c | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libopus/opus_multistream_decoder.c b/lib/rbcodec/codecs/libopus/opus_multistream_decoder.c new file mode 100644 index 0000000000..562103cd0a --- /dev/null +++ b/lib/rbcodec/codecs/libopus/opus_multistream_decoder.c | |||
@@ -0,0 +1,549 @@ | |||
1 | /* Copyright (c) 2011 Xiph.Org Foundation | ||
2 | Written by Jean-Marc Valin */ | ||
3 | /* | ||
4 | Redistribution and use in source and binary forms, with or without | ||
5 | modification, are permitted provided that the following conditions | ||
6 | are met: | ||
7 | |||
8 | - Redistributions of source code must retain the above copyright | ||
9 | notice, this list of conditions and the following disclaimer. | ||
10 | |||
11 | - Redistributions in binary form must reproduce the above copyright | ||
12 | notice, this list of conditions and the following disclaimer in the | ||
13 | documentation and/or other materials provided with the distribution. | ||
14 | |||
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | #include "config.h" | ||
30 | #endif | ||
31 | |||
32 | #include "opus_multistream.h" | ||
33 | #include "opus.h" | ||
34 | #include "opus_private.h" | ||
35 | #include "stack_alloc.h" | ||
36 | #include <stdarg.h> | ||
37 | #include "float_cast.h" | ||
38 | #include "os_support.h" | ||
39 | |||
40 | /* DECODER */ | ||
41 | |||
42 | #if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) | ||
43 | static void validate_ms_decoder(OpusMSDecoder *st) | ||
44 | { | ||
45 | validate_layout(&st->layout); | ||
46 | } | ||
47 | #define VALIDATE_MS_DECODER(st) validate_ms_decoder(st) | ||
48 | #else | ||
49 | #define VALIDATE_MS_DECODER(st) | ||
50 | #endif | ||
51 | |||
52 | |||
53 | opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) | ||
54 | { | ||
55 | int coupled_size; | ||
56 | int mono_size; | ||
57 | |||
58 | if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; | ||
59 | coupled_size = opus_decoder_get_size(2); | ||
60 | mono_size = opus_decoder_get_size(1); | ||
61 | return align(sizeof(OpusMSDecoder)) | ||
62 | + nb_coupled_streams * align(coupled_size) | ||
63 | + (nb_streams-nb_coupled_streams) * align(mono_size); | ||
64 | } | ||
65 | |||
66 | int opus_multistream_decoder_init( | ||
67 | OpusMSDecoder *st, | ||
68 | opus_int32 Fs, | ||
69 | int channels, | ||
70 | int streams, | ||
71 | int coupled_streams, | ||
72 | const unsigned char *mapping | ||
73 | ) | ||
74 | { | ||
75 | int coupled_size; | ||
76 | int mono_size; | ||
77 | int i, ret; | ||
78 | char *ptr; | ||
79 | |||
80 | if ((channels>255) || (channels<1) || (coupled_streams>streams) || | ||
81 | (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) | ||
82 | return OPUS_BAD_ARG; | ||
83 | |||
84 | st->layout.nb_channels = channels; | ||
85 | st->layout.nb_streams = streams; | ||
86 | st->layout.nb_coupled_streams = coupled_streams; | ||
87 | |||
88 | for (i=0;i<st->layout.nb_channels;i++) | ||
89 | st->layout.mapping[i] = mapping[i]; | ||
90 | if (!validate_layout(&st->layout)) | ||
91 | return OPUS_BAD_ARG; | ||
92 | |||
93 | ptr = (char*)st + align(sizeof(OpusMSDecoder)); | ||
94 | coupled_size = opus_decoder_get_size(2); | ||
95 | mono_size = opus_decoder_get_size(1); | ||
96 | |||
97 | for (i=0;i<st->layout.nb_coupled_streams;i++) | ||
98 | { | ||
99 | ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); | ||
100 | if(ret!=OPUS_OK)return ret; | ||
101 | ptr += align(coupled_size); | ||
102 | } | ||
103 | for (;i<st->layout.nb_streams;i++) | ||
104 | { | ||
105 | ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); | ||
106 | if(ret!=OPUS_OK)return ret; | ||
107 | ptr += align(mono_size); | ||
108 | } | ||
109 | return OPUS_OK; | ||
110 | } | ||
111 | |||
112 | |||
113 | OpusMSDecoder *opus_multistream_decoder_create( | ||
114 | opus_int32 Fs, | ||
115 | int channels, | ||
116 | int streams, | ||
117 | int coupled_streams, | ||
118 | const unsigned char *mapping, | ||
119 | int *error | ||
120 | ) | ||
121 | { | ||
122 | int ret; | ||
123 | OpusMSDecoder *st; | ||
124 | if ((channels>255) || (channels<1) || (coupled_streams>streams) || | ||
125 | (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) | ||
126 | { | ||
127 | if (error) | ||
128 | *error = OPUS_BAD_ARG; | ||
129 | return NULL; | ||
130 | } | ||
131 | st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); | ||
132 | if (st==NULL) | ||
133 | { | ||
134 | if (error) | ||
135 | *error = OPUS_ALLOC_FAIL; | ||
136 | return NULL; | ||
137 | } | ||
138 | ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); | ||
139 | if (error) | ||
140 | *error = ret; | ||
141 | if (ret != OPUS_OK) | ||
142 | { | ||
143 | opus_free(st); | ||
144 | st = NULL; | ||
145 | } | ||
146 | return st; | ||
147 | } | ||
148 | |||
149 | static int opus_multistream_packet_validate(const unsigned char *data, | ||
150 | opus_int32 len, int nb_streams, opus_int32 Fs) | ||
151 | { | ||
152 | int s; | ||
153 | int count; | ||
154 | unsigned char toc; | ||
155 | opus_int16 size[48]; | ||
156 | int samples=0; | ||
157 | opus_int32 packet_offset; | ||
158 | |||
159 | for (s=0;s<nb_streams;s++) | ||
160 | { | ||
161 | int tmp_samples; | ||
162 | if (len<=0) | ||
163 | return OPUS_INVALID_PACKET; | ||
164 | count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL, | ||
165 | size, NULL, &packet_offset); | ||
166 | if (count<0) | ||
167 | return count; | ||
168 | tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs); | ||
169 | if (s!=0 && samples != tmp_samples) | ||
170 | return OPUS_INVALID_PACKET; | ||
171 | samples = tmp_samples; | ||
172 | data += packet_offset; | ||
173 | len -= packet_offset; | ||
174 | } | ||
175 | return samples; | ||
176 | } | ||
177 | |||
178 | int opus_multistream_decode_native( | ||
179 | OpusMSDecoder *st, | ||
180 | const unsigned char *data, | ||
181 | opus_int32 len, | ||
182 | void *pcm, | ||
183 | opus_copy_channel_out_func copy_channel_out, | ||
184 | int frame_size, | ||
185 | int decode_fec, | ||
186 | int soft_clip, | ||
187 | void *user_data | ||
188 | ) | ||
189 | { | ||
190 | opus_int32 Fs; | ||
191 | int coupled_size; | ||
192 | int mono_size; | ||
193 | int s, c; | ||
194 | char *ptr; | ||
195 | int do_plc=0; | ||
196 | VARDECL(opus_val16, buf); | ||
197 | ALLOC_STACK; | ||
198 | |||
199 | VALIDATE_MS_DECODER(st); | ||
200 | if (frame_size <= 0) | ||
201 | { | ||
202 | RESTORE_STACK; | ||
203 | return OPUS_BAD_ARG; | ||
204 | } | ||
205 | /* Limit frame_size to avoid excessive stack allocations. */ | ||
206 | MUST_SUCCEED(opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs))); | ||
207 | frame_size = IMIN(frame_size, Fs/25*3); | ||
208 | ALLOC(buf, 2*frame_size, opus_val16); | ||
209 | ptr = (char*)st + align(sizeof(OpusMSDecoder)); | ||
210 | coupled_size = opus_decoder_get_size(2); | ||
211 | mono_size = opus_decoder_get_size(1); | ||
212 | |||
213 | if (len==0) | ||
214 | do_plc = 1; | ||
215 | if (len < 0) | ||
216 | { | ||
217 | RESTORE_STACK; | ||
218 | return OPUS_BAD_ARG; | ||
219 | } | ||
220 | if (!do_plc && len < 2*st->layout.nb_streams-1) | ||
221 | { | ||
222 | RESTORE_STACK; | ||
223 | return OPUS_INVALID_PACKET; | ||
224 | } | ||
225 | if (!do_plc) | ||
226 | { | ||
227 | int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs); | ||
228 | if (ret < 0) | ||
229 | { | ||
230 | RESTORE_STACK; | ||
231 | return ret; | ||
232 | } else if (ret > frame_size) | ||
233 | { | ||
234 | RESTORE_STACK; | ||
235 | return OPUS_BUFFER_TOO_SMALL; | ||
236 | } | ||
237 | } | ||
238 | for (s=0;s<st->layout.nb_streams;s++) | ||
239 | { | ||
240 | OpusDecoder *dec; | ||
241 | opus_int32 packet_offset; | ||
242 | int ret; | ||
243 | |||
244 | dec = (OpusDecoder*)ptr; | ||
245 | ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); | ||
246 | |||
247 | if (!do_plc && len<=0) | ||
248 | { | ||
249 | RESTORE_STACK; | ||
250 | return OPUS_INTERNAL_ERROR; | ||
251 | } | ||
252 | packet_offset = 0; | ||
253 | ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); | ||
254 | data += packet_offset; | ||
255 | len -= packet_offset; | ||
256 | if (ret <= 0) | ||
257 | { | ||
258 | RESTORE_STACK; | ||
259 | return ret; | ||
260 | } | ||
261 | frame_size = ret; | ||
262 | if (s < st->layout.nb_coupled_streams) | ||
263 | { | ||
264 | int chan, prev; | ||
265 | prev = -1; | ||
266 | /* Copy "left" audio to the channel(s) where it belongs */ | ||
267 | while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) | ||
268 | { | ||
269 | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, | ||
270 | buf, 2, frame_size, user_data); | ||
271 | prev = chan; | ||
272 | } | ||
273 | prev = -1; | ||
274 | /* Copy "right" audio to the channel(s) where it belongs */ | ||
275 | while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) | ||
276 | { | ||
277 | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, | ||
278 | buf+1, 2, frame_size, user_data); | ||
279 | prev = chan; | ||
280 | } | ||
281 | } else { | ||
282 | int chan, prev; | ||
283 | prev = -1; | ||
284 | /* Copy audio to the channel(s) where it belongs */ | ||
285 | while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) | ||
286 | { | ||
287 | (*copy_channel_out)(pcm, st->layout.nb_channels, chan, | ||
288 | buf, 1, frame_size, user_data); | ||
289 | prev = chan; | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | /* Handle muted channels */ | ||
294 | for (c=0;c<st->layout.nb_channels;c++) | ||
295 | { | ||
296 | if (st->layout.mapping[c] == 255) | ||
297 | { | ||
298 | (*copy_channel_out)(pcm, st->layout.nb_channels, c, | ||
299 | NULL, 0, frame_size, user_data); | ||
300 | } | ||
301 | } | ||
302 | RESTORE_STACK; | ||
303 | return frame_size; | ||
304 | } | ||
305 | |||
306 | #if !defined(DISABLE_FLOAT_API) | ||
307 | static void opus_copy_channel_out_float( | ||
308 | void *dst, | ||
309 | int dst_stride, | ||
310 | int dst_channel, | ||
311 | const opus_val16 *src, | ||
312 | int src_stride, | ||
313 | int frame_size, | ||
314 | void *user_data | ||
315 | ) | ||
316 | { | ||
317 | float *float_dst; | ||
318 | opus_int32 i; | ||
319 | (void)user_data; | ||
320 | float_dst = (float*)dst; | ||
321 | if (src != NULL) | ||
322 | { | ||
323 | for (i=0;i<frame_size;i++) | ||
324 | #if defined(FIXED_POINT) | ||
325 | float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride]; | ||
326 | #else | ||
327 | float_dst[i*dst_stride+dst_channel] = src[i*src_stride]; | ||
328 | #endif | ||
329 | } | ||
330 | else | ||
331 | { | ||
332 | for (i=0;i<frame_size;i++) | ||
333 | float_dst[i*dst_stride+dst_channel] = 0; | ||
334 | } | ||
335 | } | ||
336 | #endif | ||
337 | |||
338 | static void opus_copy_channel_out_short( | ||
339 | void *dst, | ||
340 | int dst_stride, | ||
341 | int dst_channel, | ||
342 | const opus_val16 *src, | ||
343 | int src_stride, | ||
344 | int frame_size, | ||
345 | void *user_data | ||
346 | ) | ||
347 | { | ||
348 | opus_int16 *short_dst; | ||
349 | opus_int32 i; | ||
350 | (void)user_data; | ||
351 | short_dst = (opus_int16*)dst; | ||
352 | if (src != NULL) | ||
353 | { | ||
354 | for (i=0;i<frame_size;i++) | ||
355 | #if defined(FIXED_POINT) | ||
356 | short_dst[i*dst_stride+dst_channel] = src[i*src_stride]; | ||
357 | #else | ||
358 | short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]); | ||
359 | #endif | ||
360 | } | ||
361 | else | ||
362 | { | ||
363 | for (i=0;i<frame_size;i++) | ||
364 | short_dst[i*dst_stride+dst_channel] = 0; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | |||
369 | |||
370 | #ifdef FIXED_POINT | ||
371 | int opus_multistream_decode( | ||
372 | OpusMSDecoder *st, | ||
373 | const unsigned char *data, | ||
374 | opus_int32 len, | ||
375 | opus_int16 *pcm, | ||
376 | int frame_size, | ||
377 | int decode_fec | ||
378 | ) | ||
379 | { | ||
380 | return opus_multistream_decode_native(st, data, len, | ||
381 | pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0, NULL); | ||
382 | } | ||
383 | |||
384 | #ifndef DISABLE_FLOAT_API | ||
385 | int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data, | ||
386 | opus_int32 len, float *pcm, int frame_size, int decode_fec) | ||
387 | { | ||
388 | return opus_multistream_decode_native(st, data, len, | ||
389 | pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL); | ||
390 | } | ||
391 | #endif | ||
392 | |||
393 | #else | ||
394 | |||
395 | int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data, | ||
396 | opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) | ||
397 | { | ||
398 | return opus_multistream_decode_native(st, data, len, | ||
399 | pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1, NULL); | ||
400 | } | ||
401 | |||
402 | int opus_multistream_decode_float( | ||
403 | OpusMSDecoder *st, | ||
404 | const unsigned char *data, | ||
405 | opus_int32 len, | ||
406 | opus_val16 *pcm, | ||
407 | int frame_size, | ||
408 | int decode_fec | ||
409 | ) | ||
410 | { | ||
411 | return opus_multistream_decode_native(st, data, len, | ||
412 | pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL); | ||
413 | } | ||
414 | #endif | ||
415 | |||
416 | int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request, | ||
417 | va_list ap) | ||
418 | { | ||
419 | int coupled_size, mono_size; | ||
420 | char *ptr; | ||
421 | int ret = OPUS_OK; | ||
422 | |||
423 | coupled_size = opus_decoder_get_size(2); | ||
424 | mono_size = opus_decoder_get_size(1); | ||
425 | ptr = (char*)st + align(sizeof(OpusMSDecoder)); | ||
426 | switch (request) | ||
427 | { | ||
428 | case OPUS_GET_BANDWIDTH_REQUEST: | ||
429 | case OPUS_GET_SAMPLE_RATE_REQUEST: | ||
430 | case OPUS_GET_GAIN_REQUEST: | ||
431 | case OPUS_GET_LAST_PACKET_DURATION_REQUEST: | ||
432 | case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: | ||
433 | { | ||
434 | OpusDecoder *dec; | ||
435 | /* For int32* GET params, just query the first stream */ | ||
436 | opus_int32 *value = va_arg(ap, opus_int32*); | ||
437 | dec = (OpusDecoder*)ptr; | ||
438 | ret = opus_decoder_ctl(dec, request, value); | ||
439 | } | ||
440 | break; | ||
441 | case OPUS_GET_FINAL_RANGE_REQUEST: | ||
442 | { | ||
443 | int s; | ||
444 | opus_uint32 *value = va_arg(ap, opus_uint32*); | ||
445 | opus_uint32 tmp; | ||
446 | if (!value) | ||
447 | { | ||
448 | goto bad_arg; | ||
449 | } | ||
450 | *value = 0; | ||
451 | for (s=0;s<st->layout.nb_streams;s++) | ||
452 | { | ||
453 | OpusDecoder *dec; | ||
454 | dec = (OpusDecoder*)ptr; | ||
455 | if (s < st->layout.nb_coupled_streams) | ||
456 | ptr += align(coupled_size); | ||
457 | else | ||
458 | ptr += align(mono_size); | ||
459 | ret = opus_decoder_ctl(dec, request, &tmp); | ||
460 | if (ret != OPUS_OK) break; | ||
461 | *value ^= tmp; | ||
462 | } | ||
463 | } | ||
464 | break; | ||
465 | case OPUS_RESET_STATE: | ||
466 | { | ||
467 | int s; | ||
468 | for (s=0;s<st->layout.nb_streams;s++) | ||
469 | { | ||
470 | OpusDecoder *dec; | ||
471 | |||
472 | dec = (OpusDecoder*)ptr; | ||
473 | if (s < st->layout.nb_coupled_streams) | ||
474 | ptr += align(coupled_size); | ||
475 | else | ||
476 | ptr += align(mono_size); | ||
477 | ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); | ||
478 | if (ret != OPUS_OK) | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | break; | ||
483 | case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: | ||
484 | { | ||
485 | int s; | ||
486 | opus_int32 stream_id; | ||
487 | OpusDecoder **value; | ||
488 | stream_id = va_arg(ap, opus_int32); | ||
489 | if (stream_id<0 || stream_id >= st->layout.nb_streams) | ||
490 | ret = OPUS_BAD_ARG; | ||
491 | value = va_arg(ap, OpusDecoder**); | ||
492 | if (!value) | ||
493 | { | ||
494 | goto bad_arg; | ||
495 | } | ||
496 | for (s=0;s<stream_id;s++) | ||
497 | { | ||
498 | if (s < st->layout.nb_coupled_streams) | ||
499 | ptr += align(coupled_size); | ||
500 | else | ||
501 | ptr += align(mono_size); | ||
502 | } | ||
503 | *value = (OpusDecoder*)ptr; | ||
504 | } | ||
505 | break; | ||
506 | case OPUS_SET_GAIN_REQUEST: | ||
507 | case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: | ||
508 | { | ||
509 | int s; | ||
510 | /* This works for int32 params */ | ||
511 | opus_int32 value = va_arg(ap, opus_int32); | ||
512 | for (s=0;s<st->layout.nb_streams;s++) | ||
513 | { | ||
514 | OpusDecoder *dec; | ||
515 | |||
516 | dec = (OpusDecoder*)ptr; | ||
517 | if (s < st->layout.nb_coupled_streams) | ||
518 | ptr += align(coupled_size); | ||
519 | else | ||
520 | ptr += align(mono_size); | ||
521 | ret = opus_decoder_ctl(dec, request, value); | ||
522 | if (ret != OPUS_OK) | ||
523 | break; | ||
524 | } | ||
525 | } | ||
526 | break; | ||
527 | default: | ||
528 | ret = OPUS_UNIMPLEMENTED; | ||
529 | break; | ||
530 | } | ||
531 | return ret; | ||
532 | bad_arg: | ||
533 | return OPUS_BAD_ARG; | ||
534 | } | ||
535 | |||
536 | int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) | ||
537 | { | ||
538 | int ret; | ||
539 | va_list ap; | ||
540 | va_start(ap, request); | ||
541 | ret = opus_multistream_decoder_ctl_va_list(st, request, ap); | ||
542 | va_end(ap); | ||
543 | return ret; | ||
544 | } | ||
545 | |||
546 | void opus_multistream_decoder_destroy(OpusMSDecoder *st) | ||
547 | { | ||
548 | opus_free(st); | ||
549 | } | ||