Index: webrtc/modules/audio_coding/codecs/opus/opus/src/src/opus_decoder.c |
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus/src/src/opus_decoder.c b/webrtc/modules/audio_coding/codecs/opus/opus/src/src/opus_decoder.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..080bec5072a1d3f21ac42e9334dc5593112c115f |
--- /dev/null |
+++ b/webrtc/modules/audio_coding/codecs/opus/opus/src/src/opus_decoder.c |
@@ -0,0 +1,981 @@ |
+/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited |
+ Written by Jean-Marc Valin and Koen Vos */ |
+/* |
+ Redistribution and use in source and binary forms, with or without |
+ modification, are permitted provided that the following conditions |
+ are met: |
+ |
+ - Redistributions of source code must retain the above copyright |
+ notice, this list of conditions and the following disclaimer. |
+ |
+ - Redistributions in binary form must reproduce the above copyright |
+ notice, this list of conditions and the following disclaimer in the |
+ documentation and/or other materials provided with the distribution. |
+ |
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+*/ |
+ |
+#ifdef HAVE_CONFIG_H |
+# include "config.h" |
+#endif |
+ |
+#ifndef OPUS_BUILD |
+# 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__) && !defined(OPUS_WILL_BE_SLOW) |
+# pragma message "You appear to be compiling without optimization, if so opus will be very slow." |
+#endif |
+ |
+#include <stdarg.h> |
+#include "celt.h" |
+#include "opus.h" |
+#include "entdec.h" |
+#include "modes.h" |
+#include "API.h" |
+#include "stack_alloc.h" |
+#include "float_cast.h" |
+#include "opus_private.h" |
+#include "os_support.h" |
+#include "structs.h" |
+#include "define.h" |
+#include "mathops.h" |
+#include "cpu_support.h" |
+ |
+struct OpusDecoder { |
+ int celt_dec_offset; |
+ int silk_dec_offset; |
+ int channels; |
+ opus_int32 Fs; /** Sampling rate (at the API level) */ |
+ silk_DecControlStruct DecControl; |
+ int decode_gain; |
+ int arch; |
+ |
+ /* Everything beyond this point gets cleared on a reset */ |
+#define OPUS_DECODER_RESET_START stream_channels |
+ int stream_channels; |
+ |
+ int bandwidth; |
+ int mode; |
+ int prev_mode; |
+ int frame_size; |
+ int prev_redundancy; |
+ int last_packet_duration; |
+#ifndef FIXED_POINT |
+ opus_val16 softclip_mem[2]; |
+#endif |
+ |
+ opus_uint32 rangeFinal; |
+}; |
+ |
+ |
+int opus_decoder_get_size(int channels) |
+{ |
+ int silkDecSizeBytes, celtDecSizeBytes; |
+ int ret; |
+ if (channels<1 || channels > 2) |
+ return 0; |
+ ret = silk_Get_Decoder_Size( &silkDecSizeBytes ); |
+ if(ret) |
+ return 0; |
+ silkDecSizeBytes = align(silkDecSizeBytes); |
+ celtDecSizeBytes = celt_decoder_get_size(channels); |
+ return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes; |
+} |
+ |
+int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) |
+{ |
+ void *silk_dec; |
+ CELTDecoder *celt_dec; |
+ int ret, silkDecSizeBytes; |
+ |
+ if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) |
+ || (channels!=1&&channels!=2)) |
+ return OPUS_BAD_ARG; |
+ |
+ OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); |
+ /* Initialize SILK encoder */ |
+ ret = silk_Get_Decoder_Size(&silkDecSizeBytes); |
+ if (ret) |
+ return OPUS_INTERNAL_ERROR; |
+ |
+ silkDecSizeBytes = align(silkDecSizeBytes); |
+ st->silk_dec_offset = align(sizeof(OpusDecoder)); |
+ st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes; |
+ silk_dec = (char*)st+st->silk_dec_offset; |
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); |
+ st->stream_channels = st->channels = channels; |
+ |
+ st->Fs = Fs; |
+ st->DecControl.API_sampleRate = st->Fs; |
+ st->DecControl.nChannelsAPI = st->channels; |
+ |
+ /* Reset decoder */ |
+ ret = silk_InitDecoder( silk_dec ); |
+ if(ret)return OPUS_INTERNAL_ERROR; |
+ |
+ /* Initialize CELT decoder */ |
+ ret = celt_decoder_init(celt_dec, Fs, channels); |
+ if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR; |
+ |
+ celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0)); |
+ |
+ st->prev_mode = 0; |
+ st->frame_size = Fs/400; |
+ st->arch = opus_select_arch(); |
+ return OPUS_OK; |
+} |
+ |
+OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error) |
+{ |
+ int ret; |
+ OpusDecoder *st; |
+ if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) |
+ || (channels!=1&&channels!=2)) |
+ { |
+ if (error) |
+ *error = OPUS_BAD_ARG; |
+ return NULL; |
+ } |
+ st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels)); |
+ if (st == NULL) |
+ { |
+ if (error) |
+ *error = OPUS_ALLOC_FAIL; |
+ return NULL; |
+ } |
+ ret = opus_decoder_init(st, Fs, channels); |
+ if (error) |
+ *error = ret; |
+ if (ret != OPUS_OK) |
+ { |
+ opus_free(st); |
+ st = NULL; |
+ } |
+ return st; |
+} |
+ |
+static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, |
+ opus_val16 *out, int overlap, int channels, |
+ const opus_val16 *window, opus_int32 Fs) |
+{ |
+ int i, c; |
+ int inc = 48000/Fs; |
+ for (c=0;c<channels;c++) |
+ { |
+ for (i=0;i<overlap;i++) |
+ { |
+ opus_val16 w = MULT16_16_Q15(window[i*inc], window[i*inc]); |
+ out[i*channels+c] = SHR32(MAC16_16(MULT16_16(w,in2[i*channels+c]), |
+ Q15ONE-w, in1[i*channels+c]), 15); |
+ } |
+ } |
+} |
+ |
+static int opus_packet_get_mode(const unsigned char *data) |
+{ |
+ int mode; |
+ if (data[0]&0x80) |
+ { |
+ mode = MODE_CELT_ONLY; |
+ } else if ((data[0]&0x60) == 0x60) |
+ { |
+ mode = MODE_HYBRID; |
+ } else { |
+ mode = MODE_SILK_ONLY; |
+ } |
+ return mode; |
+} |
+ |
+static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) |
+{ |
+ void *silk_dec; |
+ CELTDecoder *celt_dec; |
+ int i, silk_ret=0, celt_ret=0; |
+ ec_dec dec; |
+ opus_int32 silk_frame_size; |
+ int pcm_silk_size; |
+ VARDECL(opus_int16, pcm_silk); |
+ int pcm_transition_silk_size; |
+ VARDECL(opus_val16, pcm_transition_silk); |
+ int pcm_transition_celt_size; |
+ VARDECL(opus_val16, pcm_transition_celt); |
+ opus_val16 *pcm_transition=NULL; |
+ int redundant_audio_size; |
+ VARDECL(opus_val16, redundant_audio); |
+ |
+ int audiosize; |
+ int mode; |
+ int transition=0; |
+ int start_band; |
+ int redundancy=0; |
+ int redundancy_bytes = 0; |
+ int celt_to_silk=0; |
+ int c; |
+ 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; |
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); |
+ F20 = st->Fs/50; |
+ F10 = F20>>1; |
+ F5 = F10>>1; |
+ F2_5 = F5>>1; |
+ if (frame_size < F2_5) |
+ { |
+ 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) |
+ { |
+ data = NULL; |
+ /* In that case, don't conceal more than what the ToC says */ |
+ frame_size = IMIN(frame_size, st->frame_size); |
+ } |
+ if (data != NULL) |
+ { |
+ audiosize = st->frame_size; |
+ mode = st->mode; |
+ ec_dec_init(&dec,(unsigned char*)data,len); |
+ } else { |
+ audiosize = frame_size; |
+ mode = st->prev_mode; |
+ |
+ if (mode == 0) |
+ { |
+ /* If we haven't got any packet yet, all we can do is return zeros */ |
+ for (i=0;i<audiosize*st->channels;i++) |
+ pcm[i] = 0; |
+ RESTORE_STACK; |
+ return audiosize; |
+ } |
+ |
+ /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT), |
+ 10, or 20 (e.g. 12.5 or 30 ms). */ |
+ if (audiosize > F20) |
+ { |
+ do { |
+ int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0); |
+ if (ret<0) |
+ { |
+ RESTORE_STACK; |
+ return ret; |
+ } |
+ pcm += ret*st->channels; |
+ audiosize -= ret; |
+ } while (audiosize > 0); |
+ RESTORE_STACK; |
+ return frame_size; |
+ } else if (audiosize < F20) |
+ { |
+ if (audiosize > F10) |
+ audiosize = F10; |
+ else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) |
+ audiosize = F5; |
+ } |
+ } |
+ |
+ /* 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 && ( |
+ (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) |
+ || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) |
+ ) |
+ { |
+ transition = 1; |
+ /* Decide where to allocate the stack memory for pcm_transition */ |
+ if (mode == MODE_CELT_ONLY) |
+ pcm_transition_celt_size = F5*st->channels; |
+ else |
+ pcm_transition_silk_size = F5*st->channels; |
+ } |
+ ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16); |
+ if (transition && mode == MODE_CELT_ONLY) |
+ { |
+ pcm_transition = pcm_transition_celt; |
+ opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); |
+ } |
+ if (audiosize > frame_size) |
+ { |
+ /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ |
+ RESTORE_STACK; |
+ return OPUS_BAD_ARG; |
+ } else { |
+ frame_size = audiosize; |
+ } |
+ |
+ /* Don't allocate any memory when in CELT-only mode */ |
+ 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; |
+#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 ); |
+ |
+ /* The SILK PLC cannot produce frames of less than 10 ms */ |
+ st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); |
+ |
+ if (data != NULL) |
+ { |
+ st->DecControl.nChannelsInternal = st->stream_channels; |
+ if( mode == MODE_SILK_ONLY ) { |
+ if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { |
+ st->DecControl.internalSampleRate = 8000; |
+ } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { |
+ st->DecControl.internalSampleRate = 12000; |
+ } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { |
+ st->DecControl.internalSampleRate = 16000; |
+ } else { |
+ st->DecControl.internalSampleRate = 16000; |
+ silk_assert( 0 ); |
+ } |
+ } else { |
+ /* Hybrid mode */ |
+ st->DecControl.internalSampleRate = 16000; |
+ } |
+ } |
+ |
+ lost_flag = data == NULL ? 1 : 2 * decode_fec; |
+ decoded_samples = 0; |
+ do { |
+ /* 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, st->arch ); |
+ if( silk_ret ) { |
+ if (lost_flag) { |
+ /* PLC failure should not be fatal */ |
+ silk_frame_size = frame_size; |
+ for (i=0;i<frame_size*st->channels;i++) |
+ pcm_ptr[i] = 0; |
+ } else { |
+ RESTORE_STACK; |
+ return OPUS_INTERNAL_ERROR; |
+ } |
+ } |
+ pcm_ptr += silk_frame_size * st->channels; |
+ decoded_samples += silk_frame_size; |
+ } while( decoded_samples < frame_size ); |
+ } |
+ |
+ start_band = 0; |
+ if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL |
+ && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) |
+ { |
+ /* Check if we have a redundant 0-8 kHz band */ |
+ if (mode == MODE_HYBRID) |
+ redundancy = ec_dec_bit_logp(&dec, 12); |
+ else |
+ redundancy = 1; |
+ if (redundancy) |
+ { |
+ celt_to_silk = ec_dec_bit_logp(&dec, 1); |
+ /* redundancy_bytes will be at least two, in the non-hybrid |
+ case due to the ec_tell() check above */ |
+ redundancy_bytes = mode==MODE_HYBRID ? |
+ (opus_int32)ec_dec_uint(&dec, 256)+2 : |
+ len-((ec_tell(&dec)+7)>>3); |
+ len -= redundancy_bytes; |
+ /* This is a sanity check. It should never happen for a valid |
+ packet, so the exact behaviour is not normative. */ |
+ if (len*8 < ec_tell(&dec)) |
+ { |
+ len = 0; |
+ redundancy_bytes = 0; |
+ redundancy = 0; |
+ } |
+ /* Shrink decoder because of raw bits */ |
+ dec.storage -= redundancy_bytes; |
+ } |
+ } |
+ if (mode != MODE_CELT_ONLY) |
+ start_band = 17; |
+ |
+ { |
+ int endband=21; |
+ |
+ switch(st->bandwidth) |
+ { |
+ case OPUS_BANDWIDTH_NARROWBAND: |
+ endband = 13; |
+ break; |
+ case OPUS_BANDWIDTH_MEDIUMBAND: |
+ case OPUS_BANDWIDTH_WIDEBAND: |
+ endband = 17; |
+ break; |
+ case OPUS_BANDWIDTH_SUPERWIDEBAND: |
+ endband = 19; |
+ break; |
+ case OPUS_BANDWIDTH_FULLBAND: |
+ endband = 21; |
+ break; |
+ } |
+ celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband)); |
+ celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels)); |
+ } |
+ |
+ if (redundancy) |
+ { |
+ transition = 0; |
+ pcm_transition_silk_size=ALLOC_NONE; |
+ } |
+ |
+ ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16); |
+ |
+ if (transition && mode != MODE_CELT_ONLY) |
+ { |
+ pcm_transition = pcm_transition_silk; |
+ opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); |
+ } |
+ |
+ /* Only allocation memory for redundancy if/when needed */ |
+ redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE; |
+ ALLOC(redundant_audio, redundant_audio_size, opus_val16); |
+ |
+ /* 5 ms redundant frame for CELT->SILK*/ |
+ if (redundancy && celt_to_silk) |
+ { |
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
+ 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)); |
+ } |
+ |
+ /* MUST be after PLC */ |
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band)); |
+ |
+ if (mode != MODE_SILK_ONLY) |
+ { |
+ int celt_frame_size = IMIN(F20, frame_size); |
+ /* Make sure to discard any previous CELT state */ |
+ if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) |
+ 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, celt_accum); |
+ } else { |
+ unsigned char silence[2] = {0xFF, 0xFF}; |
+ 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_accum); |
+ } |
+ } |
+ |
+ if (mode != MODE_CELT_ONLY && !celt_accum) |
+ { |
+#ifdef FIXED_POINT |
+ for (i=0;i<frame_size*st->channels;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]); |
+#endif |
+ } |
+ |
+ { |
+ const CELTMode *celt_mode; |
+ celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode)); |
+ window = celt_mode->window; |
+ } |
+ |
+ /* 5 ms redundant frame for SILK->CELT */ |
+ if (redundancy && !celt_to_silk) |
+ { |
+ 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, 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); |
+ } |
+ if (redundancy && celt_to_silk) |
+ { |
+ for (c=0;c<st->channels;c++) |
+ { |
+ for (i=0;i<F2_5;i++) |
+ pcm[st->channels*i+c] = redundant_audio[st->channels*i+c]; |
+ } |
+ smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, |
+ pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); |
+ } |
+ if (transition) |
+ { |
+ if (audiosize >= F5) |
+ { |
+ for (i=0;i<st->channels*F2_5;i++) |
+ pcm[i] = pcm_transition[i]; |
+ smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, |
+ pcm+st->channels*F2_5, F2_5, |
+ st->channels, window, st->Fs); |
+ } else { |
+ /* Not enough time to do a clean transition, but we do it anyway |
+ This will not preserve amplitude perfectly and may introduce |
+ a bit of temporal aliasing, but it shouldn't be too bad and |
+ that's pretty much the best we can do. In any case, generating this |
+ transition it pretty silly in the first place */ |
+ smooth_fade(pcm_transition, pcm, |
+ pcm, F2_5, |
+ st->channels, window, st->Fs); |
+ } |
+ } |
+ |
+ if(st->decode_gain) |
+ { |
+ opus_val32 gain; |
+ gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); |
+ for (i=0;i<frame_size*st->channels;i++) |
+ { |
+ opus_val32 x; |
+ x = MULT16_32_P16(pcm[i],gain); |
+ pcm[i] = SATURATE(x, 32767); |
+ } |
+ } |
+ |
+ if (len <= 1) |
+ st->rangeFinal = 0; |
+ else |
+ st->rangeFinal = dec.rng ^ redundant_rng; |
+ |
+ st->prev_mode = mode; |
+ st->prev_redundancy = redundancy && !celt_to_silk; |
+ |
+ if (celt_ret>=0) |
+ { |
+ if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels)) |
+ OPUS_PRINT_INT(audiosize); |
+ } |
+ |
+ RESTORE_STACK; |
+ return celt_ret < 0 ? celt_ret : audiosize; |
+ |
+} |
+ |
+int opus_decode_native(OpusDecoder *st, const unsigned char *data, |
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, |
+ int self_delimited, opus_int32 *packet_offset, int soft_clip) |
+{ |
+ int i, nb_samples; |
+ int count, offset; |
+ unsigned char toc; |
+ int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; |
+ /* 48 x 2.5 ms = 120 ms */ |
+ opus_int16 size[48]; |
+ if (decode_fec<0 || decode_fec>1) |
+ return OPUS_BAD_ARG; |
+ /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ |
+ if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) |
+ return OPUS_BAD_ARG; |
+ if (len==0 || data==NULL) |
+ { |
+ int pcm_count=0; |
+ do { |
+ int ret; |
+ ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0); |
+ if (ret<0) |
+ return ret; |
+ pcm_count += ret; |
+ } while (pcm_count < frame_size); |
+ celt_assert(pcm_count == frame_size); |
+ if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels)) |
+ OPUS_PRINT_INT(pcm_count); |
+ st->last_packet_duration = pcm_count; |
+ return pcm_count; |
+ } else if (len<0) |
+ return OPUS_BAD_ARG; |
+ |
+ packet_mode = opus_packet_get_mode(data); |
+ packet_bandwidth = opus_packet_get_bandwidth(data); |
+ packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); |
+ packet_stream_channels = opus_packet_get_nb_channels(data); |
+ |
+ count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, |
+ size, &offset, packet_offset); |
+ if (count<0) |
+ return count; |
+ |
+ data += offset; |
+ |
+ if (decode_fec) |
+ { |
+ int duration_copy; |
+ int ret; |
+ /* If no FEC can be present, run the PLC (recursive call) */ |
+ if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) |
+ return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip); |
+ /* Otherwise, run the PLC on everything except the size for which we might have FEC */ |
+ duration_copy = st->last_packet_duration; |
+ if (frame_size-packet_frame_size!=0) |
+ { |
+ ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip); |
+ if (ret<0) |
+ { |
+ st->last_packet_duration = duration_copy; |
+ return ret; |
+ } |
+ celt_assert(ret==frame_size-packet_frame_size); |
+ } |
+ /* Complete with FEC */ |
+ st->mode = packet_mode; |
+ st->bandwidth = packet_bandwidth; |
+ st->frame_size = packet_frame_size; |
+ st->stream_channels = packet_stream_channels; |
+ ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), |
+ packet_frame_size, 1); |
+ if (ret<0) |
+ return ret; |
+ else { |
+ if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels)) |
+ OPUS_PRINT_INT(frame_size); |
+ st->last_packet_duration = frame_size; |
+ return frame_size; |
+ } |
+ } |
+ |
+ if (count*packet_frame_size > frame_size) |
+ return OPUS_BUFFER_TOO_SMALL; |
+ |
+ /* Update the state as the last step to avoid updating it on an invalid packet */ |
+ st->mode = packet_mode; |
+ st->bandwidth = packet_bandwidth; |
+ st->frame_size = packet_frame_size; |
+ st->stream_channels = packet_stream_channels; |
+ |
+ nb_samples=0; |
+ for (i=0;i<count;i++) |
+ { |
+ int ret; |
+ ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0); |
+ if (ret<0) |
+ return ret; |
+ celt_assert(ret==packet_frame_size); |
+ data += size[i]; |
+ nb_samples += ret; |
+ } |
+ st->last_packet_duration = nb_samples; |
+ if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels)) |
+ OPUS_PRINT_INT(nb_samples); |
+#ifndef FIXED_POINT |
+ if (soft_clip) |
+ opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem); |
+ else |
+ st->softclip_mem[0]=st->softclip_mem[1]=0; |
+#endif |
+ return nb_samples; |
+} |
+ |
+#ifdef FIXED_POINT |
+ |
+int opus_decode(OpusDecoder *st, const unsigned char *data, |
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) |
+{ |
+ if(frame_size<=0) |
+ return OPUS_BAD_ARG; |
+ return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); |
+} |
+ |
+#ifndef DISABLE_FLOAT_API |
+int opus_decode_float(OpusDecoder *st, const unsigned char *data, |
+ opus_int32 len, float *pcm, int frame_size, int decode_fec) |
+{ |
+ VARDECL(opus_int16, out); |
+ int ret, i; |
+ int nb_samples; |
+ ALLOC_STACK; |
+ |
+ if(frame_size<=0) |
+ { |
+ 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); |
+ if (ret > 0) |
+ { |
+ for (i=0;i<ret*st->channels;i++) |
+ pcm[i] = (1.f/32768.f)*(out[i]); |
+ } |
+ RESTORE_STACK; |
+ return ret; |
+} |
+#endif |
+ |
+ |
+#else |
+int opus_decode(OpusDecoder *st, const unsigned char *data, |
+ opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) |
+{ |
+ VARDECL(float, out); |
+ int ret, i; |
+ int nb_samples; |
+ ALLOC_STACK; |
+ |
+ if(frame_size<=0) |
+ { |
+ 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, float); |
+ |
+ ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); |
+ if (ret > 0) |
+ { |
+ for (i=0;i<ret*st->channels;i++) |
+ pcm[i] = FLOAT2INT16(out[i]); |
+ } |
+ RESTORE_STACK; |
+ return ret; |
+} |
+ |
+int opus_decode_float(OpusDecoder *st, const unsigned char *data, |
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) |
+{ |
+ if(frame_size<=0) |
+ return OPUS_BAD_ARG; |
+ return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); |
+} |
+ |
+#endif |
+ |
+int opus_decoder_ctl(OpusDecoder *st, int request, ...) |
+{ |
+ int ret = OPUS_OK; |
+ va_list ap; |
+ void *silk_dec; |
+ CELTDecoder *celt_dec; |
+ |
+ silk_dec = (char*)st+st->silk_dec_offset; |
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); |
+ |
+ |
+ va_start(ap, request); |
+ |
+ switch (request) |
+ { |
+ case OPUS_GET_BANDWIDTH_REQUEST: |
+ { |
+ opus_int32 *value = va_arg(ap, opus_int32*); |
+ if (!value) |
+ { |
+ goto bad_arg; |
+ } |
+ *value = st->bandwidth; |
+ } |
+ break; |
+ case OPUS_GET_FINAL_RANGE_REQUEST: |
+ { |
+ opus_uint32 *value = va_arg(ap, opus_uint32*); |
+ if (!value) |
+ { |
+ goto bad_arg; |
+ } |
+ *value = st->rangeFinal; |
+ } |
+ break; |
+ case OPUS_RESET_STATE: |
+ { |
+ OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START, |
+ sizeof(OpusDecoder)- |
+ ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); |
+ |
+ celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); |
+ silk_InitDecoder( silk_dec ); |
+ st->stream_channels = st->channels; |
+ st->frame_size = st->Fs/400; |
+ } |
+ break; |
+ case OPUS_GET_SAMPLE_RATE_REQUEST: |
+ { |
+ opus_int32 *value = va_arg(ap, opus_int32*); |
+ if (!value) |
+ { |
+ goto bad_arg; |
+ } |
+ *value = st->Fs; |
+ } |
+ break; |
+ case OPUS_GET_PITCH_REQUEST: |
+ { |
+ opus_int32 *value = va_arg(ap, opus_int32*); |
+ if (!value) |
+ { |
+ goto bad_arg; |
+ } |
+ if (st->prev_mode == MODE_CELT_ONLY) |
+ celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); |
+ else |
+ *value = st->DecControl.prevPitchLag; |
+ } |
+ break; |
+ case OPUS_GET_GAIN_REQUEST: |
+ { |
+ opus_int32 *value = va_arg(ap, opus_int32*); |
+ if (!value) |
+ { |
+ goto bad_arg; |
+ } |
+ *value = st->decode_gain; |
+ } |
+ break; |
+ case OPUS_SET_GAIN_REQUEST: |
+ { |
+ opus_int32 value = va_arg(ap, opus_int32); |
+ if (value<-32768 || value>32767) |
+ { |
+ goto bad_arg; |
+ } |
+ st->decode_gain = value; |
+ } |
+ break; |
+ case OPUS_GET_LAST_PACKET_DURATION_REQUEST: |
+ { |
+ opus_uint32 *value = va_arg(ap, opus_uint32*); |
+ if (!value) |
+ { |
+ goto bad_arg; |
+ } |
+ *value = st->last_packet_duration; |
+ } |
+ break; |
+ default: |
+ /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ |
+ ret = OPUS_UNIMPLEMENTED; |
+ break; |
+ } |
+ |
+ va_end(ap); |
+ return ret; |
+bad_arg: |
+ va_end(ap); |
+ return OPUS_BAD_ARG; |
+} |
+ |
+void opus_decoder_destroy(OpusDecoder *st) |
+{ |
+ opus_free(st); |
+} |
+ |
+ |
+int opus_packet_get_bandwidth(const unsigned char *data) |
+{ |
+ int bandwidth; |
+ if (data[0]&0x80) |
+ { |
+ bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3); |
+ if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) |
+ bandwidth = OPUS_BANDWIDTH_NARROWBAND; |
+ } else if ((data[0]&0x60) == 0x60) |
+ { |
+ bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND : |
+ OPUS_BANDWIDTH_SUPERWIDEBAND; |
+ } else { |
+ bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3); |
+ } |
+ return bandwidth; |
+} |
+ |
+int opus_packet_get_nb_channels(const unsigned char *data) |
+{ |
+ return (data[0]&0x4) ? 2 : 1; |
+} |
+ |
+int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) |
+{ |
+ int count; |
+ if (len<1) |
+ return OPUS_BAD_ARG; |
+ count = packet[0]&0x3; |
+ if (count==0) |
+ return 1; |
+ else if (count!=3) |
+ return 2; |
+ else if (len<2) |
+ return OPUS_INVALID_PACKET; |
+ else |
+ return packet[1]&0x3F; |
+} |
+ |
+int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, |
+ opus_int32 Fs) |
+{ |
+ int samples; |
+ int count = opus_packet_get_nb_frames(packet, len); |
+ |
+ if (count<0) |
+ return count; |
+ |
+ samples = count*opus_packet_get_samples_per_frame(packet, Fs); |
+ /* Can't have more than 120 ms */ |
+ if (samples*25 > Fs*3) |
+ return OPUS_INVALID_PACKET; |
+ else |
+ return samples; |
+} |
+ |
+int opus_decoder_get_nb_samples(const OpusDecoder *dec, |
+ const unsigned char packet[], opus_int32 len) |
+{ |
+ return opus_packet_get_nb_samples(packet, len, dec->Fs); |
+} |