Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.xiph.org/xiph/opus.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy B. Terriberry <tterribe@xiph.org>2012-09-07 17:01:53 +0400
committerJean-Marc Valin <jmvalin@jmvalin.ca>2012-09-08 10:17:53 +0400
commita40689e6efccb13065a0e2db22c06208482dea6f (patch)
treed363df43e866bcf1059f05a6d4e05a34e12ab63a /src/opus_multistream.c
parent84dd1cf9b701d45124770b795656a98aa53222dd (diff)
Remove large multistream stack buffers.
This avoids allocating any buffers on the stack that depend on the total channel count. Such buffers could easily exceed the size of the NONTHREADSAFE_PSEUDOSTACK. It also checks the frame_size argument in both the encoder and decoder to avoid allocating large stack buffers for opus_encode() calls that would fail anyway or opus_decode() calls that would never use all that space anyway.
Diffstat (limited to 'src/opus_multistream.c')
-rw-r--r--src/opus_multistream.c274
1 files changed, 195 insertions, 79 deletions
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;i<frame_size;i++)
- {
- buf[2*i] = pcm[st->layout.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;i<frame_size;i++)
- buf[i] = pcm[st->layout.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;i<frame_size;i++)
+#if defined(FIXED_POINT)
+ dst[i*dst_stride] = FLOAT2INT16(float_src[i*src_stride+src_channel]);
+#else
+ dst[i*dst_stride] = float_src[i*src_stride+src_channel];
+#endif
+}
+#endif
+
+static void opus_copy_channel_in_short(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+)
+{
+ const opus_int16 *short_src;
+ int i;
+ short_src = (const opus_int16 *)src;
+ for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+ dst[i*dst_stride] = short_src[i*src_stride+src_channel];
+#else
+ dst[i*dst_stride] = (1/32768.f)*short_src[i*src_stride+src_channel];
+#endif
+}
+
#ifdef FIXED_POINT
+int opus_multistream_encode(
+ 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_short,
+ pcm, frame_size, data, max_data_bytes);
+}
#ifndef DISABLE_FLOAT_API
int opus_multistream_encode_float(
@@ -318,22 +386,26 @@ int opus_multistream_encode_float(
opus_int32 max_data_bytes
)
{
- int i, ret;
- VARDECL(opus_int16, in);
- ALLOC_STACK;
-
- ALLOC(in, frame_size*st->layout.nb_channels, opus_int16);
-
- for (i=0;i<frame_size*st->layout.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;i<frame_size*st->layout.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;i<frame_size;i++)
- pcm[st->layout.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;i<frame_size;i++)
- pcm[st->layout.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;i<frame_size;i++)
- pcm[st->layout.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;i<frame_size;i++)
- pcm[st->layout.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;i<frame_size;i++)
+#if defined(FIXED_POINT)
+ float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride];
+#else
+ float_dst[i*dst_stride+dst_channel] = src[i*src_stride];
+#endif
+ }
+ else
+ {
+ for (i=0;i<frame_size;i++)
+ float_dst[i*dst_stride+dst_channel] = 0;
+ }
+}
+#endif
+
+static void opus_copy_channel_out_short(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+)
+{
+ opus_int16 *short_dst;
+ int i;
+ short_dst = (opus_int16*)dst;
+ if (src != NULL)
+ {
+ for (i=0;i<frame_size;i++)
+#if defined(FIXED_POINT)
+ short_dst[i*dst_stride+dst_channel] = src[i*src_stride];
+#else
+ short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]);
+#endif
+ }
+ else
+ {
+ for (i=0;i<frame_size;i++)
+ short_dst[i*dst_stride+dst_channel] = 0;
+ }
+}
+
+
+
#ifdef FIXED_POINT
int opus_multistream_decode(
OpusMSDecoder *st,
@@ -719,27 +856,16 @@ int opus_multistream_decode(
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_short, frame_size, decode_fec);
}
#ifndef DISABLE_FLOAT_API
int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
opus_int32 len, float *pcm, int frame_size, int decode_fec)
{
- VARDECL(opus_int16, out);
- int ret, i;
- ALLOC_STACK;
-
- ALLOC(out, frame_size*st->layout.nb_channels, opus_int16);
-
- ret = opus_multistream_decode_native(st, data, len, out, frame_size, decode_fec);
- if (ret > 0)
- {
- for (i=0;i<ret*st->layout.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;i<ret*st->layout.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 */