summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libopus/opus_multistream_decoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libopus/opus_multistream_decoder.c')
-rw-r--r--lib/rbcodec/codecs/libopus/opus_multistream_decoder.c549
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)
43static 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
53opus_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
66int 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
113OpusMSDecoder *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
149static 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
178int 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)
307static 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
338static 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
371int 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
385int 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
395int 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
402int 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
416int 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;
532bad_arg:
533 return OPUS_BAD_ARG;
534}
535
536int 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
546void opus_multistream_decoder_destroy(OpusMSDecoder *st)
547{
548 opus_free(st);
549}