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