Index: src/opus_decoder.c |
diff --git a/src/opus_decoder.c b/src/opus_decoder.c |
index 919ba521b56046d2ba081f387ded1a46f942120c..c41985e91c365946153e3af9c4b3b9472cec6017 100644 |
--- a/src/opus_decoder.c |
+++ b/src/opus_decoder.c |
@@ -33,7 +33,7 @@ |
# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details." |
#endif |
-#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) |
+#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(OPUS_WILL_BE_SLOW) |
# pragma message "You appear to be compiling without optimization, if so opus will be very slow." |
#endif |
@@ -75,14 +75,9 @@ struct OpusDecoder { |
#endif |
opus_uint32 rangeFinal; |
+ int arch; |
}; |
-#ifdef FIXED_POINT |
-static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { |
- return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; |
-} |
-#endif |
- |
int opus_decoder_get_size(int channels) |
{ |
@@ -137,6 +132,7 @@ int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) |
st->prev_mode = 0; |
st->frame_size = Fs/400; |
+ st->arch = opus_select_arch(); |
return OPUS_OK; |
} |
@@ -215,7 +211,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
VARDECL(opus_val16, pcm_transition_silk); |
int pcm_transition_celt_size; |
VARDECL(opus_val16, pcm_transition_celt); |
- opus_val16 *pcm_transition; |
+ opus_val16 *pcm_transition=NULL; |
int redundant_audio_size; |
VARDECL(opus_val16, redundant_audio); |
@@ -230,6 +226,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
int F2_5, F5, F10, F20; |
const opus_val16 *window; |
opus_uint32 redundant_rng = 0; |
+ int celt_accum; |
ALLOC_STACK; |
silk_dec = (char*)st+st->silk_dec_offset; |
@@ -295,6 +292,14 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
} |
} |
+ /* In fixed-point, we can tell CELT to do the accumulation on top of the |
+ SILK PCM buffer. This saves some stack space. */ |
+#ifdef FIXED_POINT |
+ celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10); |
+#else |
+ celt_accum = 0; |
+#endif |
+ |
pcm_transition_silk_size = ALLOC_NONE; |
pcm_transition_celt_size = ALLOC_NONE; |
if (data!=NULL && st->prev_mode > 0 && ( |
@@ -325,14 +330,20 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
} |
/* Don't allocate any memory when in CELT-only mode */ |
- pcm_silk_size = (mode != MODE_CELT_ONLY) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; |
+ pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; |
ALLOC(pcm_silk, pcm_silk_size, opus_int16); |
/* SILK processing */ |
if (mode != MODE_CELT_ONLY) |
{ |
int lost_flag, decoded_samples; |
- opus_int16 *pcm_ptr = pcm_silk; |
+ opus_int16 *pcm_ptr; |
+#ifdef FIXED_POINT |
+ if (celt_accum) |
+ pcm_ptr = pcm; |
+ else |
+#endif |
+ pcm_ptr = pcm_silk; |
if (st->prev_mode==MODE_CELT_ONLY) |
silk_InitDecoder( silk_dec ); |
@@ -366,7 +377,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
/* Call SILK decoder */ |
int first_frame = decoded_samples == 0; |
silk_ret = silk_Decode( silk_dec, &st->DecControl, |
- lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size ); |
+ lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch ); |
if( silk_ret ) { |
if (lost_flag) { |
/* PLC failure should not be fatal */ |
@@ -462,7 +473,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
{ |
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, |
- redundant_audio, F5, NULL); |
+ redundant_audio, F5, NULL, 0); |
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); |
} |
@@ -477,25 +488,28 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); |
/* Decode CELT */ |
celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, |
- len, pcm, celt_frame_size, &dec); |
+ len, pcm, celt_frame_size, &dec, celt_accum); |
} else { |
unsigned char silence[2] = {0xFF, 0xFF}; |
- for (i=0;i<frame_size*st->channels;i++) |
- pcm[i] = 0; |
+ if (!celt_accum) |
+ { |
+ for (i=0;i<frame_size*st->channels;i++) |
+ pcm[i] = 0; |
+ } |
/* For hybrid -> SILK transitions, we let the CELT MDCT |
do a fade-out by decoding a silence frame */ |
if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) |
{ |
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
- celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL); |
+ celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum); |
} |
} |
- if (mode != MODE_CELT_ONLY) |
+ if (mode != MODE_CELT_ONLY && !celt_accum) |
{ |
#ifdef FIXED_POINT |
for (i=0;i<frame_size*st->channels;i++) |
- pcm[i] = SAT16(pcm[i] + pcm_silk[i]); |
+ pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i])); |
#else |
for (i=0;i<frame_size*st->channels;i++) |
pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); |
@@ -514,7 +528,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); |
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
- celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL); |
+ celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0); |
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); |
smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, |
pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); |
@@ -710,6 +724,7 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data, |
{ |
VARDECL(opus_int16, out); |
int ret, i; |
+ int nb_samples; |
ALLOC_STACK; |
if(frame_size<=0) |
@@ -717,6 +732,14 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data, |
RESTORE_STACK; |
return OPUS_BAD_ARG; |
} |
+ if (data != NULL && len > 0 && !decode_fec) |
+ { |
+ nb_samples = opus_decoder_get_nb_samples(st, data, len); |
+ if (nb_samples>0) |
+ frame_size = IMIN(frame_size, nb_samples); |
+ else |
+ return OPUS_INVALID_PACKET; |
+ } |
ALLOC(out, frame_size*st->channels, opus_int16); |
ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); |
@@ -737,6 +760,7 @@ int opus_decode(OpusDecoder *st, const unsigned char *data, |
{ |
VARDECL(float, out); |
int ret, i; |
+ int nb_samples; |
ALLOC_STACK; |
if(frame_size<=0) |
@@ -745,6 +769,14 @@ int opus_decode(OpusDecoder *st, const unsigned char *data, |
return OPUS_BAD_ARG; |
} |
+ if (data != NULL && len > 0 && !decode_fec) |
+ { |
+ nb_samples = opus_decoder_get_nb_samples(st, data, len); |
+ if (nb_samples>0) |
+ frame_size = IMIN(frame_size, nb_samples); |
+ else |
+ return OPUS_INVALID_PACKET; |
+ } |
ALLOC(out, frame_size*st->channels, float); |
ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); |
@@ -904,27 +936,6 @@ int opus_packet_get_bandwidth(const unsigned char *data) |
return bandwidth; |
} |
-int opus_packet_get_samples_per_frame(const unsigned char *data, |
- opus_int32 Fs) |
-{ |
- int audiosize; |
- if (data[0]&0x80) |
- { |
- audiosize = ((data[0]>>3)&0x3); |
- audiosize = (Fs<<audiosize)/400; |
- } else if ((data[0]&0x60) == 0x60) |
- { |
- audiosize = (data[0]&0x08) ? Fs/50 : Fs/100; |
- } else { |
- audiosize = ((data[0]>>3)&0x3); |
- if (audiosize == 3) |
- audiosize = Fs*60/1000; |
- else |
- audiosize = (Fs<<audiosize)/100; |
- } |
- return audiosize; |
-} |
- |
int opus_packet_get_nb_channels(const unsigned char *data) |
{ |
return (data[0]&0x4) ? 2 : 1; |