blob: 1847bd5ae6afea5264f61d20f0d9f04df06cc1ed [file] [log] [blame]
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -05001/* 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"
Jean-Marc Valin51f4a322013-02-20 04:08:04 -050039#include "analysis.h"
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050040
41struct OpusMSEncoder {
Jean-Marc Valin51f4a322013-02-20 04:08:04 -050042 TonalityAnalysisState analysis;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050043 ChannelLayout layout;
Jean-Marc Valin74483662012-12-17 16:23:42 -050044 int variable_duration;
45 opus_int32 bitrate_bps;
46 opus_val32 subframe_mem[3];
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050047 /* Encoder states go here */
48};
49
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050050
51static int validate_encoder_layout(const ChannelLayout *layout)
52{
53 int s;
54 for (s=0;s<layout->nb_streams;s++)
55 {
56 if (s < layout->nb_coupled_streams)
57 {
58 if (get_left_channel(layout, s, -1)==-1)
59 return 0;
60 if (get_right_channel(layout, s, -1)==-1)
61 return 0;
62 } else {
63 if (get_mono_channel(layout, s, -1)==-1)
64 return 0;
65 }
66 }
67 return 1;
68}
69
70
71opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
72{
73 int coupled_size;
74 int mono_size;
75
76 if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
77 coupled_size = opus_encoder_get_size(2);
78 mono_size = opus_encoder_get_size(1);
79 return align(sizeof(OpusMSEncoder))
80 + nb_coupled_streams * align(coupled_size)
81 + (nb_streams-nb_coupled_streams) * align(mono_size);
82}
83
84
85
86int opus_multistream_encoder_init(
87 OpusMSEncoder *st,
88 opus_int32 Fs,
89 int channels,
90 int streams,
91 int coupled_streams,
92 const unsigned char *mapping,
93 int application
94)
95{
96 int coupled_size;
97 int mono_size;
98 int i, ret;
99 char *ptr;
100
101 if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
102 (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
103 return OPUS_BAD_ARG;
104
105 st->layout.nb_channels = channels;
106 st->layout.nb_streams = streams;
107 st->layout.nb_coupled_streams = coupled_streams;
108
Jean-Marc Valin95561be2012-12-17 17:54:01 -0500109 st->bitrate_bps = OPUS_AUTO;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500110 st->variable_duration = OPUS_FRAMESIZE_ARG;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500111 for (i=0;i<st->layout.nb_channels;i++)
112 st->layout.mapping[i] = mapping[i];
113 if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
114 return OPUS_BAD_ARG;
115 ptr = (char*)st + align(sizeof(OpusMSEncoder));
116 coupled_size = opus_encoder_get_size(2);
117 mono_size = opus_encoder_get_size(1);
118
119 for (i=0;i<st->layout.nb_coupled_streams;i++)
120 {
121 ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
122 if(ret!=OPUS_OK)return ret;
123 ptr += align(coupled_size);
124 }
125 for (;i<st->layout.nb_streams;i++)
126 {
127 ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
128 if(ret!=OPUS_OK)return ret;
129 ptr += align(mono_size);
130 }
131 return OPUS_OK;
132}
133
134OpusMSEncoder *opus_multistream_encoder_create(
135 opus_int32 Fs,
136 int channels,
137 int streams,
138 int coupled_streams,
139 const unsigned char *mapping,
140 int application,
141 int *error
142)
143{
144 int ret;
145 OpusMSEncoder *st;
146 if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
147 (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
148 {
149 if (error)
150 *error = OPUS_BAD_ARG;
151 return NULL;
152 }
153 st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams));
154 if (st==NULL)
155 {
156 if (error)
157 *error = OPUS_ALLOC_FAIL;
158 return NULL;
159 }
160 ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
161 if (ret != OPUS_OK)
162 {
163 opus_free(st);
164 st = NULL;
165 }
166 if (error)
167 *error = ret;
168 return st;
169}
170
171typedef void (*opus_copy_channel_in_func)(
172 opus_val16 *dst,
173 int dst_stride,
174 const void *src,
175 int src_stride,
176 int src_channel,
177 int frame_size
178);
179
180/* Max size in case the encoder decides to return three frames */
181#define MS_FRAME_TMP (3*1275+7)
182static int opus_multistream_encode_native
183(
184 OpusMSEncoder *st,
185 opus_copy_channel_in_func copy_channel_in,
186 const void *pcm,
187 int frame_size,
188 unsigned char *data,
Jean-Marc Valinb3eba242012-12-20 23:11:53 -0500189 opus_int32 max_data_bytes,
190 int lsb_depth
Jean-Marc Valin10a34a52012-12-20 00:23:01 -0500191#ifndef FIXED_POINT
192 , downmix_func downmix
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500193 , const void *pcm_analysis
Jean-Marc Valin10a34a52012-12-20 00:23:01 -0500194#endif
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500195)
196{
197 opus_int32 Fs;
198 int coupled_size;
199 int mono_size;
200 int s;
201 char *ptr;
202 int tot_size;
203 VARDECL(opus_val16, buf);
204 unsigned char tmp_data[MS_FRAME_TMP];
205 OpusRepacketizer rp;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500206 int orig_frame_size;
207 int coded_channels;
208 opus_int32 channel_rate;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500209 opus_int32 complexity;
210 AnalysisInfo analysis_info;
211 const CELTMode *celt_mode;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500212 ALLOC_STACK;
213
214 ptr = (char*)st + align(sizeof(OpusMSEncoder));
215 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500216 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_COMPLEXITY(&complexity));
217 opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
Jean-Marc Valin74483662012-12-17 16:23:42 -0500218
219 if (400*frame_size < Fs)
220 {
221 RESTORE_STACK;
222 return OPUS_BAD_ARG;
223 }
224 orig_frame_size = IMIN(frame_size,Fs/50);
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500225#ifndef FIXED_POINT
226 analysis_info.valid = 0;
227 if (complexity >= 7 && Fs==48000)
Jean-Marc Valin74483662012-12-17 16:23:42 -0500228 {
Jean-Marc Valin74483662012-12-17 16:23:42 -0500229 opus_int32 delay_compensation;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500230 int channels;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500231
232 channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
233 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
234 delay_compensation -= Fs/400;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500235
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500236 frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm_analysis,
237 frame_size, st->variable_duration, channels, Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix, &analysis_info);
238 } else
239#endif
240 {
241 frame_size = frame_size_select(frame_size, st->variable_duration, Fs);
242 }
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500243 /* Validate frame_size before using it to allocate stack space.
244 This mirrors the checks in opus_encode[_float](). */
245 if (400*frame_size != Fs && 200*frame_size != Fs &&
246 100*frame_size != Fs && 50*frame_size != Fs &&
247 25*frame_size != Fs && 50*frame_size != 3*Fs)
248 {
249 RESTORE_STACK;
250 return OPUS_BAD_ARG;
251 }
252 ALLOC(buf, 2*frame_size, opus_val16);
253 coupled_size = opus_encoder_get_size(2);
254 mono_size = opus_encoder_get_size(1);
255
256 if (max_data_bytes < 4*st->layout.nb_streams-1)
257 {
258 RESTORE_STACK;
259 return OPUS_BUFFER_TOO_SMALL;
260 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500261
262 /* Compute bitrate allocation between streams (this could be a lot better) */
263 coded_channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
Jean-Marc Valin95561be2012-12-17 17:54:01 -0500264 if (st->bitrate_bps==OPUS_AUTO)
265 {
266 channel_rate = Fs+60*Fs/orig_frame_size;
267 } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
268 {
269 channel_rate = 300000;
270 } else {
271 channel_rate = st->bitrate_bps/coded_channels;
272 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500273#ifndef FIXED_POINT
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500274 if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
Jean-Marc Valin74483662012-12-17 16:23:42 -0500275 {
276 opus_int32 bonus;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500277 bonus = 60*(Fs/frame_size-50);
Jean-Marc Valin74483662012-12-17 16:23:42 -0500278 channel_rate += bonus;
279 }
280#endif
281 ptr = (char*)st + align(sizeof(OpusMSEncoder));
282 for (s=0;s<st->layout.nb_streams;s++)
283 {
284 OpusEncoder *enc;
285 enc = (OpusEncoder*)ptr;
286 if (s < st->layout.nb_coupled_streams)
287 ptr += align(coupled_size);
288 else
289 ptr += align(mono_size);
290 opus_encoder_ctl(enc, OPUS_SET_BITRATE(channel_rate * (s < st->layout.nb_coupled_streams ? 2 : 1)));
291 }
292
293 ptr = (char*)st + align(sizeof(OpusMSEncoder));
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500294 /* Counting ToC */
295 tot_size = 0;
296 for (s=0;s<st->layout.nb_streams;s++)
297 {
298 OpusEncoder *enc;
299 int len;
300 int curr_max;
301
302 opus_repacketizer_init(&rp);
303 enc = (OpusEncoder*)ptr;
304 if (s < st->layout.nb_coupled_streams)
305 {
306 int left, right;
307 left = get_left_channel(&st->layout, s, -1);
308 right = get_right_channel(&st->layout, s, -1);
309 (*copy_channel_in)(buf, 2,
310 pcm, st->layout.nb_channels, left, frame_size);
311 (*copy_channel_in)(buf+1, 2,
312 pcm, st->layout.nb_channels, right, frame_size);
313 ptr += align(coupled_size);
314 } else {
315 int chan = get_mono_channel(&st->layout, s, -1);
316 (*copy_channel_in)(buf, 1,
317 pcm, st->layout.nb_channels, chan, frame_size);
318 ptr += align(mono_size);
319 }
320 /* number of bytes left (+Toc) */
321 curr_max = max_data_bytes - tot_size;
322 /* Reserve three bytes for the last stream and four for the others */
323 curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1);
324 curr_max = IMIN(curr_max,MS_FRAME_TMP);
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500325 len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth
326#ifndef FIXED_POINT
327 , &analysis_info
328#endif
329 );
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500330 if (len<0)
331 {
332 RESTORE_STACK;
333 return len;
334 }
335 /* We need to use the repacketizer to add the self-delimiting lengths
336 while taking into account the fact that the encoder can now return
337 more than one frame at a time (e.g. 60 ms CELT-only) */
338 opus_repacketizer_cat(&rp, tmp_data, len);
339 len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), data, max_data_bytes-tot_size, s != st->layout.nb_streams-1);
340 data += len;
341 tot_size += len;
342 }
343 RESTORE_STACK;
344 return tot_size;
345
346}
347
348#if !defined(DISABLE_FLOAT_API)
349static void opus_copy_channel_in_float(
350 opus_val16 *dst,
351 int dst_stride,
352 const void *src,
353 int src_stride,
354 int src_channel,
355 int frame_size
356)
357{
358 const float *float_src;
Timothy B. Terriberrya8f04b22013-03-18 14:42:44 -0700359 opus_int32 i;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500360 float_src = (const float *)src;
361 for (i=0;i<frame_size;i++)
362#if defined(FIXED_POINT)
363 dst[i*dst_stride] = FLOAT2INT16(float_src[i*src_stride+src_channel]);
364#else
365 dst[i*dst_stride] = float_src[i*src_stride+src_channel];
366#endif
367}
368#endif
369
370static void opus_copy_channel_in_short(
371 opus_val16 *dst,
372 int dst_stride,
373 const void *src,
374 int src_stride,
375 int src_channel,
376 int frame_size
377)
378{
379 const opus_int16 *short_src;
Timothy B. Terriberrya8f04b22013-03-18 14:42:44 -0700380 opus_int32 i;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500381 short_src = (const opus_int16 *)src;
382 for (i=0;i<frame_size;i++)
383#if defined(FIXED_POINT)
384 dst[i*dst_stride] = short_src[i*src_stride+src_channel];
385#else
386 dst[i*dst_stride] = (1/32768.f)*short_src[i*src_stride+src_channel];
387#endif
388}
389
390#ifdef FIXED_POINT
391int opus_multistream_encode(
392 OpusMSEncoder *st,
393 const opus_val16 *pcm,
394 int frame_size,
395 unsigned char *data,
396 opus_int32 max_data_bytes
397)
398{
399 return opus_multistream_encode_native(st, opus_copy_channel_in_short,
Jean-Marc Valinb3eba242012-12-20 23:11:53 -0500400 pcm, frame_size, data, max_data_bytes, 16);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500401}
402
403#ifndef DISABLE_FLOAT_API
404int opus_multistream_encode_float(
405 OpusMSEncoder *st,
406 const float *pcm,
407 int frame_size,
408 unsigned char *data,
409 opus_int32 max_data_bytes
410)
411{
412 return opus_multistream_encode_native(st, opus_copy_channel_in_float,
Jean-Marc Valinb3eba242012-12-20 23:11:53 -0500413 pcm, frame_size, data, max_data_bytes, 16);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500414}
415#endif
416
417#else
418
419int opus_multistream_encode_float
420(
421 OpusMSEncoder *st,
422 const opus_val16 *pcm,
423 int frame_size,
424 unsigned char *data,
425 opus_int32 max_data_bytes
426)
427{
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500428 int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500429 return opus_multistream_encode_native(st, opus_copy_channel_in_float,
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500430 pcm, frame_size, data, max_data_bytes, 24, downmix_float, pcm+channels*st->analysis.analysis_offset);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500431}
432
433int opus_multistream_encode(
434 OpusMSEncoder *st,
435 const opus_int16 *pcm,
436 int frame_size,
437 unsigned char *data,
438 opus_int32 max_data_bytes
439)
440{
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500441 int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500442 return opus_multistream_encode_native(st, opus_copy_channel_in_short,
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500443 pcm, frame_size, data, max_data_bytes, 16, downmix_int, pcm+channels*st->analysis.analysis_offset);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500444}
445#endif
446
447int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
448{
449 va_list ap;
450 int coupled_size, mono_size;
451 char *ptr;
452 int ret = OPUS_OK;
453
454 va_start(ap, request);
455
456 coupled_size = opus_encoder_get_size(2);
457 mono_size = opus_encoder_get_size(1);
458 ptr = (char*)st + align(sizeof(OpusMSEncoder));
459 switch (request)
460 {
461 case OPUS_SET_BITRATE_REQUEST:
462 {
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500463 opus_int32 value = va_arg(ap, opus_int32);
Jean-Marc Valin95561be2012-12-17 17:54:01 -0500464 if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX)
465 goto bad_arg;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500466 st->bitrate_bps = value;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500467 }
468 break;
469 case OPUS_GET_BITRATE_REQUEST:
470 {
471 int s;
472 opus_int32 *value = va_arg(ap, opus_int32*);
473 *value = 0;
474 for (s=0;s<st->layout.nb_streams;s++)
475 {
476 opus_int32 rate;
477 OpusEncoder *enc;
478 enc = (OpusEncoder*)ptr;
479 if (s < st->layout.nb_coupled_streams)
480 ptr += align(coupled_size);
481 else
482 ptr += align(mono_size);
483 opus_encoder_ctl(enc, request, &rate);
484 *value += rate;
485 }
486 }
487 break;
488 case OPUS_GET_LSB_DEPTH_REQUEST:
489 case OPUS_GET_VBR_REQUEST:
490 case OPUS_GET_APPLICATION_REQUEST:
491 case OPUS_GET_BANDWIDTH_REQUEST:
492 case OPUS_GET_COMPLEXITY_REQUEST:
493 case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
494 case OPUS_GET_DTX_REQUEST:
495 case OPUS_GET_VOICE_RATIO_REQUEST:
496 case OPUS_GET_VBR_CONSTRAINT_REQUEST:
497 case OPUS_GET_SIGNAL_REQUEST:
498 case OPUS_GET_LOOKAHEAD_REQUEST:
499 case OPUS_GET_SAMPLE_RATE_REQUEST:
500 case OPUS_GET_INBAND_FEC_REQUEST:
501 case OPUS_GET_FORCE_CHANNELS_REQUEST:
502 {
503 OpusEncoder *enc;
504 /* For int32* GET params, just query the first stream */
505 opus_int32 *value = va_arg(ap, opus_int32*);
506 enc = (OpusEncoder*)ptr;
507 ret = opus_encoder_ctl(enc, request, value);
508 }
509 break;
510 case OPUS_GET_FINAL_RANGE_REQUEST:
511 {
512 int s;
513 opus_uint32 *value = va_arg(ap, opus_uint32*);
514 opus_uint32 tmp;
515 *value=0;
516 for (s=0;s<st->layout.nb_streams;s++)
517 {
518 OpusEncoder *enc;
519 enc = (OpusEncoder*)ptr;
520 if (s < st->layout.nb_coupled_streams)
521 ptr += align(coupled_size);
522 else
523 ptr += align(mono_size);
524 ret = opus_encoder_ctl(enc, request, &tmp);
525 if (ret != OPUS_OK) break;
526 *value ^= tmp;
527 }
528 }
529 break;
530 case OPUS_SET_LSB_DEPTH_REQUEST:
531 case OPUS_SET_COMPLEXITY_REQUEST:
532 case OPUS_SET_VBR_REQUEST:
533 case OPUS_SET_VBR_CONSTRAINT_REQUEST:
534 case OPUS_SET_BANDWIDTH_REQUEST:
535 case OPUS_SET_SIGNAL_REQUEST:
536 case OPUS_SET_APPLICATION_REQUEST:
537 case OPUS_SET_INBAND_FEC_REQUEST:
538 case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
539 case OPUS_SET_DTX_REQUEST:
540 case OPUS_SET_FORCE_MODE_REQUEST:
541 case OPUS_SET_FORCE_CHANNELS_REQUEST:
542 {
543 int s;
544 /* This works for int32 params */
545 opus_int32 value = va_arg(ap, opus_int32);
546 for (s=0;s<st->layout.nb_streams;s++)
547 {
548 OpusEncoder *enc;
549
550 enc = (OpusEncoder*)ptr;
551 if (s < st->layout.nb_coupled_streams)
552 ptr += align(coupled_size);
553 else
554 ptr += align(mono_size);
555 ret = opus_encoder_ctl(enc, request, value);
556 if (ret != OPUS_OK)
557 break;
558 }
559 }
560 break;
561 case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
562 {
563 int s;
564 opus_int32 stream_id;
565 OpusEncoder **value;
566 stream_id = va_arg(ap, opus_int32);
567 if (stream_id<0 || stream_id >= st->layout.nb_streams)
568 ret = OPUS_BAD_ARG;
569 value = va_arg(ap, OpusEncoder**);
570 for (s=0;s<stream_id;s++)
571 {
572 if (s < st->layout.nb_coupled_streams)
573 ptr += align(coupled_size);
574 else
575 ptr += align(mono_size);
576 }
577 *value = (OpusEncoder*)ptr;
578 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500579 break;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500580 case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
Jean-Marc Valin74483662012-12-17 16:23:42 -0500581 {
582 opus_int32 value = va_arg(ap, opus_int32);
Jean-Marc Valin74483662012-12-17 16:23:42 -0500583 st->variable_duration = value;
584 }
585 break;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500586 case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
Jean-Marc Valin74483662012-12-17 16:23:42 -0500587 {
588 opus_int32 *value = va_arg(ap, opus_int32*);
589 *value = st->variable_duration;
590 }
591 break;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500592 default:
593 ret = OPUS_UNIMPLEMENTED;
594 break;
595 }
596
597 va_end(ap);
598 return ret;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500599bad_arg:
600 va_end(ap);
601 return OPUS_BAD_ARG;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500602}
603
604void opus_multistream_encoder_destroy(OpusMSEncoder *st)
605{
606 opus_free(st);
607}
608
609