2013-02-18 00:33:39 +00:00
/* 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
2014-02-08 03:21:02 +00:00
# include "config.h"
2013-02-18 00:33:39 +00:00
# endif
# ifndef OPUS_BUILD
2014-02-08 03:21:02 +00:00
# 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
2014-08-25 16:03:10 +00:00
# if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(__APPLE__)
2014-02-08 03:21:02 +00:00
# pragma message "You appear to be compiling without optimization, if so opus will be very slow."
2013-02-18 00:33:39 +00:00
# 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"
2014-02-08 03:21:02 +00:00
# include "cpu_support.h"
2013-02-18 00:33:39 +00:00
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 ;
/* 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 ;
2014-02-08 03:21:02 +00:00
# ifndef FIXED_POINT
opus_val16 softclip_mem [ 2 ] ;
# endif
2013-02-18 00:33:39 +00:00
opus_uint32 rangeFinal ;
} ;
# ifdef FIXED_POINT
2014-02-08 03:21:02 +00:00
static OPUS_INLINE opus_int16 SAT16 ( opus_int32 x ) {
2013-02-18 00:33:39 +00:00
return x > 32767 ? 32767 : x < - 32768 ? - 32768 : ( opus_int16 ) x ;
}
# endif
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 ;
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 ;
2014-02-08 03:21:02 +00:00
int pcm_silk_size ;
2013-02-18 00:33:39 +00:00
VARDECL ( opus_int16 , pcm_silk ) ;
2014-02-08 03:21:02 +00:00
int pcm_transition_silk_size ;
VARDECL ( opus_val16 , pcm_transition_silk ) ;
int pcm_transition_celt_size ;
VARDECL ( opus_val16 , pcm_transition_celt ) ;
2014-08-30 16:29:09 +00:00
opus_val16 * pcm_transition = NULL ;
2014-02-08 03:21:02 +00:00
int redundant_audio_size ;
2013-02-18 00:33:39 +00:00
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 ;
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 ;
2014-02-08 03:21:02 +00:00
mode = st - > prev_mode ;
2013-02-18 00:33:39 +00:00
2014-02-08 03:21:02 +00:00
if ( mode = = 0 )
2013-02-18 00:33:39 +00:00
{
/* 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 ;
}
2014-02-08 03:21:02 +00:00
/* 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 ;
}
}
2013-02-18 00:33:39 +00:00
2014-02-08 03:21:02 +00:00
pcm_transition_silk_size = ALLOC_NONE ;
pcm_transition_celt_size = ALLOC_NONE ;
2013-02-18 00:33:39 +00:00
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 ;
2014-02-08 03:21:02 +00:00
/* Decide where to allocate the stack memory for pcm_transition */
2013-02-18 00:33:39 +00:00
if ( mode = = MODE_CELT_ONLY )
2014-02-08 03:21:02 +00:00
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 ) ;
2013-02-18 00:33:39 +00:00
}
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 ;
}
2014-02-08 03:21:02 +00:00
/* 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 ;
ALLOC ( pcm_silk , pcm_silk_size , opus_int16 ) ;
2013-02-18 00:33:39 +00:00
/* SILK processing */
if ( mode ! = MODE_CELT_ONLY )
{
int lost_flag , decoded_samples ;
opus_int16 * 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 ) ;
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 ;
2014-02-08 03:21:02 +00:00
return OPUS_INTERNAL_ERROR ;
2013-02-18 00:33:39 +00:00
}
}
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 )
2014-02-08 03:21:02 +00:00
{
2013-02-18 00:33:39 +00:00
transition = 0 ;
2014-02-08 03:21:02 +00:00
pcm_transition_silk_size = ALLOC_NONE ;
}
ALLOC ( pcm_transition_silk , pcm_transition_silk_size , opus_val16 ) ;
2013-02-18 00:33:39 +00:00
if ( transition & & mode ! = MODE_CELT_ONLY )
2014-02-08 03:21:02 +00:00
{
pcm_transition = pcm_transition_silk ;
2013-02-18 00:33:39 +00:00
opus_decode_frame ( st , NULL , 0 , pcm_transition , IMIN ( F5 , audiosize ) , 0 ) ;
2014-02-08 03:21:02 +00:00
}
/* 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 ) ;
2013-02-18 00:33:39 +00:00
/* 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 ) ;
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 ) ;
} else {
unsigned char silence [ 2 ] = { 0xFF , 0xFF } ;
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 ) ;
}
}
if ( mode ! = MODE_CELT_ONLY )
{
# ifdef FIXED_POINT
for ( i = 0 ; i < frame_size * st - > channels ; i + + )
pcm [ i ] = SAT16 ( 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 ) ;
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-4 f , 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 ;
2014-02-08 03:21:02 +00:00
if ( celt_ret > = 0 )
2013-02-18 00:33:39 +00:00
{
2014-02-08 03:21:02 +00:00
if ( OPUS_CHECK_ARRAY ( pcm , audiosize * st - > channels ) )
OPUS_PRINT_INT ( audiosize ) ;
2013-02-18 00:33:39 +00:00
}
2014-02-08 03:21:02 +00:00
RESTORE_STACK ;
return celt_ret < 0 ? celt_ret : audiosize ;
2013-02-18 00:33:39 +00:00
}
int opus_decode_native ( OpusDecoder * st , const unsigned char * data ,
opus_int32 len , opus_val16 * pcm , int frame_size , int decode_fec ,
2014-02-08 03:21:02 +00:00
int self_delimited , opus_int32 * packet_offset , int soft_clip )
2013-02-18 00:33:39 +00:00
{
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 */
2014-02-08 03:21:02 +00:00
opus_int16 size [ 48 ] ;
2013-02-18 00:33:39 +00:00
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 ;
2014-02-08 03:21:02 +00:00
ret = opus_decode_frame ( st , NULL , 0 , pcm + pcm_count * st - > channels , frame_size - pcm_count , 0 ) ;
2013-02-18 00:33:39 +00:00
if ( ret < 0 )
return ret ;
pcm_count + = ret ;
} while ( pcm_count < frame_size ) ;
2014-02-08 03:21:02 +00:00
celt_assert ( pcm_count = = frame_size ) ;
if ( OPUS_CHECK_ARRAY ( pcm , pcm_count * st - > channels ) )
OPUS_PRINT_INT ( pcm_count ) ;
2013-02-18 00:33:39 +00:00
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 ) ;
2014-02-08 03:21:02 +00:00
count = opus_packet_parse_impl ( data , len , self_delimited , & toc , NULL ,
size , & offset , packet_offset ) ;
if ( count < 0 )
return count ;
2013-02-18 00:33:39 +00:00
data + = offset ;
if ( decode_fec )
{
int duration_copy ;
int ret ;
/* If no FEC can be present, run the PLC (recursive call) */
2014-02-08 03:21:02 +00:00
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 ) ;
2013-02-18 00:33:39 +00:00
/* Otherwise, run the PLC on everything except the size for which we might have FEC */
duration_copy = st - > last_packet_duration ;
2014-02-08 03:21:02 +00:00
if ( frame_size - packet_frame_size ! = 0 )
2013-02-18 00:33:39 +00:00
{
2014-02-08 03:21:02 +00:00
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 ) ;
2013-02-18 00:33:39 +00:00
}
/* 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 ;
2014-02-08 03:21:02 +00:00
else {
if ( OPUS_CHECK_ARRAY ( pcm , frame_size * st - > channels ) )
OPUS_PRINT_INT ( frame_size ) ;
st - > last_packet_duration = frame_size ;
return frame_size ;
}
2013-02-18 00:33:39 +00:00
}
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 ;
2014-02-08 03:21:02 +00:00
ret = opus_decode_frame ( st , data , size [ i ] , pcm + nb_samples * st - > channels , frame_size - nb_samples , 0 ) ;
2013-02-18 00:33:39 +00:00
if ( ret < 0 )
return ret ;
2014-02-08 03:21:02 +00:00
celt_assert ( ret = = packet_frame_size ) ;
2013-02-18 00:33:39 +00:00
data + = size [ i ] ;
nb_samples + = ret ;
}
st - > last_packet_duration = nb_samples ;
2014-02-08 03:21:02 +00:00
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
2013-02-18 00:33:39 +00:00
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 )
{
2014-02-08 03:21:02 +00:00
if ( frame_size < = 0 )
return OPUS_BAD_ARG ;
return opus_decode_native ( st , data , len , pcm , frame_size , decode_fec , 0 , NULL , 0 ) ;
2013-02-18 00:33:39 +00:00
}
# 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 ;
ALLOC_STACK ;
2014-02-08 03:21:02 +00:00
if ( frame_size < = 0 )
{
RESTORE_STACK ;
return OPUS_BAD_ARG ;
}
2013-02-18 00:33:39 +00:00
ALLOC ( out , frame_size * st - > channels , opus_int16 ) ;
2014-02-08 03:21:02 +00:00
ret = opus_decode_native ( st , data , len , out , frame_size , decode_fec , 0 , NULL , 0 ) ;
2013-02-18 00:33:39 +00:00
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 ;
ALLOC_STACK ;
2014-02-08 03:21:02 +00:00
if ( frame_size < = 0 )
2013-02-18 00:33:39 +00:00
{
RESTORE_STACK ;
return OPUS_BAD_ARG ;
}
ALLOC ( out , frame_size * st - > channels , float ) ;
2014-02-08 03:21:02 +00:00
ret = opus_decode_native ( st , data , len , out , frame_size , decode_fec , 0 , NULL , 1 ) ;
2013-02-18 00:33:39 +00:00
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 )
{
2014-02-08 03:21:02 +00:00
if ( frame_size < = 0 )
return OPUS_BAD_ARG ;
return opus_decode_native ( st , data , len , pcm , frame_size , decode_fec , 0 , NULL , 0 ) ;
2013-02-18 00:33:39 +00:00
}
# 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 * ) ;
2014-02-08 03:21:02 +00:00
if ( ! value )
{
goto bad_arg ;
}
2013-02-18 00:33:39 +00:00
* value = st - > bandwidth ;
}
break ;
case OPUS_GET_FINAL_RANGE_REQUEST :
{
opus_uint32 * value = va_arg ( ap , opus_uint32 * ) ;
2014-02-08 03:21:02 +00:00
if ( ! value )
{
goto bad_arg ;
}
2013-02-18 00:33:39 +00:00
* 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 * ) ;
2014-02-08 03:21:02 +00:00
if ( ! value )
2013-02-18 00:33:39 +00:00
{
2014-02-08 03:21:02 +00:00
goto bad_arg ;
2013-02-18 00:33:39 +00:00
}
* value = st - > Fs ;
}
break ;
case OPUS_GET_PITCH_REQUEST :
{
opus_int32 * value = va_arg ( ap , opus_int32 * ) ;
2014-02-08 03:21:02 +00:00
if ( ! value )
2013-02-18 00:33:39 +00:00
{
2014-02-08 03:21:02 +00:00
goto bad_arg ;
2013-02-18 00:33:39 +00:00
}
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 * ) ;
2014-02-08 03:21:02 +00:00
if ( ! value )
2013-02-18 00:33:39 +00:00
{
2014-02-08 03:21:02 +00:00
goto bad_arg ;
2013-02-18 00:33:39 +00:00
}
* value = st - > decode_gain ;
}
break ;
case OPUS_SET_GAIN_REQUEST :
{
opus_int32 value = va_arg ( ap , opus_int32 ) ;
if ( value < - 32768 | | value > 32767 )
{
2014-02-08 03:21:02 +00:00
goto bad_arg ;
2013-02-18 00:33:39 +00:00
}
st - > decode_gain = value ;
}
break ;
case OPUS_GET_LAST_PACKET_DURATION_REQUEST :
{
opus_uint32 * value = va_arg ( ap , opus_uint32 * ) ;
2014-02-08 03:21:02 +00:00
if ( ! value )
{
goto bad_arg ;
}
2013-02-18 00:33:39 +00:00
* 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 ;
2014-02-08 03:21:02 +00:00
bad_arg :
va_end ( ap ) ;
return OPUS_BAD_ARG ;
2013-02-18 00:33:39 +00:00
}
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_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 ;
}
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 ) ;
}