diff --git a/include/opus_defines.h b/include/opus_defines.h
index d86fbccf..830d225f 100644
--- a/include/opus_defines.h
+++ b/include/opus_defines.h
@@ -111,7 +111,8 @@ extern "C" {
#endif
/** These are the actual Encoder CTL ID numbers.
- * They should not be used directly by applications. */
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
#define OPUS_SET_APPLICATION_REQUEST 4000
#define OPUS_GET_APPLICATION_REQUEST 4001
#define OPUS_SET_BITRATE_REQUEST 4002
@@ -138,6 +139,7 @@ extern "C" {
#define OPUS_GET_SIGNAL_REQUEST 4025
#define OPUS_GET_LOOKAHEAD_REQUEST 4027
/* #define OPUS_RESET_STATE 4028 */
+#define OPUS_GET_SAMPLE_RATE_REQUEST 4029
#define OPUS_GET_FINAL_RANGE_REQUEST 4031
#define OPUS_GET_PITCH_REQUEST 4033
#define OPUS_SET_GAIN_REQUEST 4034
@@ -422,6 +424,14 @@ extern "C" {
* @hideinitializer */
#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)
+/** Gets the sampling rate the encoder or decoder was initialized with.
+ * This simply returns the Fs
value passed to opus_encoder_init()
+ * or opus_decoder_init().
+ * @param[out] x opus_int32 *: Sampling rate of encoder or decoder.
+ * @hideinitializer
+ */
+#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
+
/** Gets the total samples of delay added by the entire codec.
* This can be queried by the encoder and then the provided number of samples can be
* skipped on from the start of the decoder's output to provide time aligned input
diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index 966ca872..161bd026 100644
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -228,6 +228,8 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
RESTORE_STACK;
return OPUS_BUFFER_TOO_SMALL;
}
+ /* Limit frame_size to avoid excessive stack allocations. */
+ frame_size = IMIN(frame_size, st->Fs/25*3);
/* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
if (len<=1)
{
@@ -856,6 +858,17 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
st->frame_size = st->Fs/400;
}
break;
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ {
+ ret = OPUS_BAD_ARG;
+ break;
+ }
+ *value = st->Fs;
+ }
+ break;
case OPUS_GET_PITCH_REQUEST:
{
opus_int32 *value = va_arg(ap, opus_int32*);
diff --git a/src/opus_encoder.c b/src/opus_encoder.c
index 1fcbf0f5..b77e48e6 100644
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -1531,6 +1531,17 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)
*value += st->delay_compensation;
}
break;
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ {
+ ret = OPUS_BAD_ARG;
+ break;
+ }
+ *value = st->Fs;
+ }
+ break;
case OPUS_GET_FINAL_RANGE_REQUEST:
{
opus_uint32 *value = va_arg(ap, opus_uint32*);
diff --git a/src/opus_multistream.c b/src/opus_multistream.c
index 623e0835..955dc818 100644
--- a/src/opus_multistream.c
+++ b/src/opus_multistream.c
@@ -55,7 +55,6 @@ struct OpusMSDecoder {
/* Decoder states go here */
};
-
#ifdef FIXED_POINT
#define opus_encode_native opus_encode
#else
@@ -221,24 +220,31 @@ OpusMSEncoder *opus_multistream_encoder_create(
return st;
}
+typedef void (*opus_copy_channel_in_func)(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+);
+
/* Max size in case the encoder decides to return three frames */
#define MS_FRAME_TMP (3*1275+7)
-#ifdef FIXED_POINT
-int opus_multistream_encode
-#else
-int opus_multistream_encode_float
-#endif
+static int opus_multistream_encode_native
(
OpusMSEncoder *st,
- const opus_val16 *pcm,
+ opus_copy_channel_in_func copy_channel_in,
+ const void *pcm,
int frame_size,
unsigned char *data,
opus_int32 max_data_bytes
)
{
+ opus_int32 Fs;
int coupled_size;
int mono_size;
- int s, i;
+ int s;
char *ptr;
int tot_size;
VARDECL(opus_val16, buf);
@@ -246,8 +252,18 @@ int opus_multistream_encode_float
OpusRepacketizer rp;
ALLOC_STACK;
- ALLOC(buf, 2*frame_size, opus_val16);
ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+ /* Validate frame_size before using it to allocate stack space.
+ This mirrors the checks in opus_encode[_float](). */
+ if (400*frame_size != Fs && 200*frame_size != Fs &&
+ 100*frame_size != Fs && 50*frame_size != Fs &&
+ 25*frame_size != Fs && 50*frame_size != 3*Fs)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ ALLOC(buf, 2*frame_size, opus_val16);
coupled_size = opus_encoder_get_size(2);
mono_size = opus_encoder_get_size(1);
@@ -271,16 +287,15 @@ int opus_multistream_encode_float
int left, right;
left = get_left_channel(&st->layout, s, -1);
right = get_right_channel(&st->layout, s, -1);
- for (i=0;ilayout.nb_channels*i+left];
- buf[2*i+1] = pcm[st->layout.nb_channels*i+right];
- }
+ (*copy_channel_in)(buf, 2,
+ pcm, st->layout.nb_channels, left, frame_size);
+ (*copy_channel_in)(buf+1, 2,
+ pcm, st->layout.nb_channels, right, frame_size);
ptr += align(coupled_size);
} else {
int chan = get_mono_channel(&st->layout, s, -1);
- for (i=0;ilayout.nb_channels*i+chan];
+ (*copy_channel_in)(buf, 1,
+ pcm, st->layout.nb_channels, chan, frame_size);
ptr += align(mono_size);
}
/* number of bytes left (+Toc) */
@@ -307,7 +322,60 @@ int opus_multistream_encode_float
}
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_in_float(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+)
+{
+ const float *float_src;
+ int i;
+ float_src = (const float *)src;
+ for (i=0;ilayout.nb_channels, opus_int16);
-
- for (i=0;ilayout.nb_channels;i++)
- in[i] = FLOAT2INT16(pcm[i]);
- ret = opus_multistream_encode(st, in, frame_size, data, max_data_bytes);
- RESTORE_STACK;
- return ret;
+ return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+ pcm, frame_size, data, max_data_bytes);
}
#endif
#else
+int opus_multistream_encode_float
+(
+ OpusMSEncoder *st,
+ const opus_val16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+ pcm, frame_size, data, max_data_bytes);
+}
+
int opus_multistream_encode(
OpusMSEncoder *st,
const opus_int16 *pcm,
@@ -342,19 +414,9 @@ int opus_multistream_encode(
opus_int32 max_data_bytes
)
{
- int i, ret;
- VARDECL(float, in);
- ALLOC_STACK;
-
- ALLOC(in, frame_size*st->layout.nb_channels, float);
-
- for (i=0;ilayout.nb_channels;i++)
- in[i] = (1.f/32768.f)*pcm[i];
- ret = opus_multistream_encode_float(st, in, frame_size, data, max_data_bytes);
- RESTORE_STACK;
- return ret;
+ return opus_multistream_encode_native(st, opus_copy_channel_in_short,
+ pcm, frame_size, data, max_data_bytes);
}
-
#endif
int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
@@ -419,6 +481,7 @@ int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
case OPUS_GET_VBR_CONSTRAINT_REQUEST:
case OPUS_GET_SIGNAL_REQUEST:
case OPUS_GET_LOOKAHEAD_REQUEST:
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
case OPUS_GET_INBAND_FEC_REQUEST:
{
OpusEncoder *enc;
@@ -604,23 +667,37 @@ OpusMSDecoder *opus_multistream_decoder_create(
}
+typedef void (*opus_copy_channel_out_func)(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+);
+
static int opus_multistream_decode_native(
OpusMSDecoder *st,
const unsigned char *data,
opus_int32 len,
- opus_val16 *pcm,
+ void *pcm,
+ opus_copy_channel_out_func copy_channel_out,
int frame_size,
int decode_fec
)
{
+ opus_int32 Fs;
int coupled_size;
int mono_size;
- int s, i, c;
+ int s, c;
char *ptr;
int do_plc=0;
VARDECL(opus_val16, buf);
ALLOC_STACK;
+ /* Limit frame_size to avoid excessive stack allocations. */
+ opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs));
+ frame_size = IMIN(frame_size, Fs/25*3);
ALLOC(buf, 2*frame_size, opus_val16);
ptr = (char*)st + align(sizeof(OpusMSDecoder));
coupled_size = opus_decoder_get_size(2);
@@ -672,16 +749,16 @@ static int opus_multistream_decode_native(
/* Copy "left" audio to the channel(s) where it belongs */
while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
{
- for (i=0;ilayout.nb_channels*i+chan] = buf[2*i];
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf, 2, frame_size);
prev = chan;
}
prev = -1;
/* Copy "right" audio to the channel(s) where it belongs */
while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
{
- for (i=0;ilayout.nb_channels*i+chan] = buf[2*i+1];
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf+1, 2, frame_size);
prev = chan;
}
} else {
@@ -690,8 +767,8 @@ static int opus_multistream_decode_native(
/* Copy audio to the channel(s) where it belongs */
while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
{
- for (i=0;ilayout.nb_channels*i+chan] = buf[i];
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf, 1, frame_size);
prev = chan;
}
}
@@ -701,14 +778,74 @@ static int opus_multistream_decode_native(
{
if (st->layout.mapping[c] == 255)
{
- for (i=0;ilayout.nb_channels*i+c] = 0;
+ (*copy_channel_out)(pcm, st->layout.nb_channels, c,
+ NULL, 0, frame_size);
}
}
RESTORE_STACK;
return frame_size;
}
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_out_float(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+)
+{
+ float *float_dst;
+ int i;
+ float_dst = (float*)dst;
+ if (src != NULL)
+ {
+ for (i=0;ilayout.nb_channels, opus_int16);
-
- ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec);
- if (ret > 0)
- {
- for (i=0;ilayout.nb_channels;i++)
- pcm[i] = (1.f/32768.f)*(out[i]);
- }
- RESTORE_STACK;
- return ret;
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_float, frame_size, decode_fec);
}
#endif
@@ -748,20 +874,8 @@ int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
{
- VARDECL(float, out);
- int ret, i;
- ALLOC_STACK;
-
- ALLOC(out, frame_size*st->layout.nb_channels, float);
-
- ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec);
- if (ret > 0)
- {
- for (i=0;ilayout.nb_channels;i++)
- pcm[i] = FLOAT2INT16(out[i]);
- }
- RESTORE_STACK;
- return ret;
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_short, frame_size, decode_fec);
}
int opus_multistream_decode_float(
@@ -773,7 +887,8 @@ int opus_multistream_decode_float(
int decode_fec
)
{
- return opus_multistream_decode_native(st, data, len, pcm, frame_size, decode_fec);
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_float, frame_size, decode_fec);
}
#endif
@@ -792,6 +907,7 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
switch (request)
{
case OPUS_GET_BANDWIDTH_REQUEST:
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
{
OpusDecoder *dec;
/* For int32* GET params, just query the first stream */