blob: 3efab53dfc12a2291d6a1e51d9168f50102e62b5 [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 Valin49587512013-07-07 02:50:18 -040040#include "mathops.h"
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050041
Jean-Marc Valin7a8b1392013-04-29 18:32:27 -040042typedef struct {
43 int nb_streams;
44 int nb_coupled_streams;
45 unsigned char mapping[8];
46} VorbisLayout;
47
48/* Index is nb_channel-1*/
49static const VorbisLayout vorbis_mappings[8] = {
50 {1, 0, {0}}, /* 1: mono */
51 {1, 1, {0, 1}}, /* 2: stereo */
52 {2, 1, {0, 2, 1}}, /* 3: 1-d surround */
53 {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */
54 {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */
55 {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */
56 {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */
57 {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */
58};
59
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050060struct OpusMSEncoder {
Jean-Marc Valin51f4a322013-02-20 04:08:04 -050061 TonalityAnalysisState analysis;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050062 ChannelLayout layout;
Jean-Marc Valin1b723862013-04-25 21:34:04 -040063 int lfe_stream;
Jean-Marc Valin74483662012-12-17 16:23:42 -050064 int variable_duration;
Jean-Marc Valina4dccd32013-05-04 23:54:20 -040065 int surround;
Jean-Marc Valin74483662012-12-17 16:23:42 -050066 opus_int32 bitrate_bps;
67 opus_val32 subframe_mem[3];
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050068 /* Encoder states go here */
69};
70
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -050071
72static int validate_encoder_layout(const ChannelLayout *layout)
73{
74 int s;
75 for (s=0;s<layout->nb_streams;s++)
76 {
77 if (s < layout->nb_coupled_streams)
78 {
79 if (get_left_channel(layout, s, -1)==-1)
80 return 0;
81 if (get_right_channel(layout, s, -1)==-1)
82 return 0;
83 } else {
84 if (get_mono_channel(layout, s, -1)==-1)
85 return 0;
86 }
87 }
88 return 1;
89}
90
91
92opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
93{
94 int coupled_size;
95 int mono_size;
96
97 if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
98 coupled_size = opus_encoder_get_size(2);
99 mono_size = opus_encoder_get_size(1);
100 return align(sizeof(OpusMSEncoder))
101 + nb_coupled_streams * align(coupled_size)
102 + (nb_streams-nb_coupled_streams) * align(mono_size);
103}
104
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400105opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family)
106{
107 int nb_streams;
108 int nb_coupled_streams;
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400109 opus_int32 size;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400110
Jean-Marc Valin7a8b1392013-04-29 18:32:27 -0400111 if (mapping_family==0)
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400112 {
Jean-Marc Valin7a8b1392013-04-29 18:32:27 -0400113 if (channels==1)
114 {
115 nb_streams=1;
116 nb_coupled_streams=0;
117 } else if (channels==2)
118 {
119 nb_streams=1;
120 nb_coupled_streams=1;
121 } else
122 return 0;
123 } else if (mapping_family==1 && channels<=8 && channels>=1)
124 {
125 nb_streams=vorbis_mappings[channels-1].nb_streams;
126 nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
127 } else if (mapping_family==255)
128 {
129 nb_streams=channels;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400130 nb_coupled_streams=0;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400131 } else
132 return 0;
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400133 size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
134 if (channels>2)
135 size += align(opus_encoder_get_size(2));
136 return size;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400137}
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500138
139
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400140static int opus_multistream_encoder_init_impl(
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500141 OpusMSEncoder *st,
142 opus_int32 Fs,
143 int channels,
144 int streams,
145 int coupled_streams,
146 const unsigned char *mapping,
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400147 int application,
148 int surround
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500149)
150{
151 int coupled_size;
152 int mono_size;
153 int i, ret;
154 char *ptr;
155
156 if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
157 (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
158 return OPUS_BAD_ARG;
159
160 st->layout.nb_channels = channels;
161 st->layout.nb_streams = streams;
162 st->layout.nb_coupled_streams = coupled_streams;
Jean-Marc Valinb0429352013-05-05 02:22:06 -0400163 st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0;
164 OPUS_CLEAR(&st->analysis,1);
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400165 if (!surround)
166 st->lfe_stream = -1;
Jean-Marc Valin95561be2012-12-17 17:54:01 -0500167 st->bitrate_bps = OPUS_AUTO;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500168 st->variable_duration = OPUS_FRAMESIZE_ARG;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500169 for (i=0;i<st->layout.nb_channels;i++)
170 st->layout.mapping[i] = mapping[i];
171 if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
172 return OPUS_BAD_ARG;
173 ptr = (char*)st + align(sizeof(OpusMSEncoder));
174 coupled_size = opus_encoder_get_size(2);
175 mono_size = opus_encoder_get_size(1);
176
177 for (i=0;i<st->layout.nb_coupled_streams;i++)
178 {
179 ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400180 if(ret!=OPUS_OK)return ret;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400181 if (i==st->lfe_stream)
182 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500183 ptr += align(coupled_size);
184 }
185 for (;i<st->layout.nb_streams;i++)
186 {
187 ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400188 if (i==st->lfe_stream)
189 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500190 if(ret!=OPUS_OK)return ret;
191 ptr += align(mono_size);
192 }
Jean-Marc Valin58d80ab2013-05-27 20:47:47 -0400193 if (surround)
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400194 {
195 OpusEncoder *downmix_enc;
196 downmix_enc = (OpusEncoder*)ptr;
197 ret = opus_encoder_init(downmix_enc, Fs, 2, OPUS_APPLICATION_AUDIO);
198 if(ret!=OPUS_OK)return ret;
199 }
200 st->surround = surround;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500201 return OPUS_OK;
202}
203
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400204int opus_multistream_encoder_init(
205 OpusMSEncoder *st,
206 opus_int32 Fs,
207 int channels,
208 int streams,
209 int coupled_streams,
210 const unsigned char *mapping,
211 int application
212)
213{
214 return opus_multistream_encoder_init_impl(st, Fs, channels, streams, coupled_streams, mapping, application, 0);
215}
216
217int opus_multistream_surround_encoder_init(
218 OpusMSEncoder *st,
219 opus_int32 Fs,
220 int channels,
221 int mapping_family,
222 int *streams,
223 int *coupled_streams,
224 unsigned char *mapping,
225 int application
226)
227{
Jean-Marc Valin337f34c2013-07-01 16:17:01 -0400228 if ((channels>255) || (channels<1))
229 return OPUS_BAD_ARG;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400230 st->lfe_stream = -1;
Jean-Marc Valin7a8b1392013-04-29 18:32:27 -0400231 if (mapping_family==0)
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400232 {
Jean-Marc Valin7a8b1392013-04-29 18:32:27 -0400233 if (channels==1)
234 {
235 *streams=1;
236 *coupled_streams=0;
237 mapping[0]=0;
238 } else if (channels==2)
239 {
240 *streams=1;
241 *coupled_streams=1;
242 mapping[0]=0;
243 mapping[1]=1;
244 } else
245 return OPUS_UNIMPLEMENTED;
246 } else if (mapping_family==1 && channels<=8 && channels>=1)
247 {
248 int i;
249 *streams=vorbis_mappings[channels-1].nb_streams;
250 *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
251 for (i=0;i<channels;i++)
252 mapping[i] = vorbis_mappings[channels-1].mapping[i];
253 if (channels>=6)
254 st->lfe_stream = *streams-1;
255 } else if (mapping_family==255)
256 {
257 int i;
258 *streams=channels;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400259 *coupled_streams=0;
Jean-Marc Valin7a8b1392013-04-29 18:32:27 -0400260 for(i=0;i<channels;i++)
261 mapping[i] = i;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400262 } else
Jean-Marc Valin7a8b1392013-04-29 18:32:27 -0400263 return OPUS_UNIMPLEMENTED;
Jean-Marc Valin337f34c2013-07-01 16:17:01 -0400264 return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, *coupled_streams,
Jean-Marc Valin58d80ab2013-05-27 20:47:47 -0400265 mapping, application, channels>2&&mapping_family==1);
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400266}
267
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500268OpusMSEncoder *opus_multistream_encoder_create(
269 opus_int32 Fs,
270 int channels,
271 int streams,
272 int coupled_streams,
273 const unsigned char *mapping,
274 int application,
275 int *error
276)
277{
278 int ret;
279 OpusMSEncoder *st;
280 if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
281 (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
282 {
283 if (error)
284 *error = OPUS_BAD_ARG;
285 return NULL;
286 }
287 st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams));
288 if (st==NULL)
289 {
290 if (error)
291 *error = OPUS_ALLOC_FAIL;
292 return NULL;
293 }
294 ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
295 if (ret != OPUS_OK)
296 {
297 opus_free(st);
298 st = NULL;
299 }
300 if (error)
301 *error = ret;
302 return st;
303}
304
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400305OpusMSEncoder *opus_multistream_surround_encoder_create(
306 opus_int32 Fs,
307 int channels,
308 int mapping_family,
309 int *streams,
310 int *coupled_streams,
311 unsigned char *mapping,
312 int application,
313 int *error
314)
315{
316 int ret;
317 OpusMSEncoder *st;
318 if ((channels>255) || (channels<1))
319 {
320 if (error)
321 *error = OPUS_BAD_ARG;
322 return NULL;
323 }
324 st = (OpusMSEncoder *)opus_alloc(opus_multistream_surround_encoder_get_size(channels, mapping_family));
325 if (st==NULL)
326 {
327 if (error)
328 *error = OPUS_ALLOC_FAIL;
329 return NULL;
330 }
331 ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application);
332 if (ret != OPUS_OK)
333 {
334 opus_free(st);
335 st = NULL;
336 }
337 if (error)
338 *error = ret;
339 return st;
340}
341
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500342typedef void (*opus_copy_channel_in_func)(
343 opus_val16 *dst,
344 int dst_stride,
345 const void *src,
346 int src_stride,
347 int src_channel,
348 int frame_size
349);
350
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400351typedef void (*opus_surround_downmix_funct)(
352 opus_val16 *dst,
353 const void *src,
354 int channels,
355 int frame_size
356);
357
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400358static void surround_rate_allocation(
359 OpusMSEncoder *st,
360 opus_int32 *rate,
361 int frame_size
362 )
363{
364 int i;
365 opus_int32 channel_rate;
366 opus_int32 Fs;
367 char *ptr;
Jean-Marc Valind66bdc72013-05-06 16:03:39 -0400368 int stream_offset;
369 int lfe_offset;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400370 int coupled_ratio; /* Q8 */
371 int lfe_ratio; /* Q8 */
372
373 ptr = (char*)st + align(sizeof(OpusMSEncoder));
374 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
375
Jean-Marc Valin49587512013-07-07 02:50:18 -0400376 if (st->bitrate_bps > st->layout.nb_channels*40000)
377 stream_offset = 20000;
378 else
379 stream_offset = st->bitrate_bps/st->layout.nb_channels/2;
Jean-Marc Valind66bdc72013-05-06 16:03:39 -0400380 /* We start by giving each stream (coupled or uncoupled) the same bitrate.
381 This models the main saving of coupled channels over uncoupled. */
Jean-Marc Valind66bdc72013-05-06 16:03:39 -0400382 /* The LFE stream is an exception to the above and gets fewer bits. */
383 lfe_offset = 3500;
384 /* Coupled streams get twice the mono rate after the first 20 kb/s. */
385 coupled_ratio = 512;
386 /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400387 lfe_ratio = 32;
388
389 /* Compute bitrate allocation between streams */
390 if (st->bitrate_bps==OPUS_AUTO)
391 {
392 channel_rate = Fs+60*Fs/frame_size;
393 } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
394 {
395 channel_rate = 300000;
396 } else {
Jean-Marc Valind66bdc72013-05-06 16:03:39 -0400397 int nb_lfe;
398 int nb_uncoupled;
399 int nb_coupled;
400 int total;
401 nb_lfe = (st->lfe_stream!=-1);
402 nb_coupled = st->layout.nb_coupled_streams;
403 nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe;
404 total = (nb_uncoupled<<8) /* mono */
405 + coupled_ratio*nb_coupled /* stereo */
406 + nb_lfe*lfe_ratio;
407 channel_rate = 256*(st->bitrate_bps-lfe_offset*nb_lfe-stream_offset*(nb_coupled+nb_uncoupled))/total;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400408 }
409#ifndef FIXED_POINT
410 if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
411 {
412 opus_int32 bonus;
413 bonus = 60*(Fs/frame_size-50);
414 channel_rate += bonus;
415 }
416#endif
417
418 for (i=0;i<st->layout.nb_streams;i++)
419 {
420 if (i<st->layout.nb_coupled_streams)
Jean-Marc Valind66bdc72013-05-06 16:03:39 -0400421 rate[i] = stream_offset+(channel_rate*coupled_ratio>>8);
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400422 else if (i!=st->lfe_stream)
Jean-Marc Valind66bdc72013-05-06 16:03:39 -0400423 rate[i] = stream_offset+channel_rate;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400424 else
Jean-Marc Valind66bdc72013-05-06 16:03:39 -0400425 rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8);
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400426 }
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400427}
428
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500429/* Max size in case the encoder decides to return three frames */
430#define MS_FRAME_TMP (3*1275+7)
431static int opus_multistream_encode_native
432(
433 OpusMSEncoder *st,
434 opus_copy_channel_in_func copy_channel_in,
435 const void *pcm,
436 int frame_size,
437 unsigned char *data,
Jean-Marc Valinb3eba242012-12-20 23:11:53 -0500438 opus_int32 max_data_bytes,
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400439 int lsb_depth,
440 opus_surround_downmix_funct surround_downmix
Jean-Marc Valin10a34a52012-12-20 00:23:01 -0500441#ifndef FIXED_POINT
442 , downmix_func downmix
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500443 , const void *pcm_analysis
Jean-Marc Valin10a34a52012-12-20 00:23:01 -0500444#endif
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500445)
446{
447 opus_int32 Fs;
448 int coupled_size;
449 int mono_size;
450 int s;
451 char *ptr;
452 int tot_size;
453 VARDECL(opus_val16, buf);
454 unsigned char tmp_data[MS_FRAME_TMP];
455 OpusRepacketizer rp;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500456 opus_int32 complexity;
457 AnalysisInfo analysis_info;
458 const CELTMode *celt_mode;
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400459 opus_int32 bitrates[256];
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400460 opus_val16 bandLogE[42];
461 opus_val16 bandLogE_mono[21];
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500462 ALLOC_STACK;
463
464 ptr = (char*)st + align(sizeof(OpusMSEncoder));
465 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500466 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_COMPLEXITY(&complexity));
467 opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
Jean-Marc Valin74483662012-12-17 16:23:42 -0500468
469 if (400*frame_size < Fs)
470 {
471 RESTORE_STACK;
472 return OPUS_BAD_ARG;
473 }
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500474#ifndef FIXED_POINT
475 analysis_info.valid = 0;
476 if (complexity >= 7 && Fs==48000)
Jean-Marc Valin74483662012-12-17 16:23:42 -0500477 {
Jean-Marc Valin74483662012-12-17 16:23:42 -0500478 opus_int32 delay_compensation;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500479 int channels;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500480
481 channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
482 opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
483 delay_compensation -= Fs/400;
Jean-Marc Valin74483662012-12-17 16:23:42 -0500484
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500485 frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm_analysis,
486 frame_size, st->variable_duration, channels, Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix, &analysis_info);
487 } else
488#endif
489 {
490 frame_size = frame_size_select(frame_size, st->variable_duration, Fs);
491 }
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500492 /* Validate frame_size before using it to allocate stack space.
493 This mirrors the checks in opus_encode[_float](). */
494 if (400*frame_size != Fs && 200*frame_size != Fs &&
495 100*frame_size != Fs && 50*frame_size != Fs &&
496 25*frame_size != Fs && 50*frame_size != 3*Fs)
497 {
498 RESTORE_STACK;
499 return OPUS_BAD_ARG;
500 }
501 ALLOC(buf, 2*frame_size, opus_val16);
502 coupled_size = opus_encoder_get_size(2);
503 mono_size = opus_encoder_get_size(1);
504
Jean-Marc Valin58d80ab2013-05-27 20:47:47 -0400505 if (st->surround)
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400506 {
507 int i;
508 unsigned char dummy[512];
509 /* Temporary kludge -- remove */
510 OpusEncoder *downmix_enc;
511
512 ptr = (char*)st + align(sizeof(OpusMSEncoder));
513 for (s=0;s<st->layout.nb_streams;s++)
514 {
515 if (s < st->layout.nb_coupled_streams)
516 ptr += align(coupled_size);
517 else
518 ptr += align(mono_size);
519 }
520 downmix_enc = (OpusEncoder*)ptr;
521 surround_downmix(buf, pcm, st->layout.nb_channels, frame_size);
522 opus_encoder_ctl(downmix_enc, OPUS_SET_ENERGY_SAVE(bandLogE));
523 opus_encoder_ctl(downmix_enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
524 opus_encoder_ctl(downmix_enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
525 opus_encoder_ctl(downmix_enc, OPUS_SET_FORCE_CHANNELS(2));
526 opus_encode_native(downmix_enc, buf, frame_size, dummy, 512, lsb_depth
527#ifndef FIXED_POINT
528 , &analysis_info
529#endif
530 );
Jean-Marc Valin49587512013-07-07 02:50:18 -0400531 /* Combines the left and right mask into a centre mask. We
532 use an approximation for the log of the sum of the energies. */
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400533 for(i=0;i<21;i++)
Jean-Marc Valin49587512013-07-07 02:50:18 -0400534 {
535 opus_val16 diff;
536 diff = ABS16(SUB16(bandLogE[i], bandLogE[21+i]));
537 diff = diff + HALF16(diff);
538 diff = SHR32(HALF32(celt_exp2(-diff)), 16-DB_SHIFT);
539 bandLogE_mono[i] = MAX16(bandLogE[i], bandLogE[21+i]) + diff;
540 }
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400541 }
542
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500543 if (max_data_bytes < 4*st->layout.nb_streams-1)
544 {
545 RESTORE_STACK;
546 return OPUS_BUFFER_TOO_SMALL;
547 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500548
549 /* Compute bitrate allocation between streams (this could be a lot better) */
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400550 surround_rate_allocation(st, bitrates, frame_size);
551
Jean-Marc Valin74483662012-12-17 16:23:42 -0500552 ptr = (char*)st + align(sizeof(OpusMSEncoder));
553 for (s=0;s<st->layout.nb_streams;s++)
554 {
555 OpusEncoder *enc;
556 enc = (OpusEncoder*)ptr;
557 if (s < st->layout.nb_coupled_streams)
558 ptr += align(coupled_size);
559 else
560 ptr += align(mono_size);
Jean-Marc Valin1b723862013-04-25 21:34:04 -0400561 opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s]));
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400562 if (st->surround)
563 {
564 opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
565 opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
566 if (s < st->layout.nb_coupled_streams)
567 opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2));
568 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500569 }
570
571 ptr = (char*)st + align(sizeof(OpusMSEncoder));
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500572 /* Counting ToC */
573 tot_size = 0;
574 for (s=0;s<st->layout.nb_streams;s++)
575 {
576 OpusEncoder *enc;
577 int len;
578 int curr_max;
579
580 opus_repacketizer_init(&rp);
581 enc = (OpusEncoder*)ptr;
582 if (s < st->layout.nb_coupled_streams)
583 {
584 int left, right;
585 left = get_left_channel(&st->layout, s, -1);
586 right = get_right_channel(&st->layout, s, -1);
587 (*copy_channel_in)(buf, 2,
588 pcm, st->layout.nb_channels, left, frame_size);
589 (*copy_channel_in)(buf+1, 2,
590 pcm, st->layout.nb_channels, right, frame_size);
591 ptr += align(coupled_size);
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400592 /* FIXME: This isn't correct for the coupled center channels in
593 6.1 surround configuration */
594 if (st->surround)
595 opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500596 } else {
597 int chan = get_mono_channel(&st->layout, s, -1);
598 (*copy_channel_in)(buf, 1,
599 pcm, st->layout.nb_channels, chan, frame_size);
600 ptr += align(mono_size);
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400601 if (st->surround)
602 opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE_mono));
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500603 }
604 /* number of bytes left (+Toc) */
605 curr_max = max_data_bytes - tot_size;
606 /* Reserve three bytes for the last stream and four for the others */
607 curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1);
608 curr_max = IMIN(curr_max,MS_FRAME_TMP);
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500609 len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth
610#ifndef FIXED_POINT
611 , &analysis_info
612#endif
613 );
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500614 if (len<0)
615 {
616 RESTORE_STACK;
617 return len;
618 }
619 /* We need to use the repacketizer to add the self-delimiting lengths
620 while taking into account the fact that the encoder can now return
621 more than one frame at a time (e.g. 60 ms CELT-only) */
622 opus_repacketizer_cat(&rp, tmp_data, len);
623 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);
624 data += len;
625 tot_size += len;
626 }
627 RESTORE_STACK;
628 return tot_size;
629
630}
631
632#if !defined(DISABLE_FLOAT_API)
633static void opus_copy_channel_in_float(
634 opus_val16 *dst,
635 int dst_stride,
636 const void *src,
637 int src_stride,
638 int src_channel,
639 int frame_size
640)
641{
642 const float *float_src;
Timothy B. Terriberrya8f04b22013-03-18 14:42:44 -0700643 opus_int32 i;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500644 float_src = (const float *)src;
645 for (i=0;i<frame_size;i++)
646#if defined(FIXED_POINT)
647 dst[i*dst_stride] = FLOAT2INT16(float_src[i*src_stride+src_channel]);
648#else
649 dst[i*dst_stride] = float_src[i*src_stride+src_channel];
650#endif
651}
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400652
653static void channel_pos(int channels, int pos[8])
654{
655 /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */
656 if (channels==4)
657 {
658 pos[0]=1;
659 pos[1]=3;
660 pos[2]=1;
661 pos[3]=3;
662 } else if (channels==3||channels==5||channels==6)
663 {
664 pos[0]=1;
665 pos[1]=2;
666 pos[2]=3;
667 pos[3]=1;
668 pos[4]=3;
669 pos[5]=0;
670 } else if (channels==7)
671 {
672 pos[0]=1;
673 pos[1]=2;
674 pos[2]=3;
675 pos[3]=1;
676 pos[4]=3;
677 pos[5]=2;
678 pos[6]=0;
679 } else if (channels==8)
680 {
681 pos[0]=1;
682 pos[1]=2;
683 pos[2]=3;
684 pos[3]=1;
685 pos[4]=3;
686 pos[5]=1;
687 pos[6]=3;
688 pos[7]=0;
689 }
690}
691
692static void opus_surround_downmix_float(
693 opus_val16 *dst,
694 const void *src,
695 int channels,
696 int frame_size
697)
698{
699 const float *float_src;
700 opus_int32 i;
701 int pos[8] = {0};
702 int c;
703 float_src = (const float *)src;
704
705 channel_pos(channels, pos);
706 for (i=0;i<2*frame_size;i++)
707 dst[i]=0;
708
709 for (c=0;c<channels;c++)
710 {
Jean-Marc Valin49587512013-07-07 02:50:18 -0400711 if (pos[c]==1)
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400712 {
713 for (i=0;i<frame_size;i++)
714#if defined(FIXED_POINT)
715 dst[2*i] += SHR16(FLOAT2INT16(float_src[i*channels+c]),3);
716#else
717 dst[2*i] += float_src[i*channels+c];
718#endif
Jean-Marc Valin49587512013-07-07 02:50:18 -0400719 } else if (pos[c]==3)
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400720 {
721 for (i=0;i<frame_size;i++)
722#if defined(FIXED_POINT)
723 dst[2*i+1] += SHR16(FLOAT2INT16(float_src[i*channels+c]),3);
724#else
725 dst[2*i+1] += float_src[i*channels+c];
726#endif
Jean-Marc Valin49587512013-07-07 02:50:18 -0400727 } else if (pos[c]==2)
728 {
729 for (i=0;i<frame_size;i++)
730 {
731#if defined(FIXED_POINT)
732 dst[2*i] += SHR32(MULT16_16(QCONST16(.70711f,15), FLOAT2INT16(float_src[i*channels+c])),3+15);
733 dst[2*i+1] += SHR32(MULT16_16(QCONST16(.70711f,15), FLOAT2INT16(float_src[i*channels+c])),3+15);
734#else
735 dst[2*i] += .707*float_src[i*channels+c];
736 dst[2*i+1] += .707*float_src[i*channels+c];
737#endif
738 }
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400739 }
740 }
741}
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500742#endif
743
744static void opus_copy_channel_in_short(
745 opus_val16 *dst,
746 int dst_stride,
747 const void *src,
748 int src_stride,
749 int src_channel,
750 int frame_size
751)
752{
753 const opus_int16 *short_src;
Timothy B. Terriberrya8f04b22013-03-18 14:42:44 -0700754 opus_int32 i;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500755 short_src = (const opus_int16 *)src;
756 for (i=0;i<frame_size;i++)
757#if defined(FIXED_POINT)
758 dst[i*dst_stride] = short_src[i*src_stride+src_channel];
759#else
760 dst[i*dst_stride] = (1/32768.f)*short_src[i*src_stride+src_channel];
761#endif
762}
763
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400764static void opus_surround_downmix_short(
765 opus_val16 *dst,
766 const void *src,
767 int channels,
768 int frame_size
769)
770{
771 const opus_int16 *short_src;
772 opus_int32 i;
773 int pos[8] = {0};
774 int c;
775 short_src = (const opus_int16 *)src;
776
777 channel_pos(channels, pos);
778 for (i=0;i<2*frame_size;i++)
779 dst[i]=0;
780
781 for (c=0;c<channels;c++)
782 {
Jean-Marc Valin49587512013-07-07 02:50:18 -0400783 if (pos[c]==1)
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400784 {
785 for (i=0;i<frame_size;i++)
786#if defined(FIXED_POINT)
787 dst[2*i] += SHR16(short_src[i*channels+c],3);
788#else
789 dst[2*i] += (1/32768.f)*short_src[i*channels+c];
790#endif
Jean-Marc Valin49587512013-07-07 02:50:18 -0400791 } else if (pos[c]==3)
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400792 {
793 for (i=0;i<frame_size;i++)
794#if defined(FIXED_POINT)
795 dst[2*i+1] += SHR16(short_src[i*channels+c],3);
796#else
797 dst[2*i+1] += (1/32768.f)*short_src[i*channels+c];
798#endif
Jean-Marc Valin49587512013-07-07 02:50:18 -0400799 } else if (pos[c]==2)
800 {
801 for (i=0;i<frame_size;i++)
802 {
803#if defined(FIXED_POINT)
804 dst[2*i] += SHR32(MULT16_16(QCONST16(.70711f,15), short_src[i*channels+c]),3+15);
805 dst[2*i+1] += SHR32(MULT16_16(QCONST16(.70711f,15), short_src[i*channels+c]),3+15);
806#else
807 dst[2*i] += (.707f/32768.f)*short_src[i*channels+c];
808 dst[2*i+1] += (.707f/32768.f)*short_src[i*channels+c];
809#endif
810 }
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400811 }
812 }
813}
814
815
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500816#ifdef FIXED_POINT
817int opus_multistream_encode(
818 OpusMSEncoder *st,
819 const opus_val16 *pcm,
820 int frame_size,
821 unsigned char *data,
822 opus_int32 max_data_bytes
823)
824{
825 return opus_multistream_encode_native(st, opus_copy_channel_in_short,
Jean-Marc Valin2f7a3152013-07-07 01:11:23 -0400826 pcm, frame_size, data, max_data_bytes, 16, opus_surround_downmix_short);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500827}
828
829#ifndef DISABLE_FLOAT_API
830int opus_multistream_encode_float(
831 OpusMSEncoder *st,
832 const float *pcm,
833 int frame_size,
834 unsigned char *data,
835 opus_int32 max_data_bytes
836)
837{
838 return opus_multistream_encode_native(st, opus_copy_channel_in_float,
Jean-Marc Valin2f7a3152013-07-07 01:11:23 -0400839 pcm, frame_size, data, max_data_bytes, 16, opus_surround_downmix_float);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500840}
841#endif
842
843#else
844
845int opus_multistream_encode_float
846(
847 OpusMSEncoder *st,
848 const opus_val16 *pcm,
849 int frame_size,
850 unsigned char *data,
851 opus_int32 max_data_bytes
852)
853{
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500854 int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500855 return opus_multistream_encode_native(st, opus_copy_channel_in_float,
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400856 pcm, frame_size, data, max_data_bytes, 24, opus_surround_downmix_float, downmix_float, pcm+channels*st->analysis.analysis_offset);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500857}
858
859int opus_multistream_encode(
860 OpusMSEncoder *st,
861 const opus_int16 *pcm,
862 int frame_size,
863 unsigned char *data,
864 opus_int32 max_data_bytes
865)
866{
Jean-Marc Valin51f4a322013-02-20 04:08:04 -0500867 int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500868 return opus_multistream_encode_native(st, opus_copy_channel_in_short,
Jean-Marc Valina4dccd32013-05-04 23:54:20 -0400869 pcm, frame_size, data, max_data_bytes, 16, opus_surround_downmix_short, downmix_int, pcm+channels*st->analysis.analysis_offset);
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500870}
871#endif
872
873int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
874{
875 va_list ap;
876 int coupled_size, mono_size;
877 char *ptr;
878 int ret = OPUS_OK;
879
880 va_start(ap, request);
881
882 coupled_size = opus_encoder_get_size(2);
883 mono_size = opus_encoder_get_size(1);
884 ptr = (char*)st + align(sizeof(OpusMSEncoder));
885 switch (request)
886 {
887 case OPUS_SET_BITRATE_REQUEST:
888 {
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500889 opus_int32 value = va_arg(ap, opus_int32);
Gregory Maxwella0d096f2013-06-29 20:33:32 -0700890 if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX)
891 {
Jean-Marc Valin95561be2012-12-17 17:54:01 -0500892 goto bad_arg;
Gregory Maxwellb271dae2013-06-29 20:25:55 -0700893 }
Jean-Marc Valin74483662012-12-17 16:23:42 -0500894 st->bitrate_bps = value;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500895 }
896 break;
897 case OPUS_GET_BITRATE_REQUEST:
898 {
899 int s;
900 opus_int32 *value = va_arg(ap, opus_int32*);
Gregory Maxwella0d096f2013-06-29 20:33:32 -0700901 if (!value)
902 {
Gregory Maxwellb271dae2013-06-29 20:25:55 -0700903 goto bad_arg;
904 }
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500905 *value = 0;
906 for (s=0;s<st->layout.nb_streams;s++)
907 {
908 opus_int32 rate;
909 OpusEncoder *enc;
910 enc = (OpusEncoder*)ptr;
911 if (s < st->layout.nb_coupled_streams)
912 ptr += align(coupled_size);
913 else
914 ptr += align(mono_size);
915 opus_encoder_ctl(enc, request, &rate);
916 *value += rate;
917 }
918 }
919 break;
920 case OPUS_GET_LSB_DEPTH_REQUEST:
921 case OPUS_GET_VBR_REQUEST:
922 case OPUS_GET_APPLICATION_REQUEST:
923 case OPUS_GET_BANDWIDTH_REQUEST:
924 case OPUS_GET_COMPLEXITY_REQUEST:
925 case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
926 case OPUS_GET_DTX_REQUEST:
927 case OPUS_GET_VOICE_RATIO_REQUEST:
928 case OPUS_GET_VBR_CONSTRAINT_REQUEST:
929 case OPUS_GET_SIGNAL_REQUEST:
930 case OPUS_GET_LOOKAHEAD_REQUEST:
931 case OPUS_GET_SAMPLE_RATE_REQUEST:
932 case OPUS_GET_INBAND_FEC_REQUEST:
933 case OPUS_GET_FORCE_CHANNELS_REQUEST:
934 {
935 OpusEncoder *enc;
936 /* For int32* GET params, just query the first stream */
937 opus_int32 *value = va_arg(ap, opus_int32*);
938 enc = (OpusEncoder*)ptr;
939 ret = opus_encoder_ctl(enc, request, value);
940 }
941 break;
942 case OPUS_GET_FINAL_RANGE_REQUEST:
943 {
944 int s;
945 opus_uint32 *value = va_arg(ap, opus_uint32*);
946 opus_uint32 tmp;
Gregory Maxwella0d096f2013-06-29 20:33:32 -0700947 if (!value)
948 {
Gregory Maxwellb271dae2013-06-29 20:25:55 -0700949 goto bad_arg;
950 }
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -0500951 *value=0;
952 for (s=0;s<st->layout.nb_streams;s++)
953 {
954 OpusEncoder *enc;
955 enc = (OpusEncoder*)ptr;
956 if (s < st->layout.nb_coupled_streams)
957 ptr += align(coupled_size);
958 else
959 ptr += align(mono_size);
960 ret = opus_encoder_ctl(enc, request, &tmp);
961 if (ret != OPUS_OK) break;
962 *value ^= tmp;
963 }
964 }
965 break;
966 case OPUS_SET_LSB_DEPTH_REQUEST:
967 case OPUS_SET_COMPLEXITY_REQUEST:
968 case OPUS_SET_VBR_REQUEST:
969 case OPUS_SET_VBR_CONSTRAINT_REQUEST:
970 case OPUS_SET_BANDWIDTH_REQUEST:
971 case OPUS_SET_SIGNAL_REQUEST:
972 case OPUS_SET_APPLICATION_REQUEST:
973 case OPUS_SET_INBAND_FEC_REQUEST:
974 case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
975 case OPUS_SET_DTX_REQUEST:
976 case OPUS_SET_FORCE_MODE_REQUEST:
977 case OPUS_SET_FORCE_CHANNELS_REQUEST:
978 {
979 int s;
980 /* This works for int32 params */
981 opus_int32 value = va_arg(ap, opus_int32);
982 for (s=0;s<st->layout.nb_streams;s++)
983 {
984 OpusEncoder *enc;
985
986 enc = (OpusEncoder*)ptr;
987 if (s < st->layout.nb_coupled_streams)
988 ptr += align(coupled_size);
989 else
990 ptr += align(mono_size);
991 ret = opus_encoder_ctl(enc, request, value);
992 if (ret != OPUS_OK)
993 break;
994 }
995 }
996 break;
997 case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
998 {
999 int s;
1000 opus_int32 stream_id;
1001 OpusEncoder **value;
1002 stream_id = va_arg(ap, opus_int32);
1003 if (stream_id<0 || stream_id >= st->layout.nb_streams)
1004 ret = OPUS_BAD_ARG;
1005 value = va_arg(ap, OpusEncoder**);
Gregory Maxwella0d096f2013-06-29 20:33:32 -07001006 if (!value)
1007 {
Gregory Maxwellb271dae2013-06-29 20:25:55 -07001008 goto bad_arg;
1009 }
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -05001010 for (s=0;s<stream_id;s++)
1011 {
1012 if (s < st->layout.nb_coupled_streams)
1013 ptr += align(coupled_size);
1014 else
1015 ptr += align(mono_size);
1016 }
1017 *value = (OpusEncoder*)ptr;
1018 }
Jean-Marc Valin74483662012-12-17 16:23:42 -05001019 break;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -05001020 case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
Jean-Marc Valin74483662012-12-17 16:23:42 -05001021 {
1022 opus_int32 value = va_arg(ap, opus_int32);
Jean-Marc Valin74483662012-12-17 16:23:42 -05001023 st->variable_duration = value;
1024 }
1025 break;
Jean-Marc Valin51f4a322013-02-20 04:08:04 -05001026 case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
Jean-Marc Valin74483662012-12-17 16:23:42 -05001027 {
1028 opus_int32 *value = va_arg(ap, opus_int32*);
Gregory Maxwella0d096f2013-06-29 20:33:32 -07001029 if (!value)
1030 {
Gregory Maxwellb271dae2013-06-29 20:25:55 -07001031 goto bad_arg;
1032 }
Jean-Marc Valin74483662012-12-17 16:23:42 -05001033 *value = st->variable_duration;
1034 }
1035 break;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -05001036 default:
1037 ret = OPUS_UNIMPLEMENTED;
1038 break;
1039 }
1040
1041 va_end(ap);
1042 return ret;
Jean-Marc Valin74483662012-12-17 16:23:42 -05001043bad_arg:
1044 va_end(ap);
1045 return OPUS_BAD_ARG;
Jean-Marc Valinae0e2ca2012-11-07 19:57:33 -05001046}
1047
1048void opus_multistream_encoder_destroy(OpusMSEncoder *st)
1049{
1050 opus_free(st);
1051}