#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
#ifdefined(__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
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 complexity; int ignore_extensions; int arch; #ifdef ENABLE_DEEP_PLC
LPCNetPLCState lpcnet; #endif
/* 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
staticint opus_decode_frame(OpusDecoder *st, constunsignedchar *data,
opus_int32 len, opus_res *pcm, int frame_size, int decode_fec ARG_QEXT(opus_extension_data *ext))
{ void *silk_dec;
CELTDecoder *celt_dec; int i, silk_ret=0, celt_ret=0;
ec_dec dec;
opus_int32 silk_frame_size; int pcm_transition_silk_size;
VARDECL(opus_res, pcm_transition_silk); int pcm_transition_celt_size;
VARDECL(opus_res, pcm_transition_celt);
opus_res *pcm_transition=NULL; int redundant_audio_size;
VARDECL(opus_res, redundant_audio);
int audiosize; int mode; int bandwidth; 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 celt_coef *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;
bandwidth = st->bandwidth;
ec_dec_init(&dec,(unsignedchar*)data,len);
} else {
audiosize = frame_size; /* Run PLC using last used mode (CELT if we ended with CELT redundancy) */
mode = st->prev_redundancy ? MODE_CELT_ONLY : st->prev_mode;
bandwidth = 0;
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 ARG_QEXT(NULL)); if (ret<0)
{
RESTORE_STACK; return ret;
}
pcm += ret*st->channels;
audiosize -= ret;
} while (audiosize > 0);
RESTORE_STACK; return frame_size;
} elseif (audiosize < F20)
{ if (audiosize > F10)
audiosize = F10; elseif (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. */
celt_accum = (mode != MODE_CELT_ONLY);
start_band = 0; if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL
&& ec_tell(&dec)+17+20*(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;
if (redundancy)
{
transition = 0;
pcm_transition_silk_size=ALLOC_NONE;
}
switch(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; default:
celt_assert(0); break;
}
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband)));
}
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels)));
/* Only allocation memory for redundancy if/when needed */
redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE;
ALLOC(redundant_audio, redundant_audio_size, opus_res);
/* 5 ms redundant frame for CELT->SILK*/ if (redundancy && celt_to_silk)
{ /* If the previous frame did not use CELT (the first redundancy frame in atransitionfromSILKmayhavebeenlost)thentheCELTdecoderis staleatthispointandtheredundancyaudioisnotuseful,however thefinalrangeisstillneeded(fortesting),sotheredundancyis
always decoded but the decoded audio may not be used */
MUST_SUCCEED(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);
MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)));
}
/* MUST be after PLC */
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band)));
#ifdef ENABLE_OSCE_BWE if (mode != MODE_SILK_ONLY && st->DecControl.osce_extended_mode != OSCE_MODE_SILK_BBWE) #else if (mode != MODE_SILK_ONLY) #endif
{ 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)
MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); /* Decode CELT */
celt_ret = celt_decode_with_ec_dred(celt_dec, decode_fec ? NULL : data,
len, pcm, celt_frame_size, &dec, celt_accum #ifdef ENABLE_DEEP_PLC
, &st->lpcnet #endif
ARG_QEXT(ext ? ext->data : NULL) ARG_QEXT(ext ? ext->len : 0));
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&st->rangeFinal));
} else { unsignedchar 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) )
{
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)));
celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum);
}
st->rangeFinal = dec.rng;
}
/* 5 ms redundant frame for SILK->CELT */ if (redundancy && !celt_to_silk)
{
MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE));
MUST_SUCCEED(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);
MUST_SUCCEED(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);
} /* 5ms redundant frame for CELT->SILK; ignore if the previous frame did not useCELT(thefirstredundancyframeinatransitionfromSILKmayhave
been lost) */ if (redundancy && celt_to_silk && (st->prev_mode != MODE_SILK_ONLY || st->prev_redundancy))
{ 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 Thiswillnotpreserveamplitudeperfectlyandmayintroduce abitoftemporalaliasing,butitshouldn'tbetoobadand that'sprettymuchthebestwecando.Inanycase,generatingthis
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; #ifdef ENABLE_RES24
x = MULT32_32_Q16(pcm[i],gain); #else
x = MULT16_32_P16(pcm[i],gain); #endif
pcm[i] = SATURATE(x, 32767);
}
}
int opus_decode_native(OpusDecoder *st, constunsignedchar *data,
opus_int32 len, opus_res *pcm, int frame_size, int decode_fec, int self_delimited, opus_int32 *packet_offset, int soft_clip, const OpusDRED *dred, opus_int32 dred_offset)
{ int i, nb_samples; int count, offset; unsignedchar toc; int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; /* 48 x 2.5 ms = 120 ms */
opus_int16 size[48]; constunsignedchar *padding;
opus_int32 padding_len;
OpusExtensionIterator iter;
VALIDATE_OPUS_DECODER(st); 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; #ifdef ENABLE_DRED if (dred != NULL && dred->process_stage == 2) { int F10; int features_per_frame; int needed_feature_frames; int init_frames;
lpcnet_plc_fec_clear(&st->lpcnet);
F10 = st->Fs/100; /* if blend==0, the last PLC call was "update" and we need to feed two extra 10-ms frames. */
init_frames = (st->lpcnet.blend == 0) ? 2 : 0;
features_per_frame = IMAX(1, frame_size/F10);
needed_feature_frames = init_frames + features_per_frame; for (i=0;i<needed_feature_frames;i++) { int feature_offset; /* We floor instead of rounding because 5-ms overlap compensates for the missing 0.5 rounding offset. */
feature_offset = init_frames - i - 2 + (int)floor(((float)dred_offset + dred->dred_offset*F10/4)/F10); if (feature_offset <= 4*dred->nb_latents-1 && feature_offset >= 0) {
lpcnet_plc_fec_add(&st->lpcnet, dred->fec_features+feature_offset*DRED_NUM_FEATURES);
} else { if (feature_offset >= 0) lpcnet_plc_fec_add(&st->lpcnet, NULL);
}
}
} #else
(void)dred;
(void)dred_offset; #endif 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, 0ARG_QEXT(NULL)); 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;
} elseif (len<0) return OPUS_BAD_ARG;
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, NULL, 0); /* 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, NULL, 0); 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 ARG_QEXT(NULL)); 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; #ifdef ENABLE_QEXT
opus_extension_data ext;
ext.frame = -1;
ext.data = NULL;
ext.len = 0;
ext.id = -1; while (ext.frame < i) {
OpusExtensionIterator iter_copy;
iter_copy = iter;
ret = opus_extension_iterator_find(&iter, &ext, QEXT_EXTENSION_ID); if (ret <= 0) break; if (ext.frame > i) iter = iter_copy;
} if (ext.frame != i) ext.data = NULL; #endif
ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0 ARG_QEXT(&ext)); 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_impl(pcm, nb_samples, st->channels, st->softclip_mem, st->arch); else
st->softclip_mem[0]=st->softclip_mem[1]=0; #endif return nb_samples;
}
int opus_packet_get_nb_frames(constunsignedchar packet[], opus_int32 len)
{ int count; if (len<1) return OPUS_BAD_ARG;
count = packet[0]&0x3; if (count==0) return1; elseif (count!=3) return2; elseif (len<2) return OPUS_INVALID_PACKET; else return packet[1]&0x3F;
}
int opus_packet_get_nb_samples(constunsignedchar 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_packet_has_lbrr(constunsignedchar packet[], opus_int32 len)
{ int ret; constunsignedchar *frames[48];
opus_int16 size[48]; int packet_mode, packet_frame_size, packet_stream_channels; int nb_frames=1; int lbrr;
#ifdef ENABLE_DRED staticint dred_find_payload(constunsignedchar *data, opus_int32 len, constunsignedchar **payload, int *dred_frame_offset)
{
OpusExtensionIterator iter;
opus_extension_data ext; constunsignedchar *padding;
opus_int32 padding_len; int nb_frames; constunsignedchar *frames[48];
opus_int16 size[48]; int frame_size; int ret;
*payload = NULL; /* Get the padding section of the packet. */
ret = opus_packet_parse_impl(data, len, 0, NULL, frames, size, NULL, NULL,
&padding, &padding_len); if (ret < 0) return ret;
nb_frames = ret;
frame_size = opus_packet_get_samples_per_frame(data, 48000);
opus_extension_iterator_init(&iter, padding, padding_len, nb_frames); for (;;) {
ret = opus_extension_iterator_find(&iter, &ext, DRED_EXTENSION_ID); if (ret <= 0) return ret; /* DRED position in the packet, in units of 2.5 ms like for the signaled DRED offset. */
*dred_frame_offset = ext.frame*frame_size/120; #ifdef DRED_EXPERIMENTAL_VERSION /* Check that temporary extension type and version match.
This check will be removed once extension is finalized. */ if (ext.len > DRED_EXPERIMENTAL_BYTES && ext.data[0] == 'D'
&& ext.data[1] == DRED_EXPERIMENTAL_VERSION) {
*payload = ext.data+2; return ext.len-2;
} #else if (ext.len > 0) {
*payload = ext.data; return ext.len;
} #endif
}
} #endif
int opus_dred_get_size(void)
{ #ifdef ENABLE_DRED returnsizeof(OpusDRED); #else return0; #endif
}
OpusDRED *opus_dred_alloc(int *error)
{ #ifdef ENABLE_DRED
OpusDRED *dec;
dec = (OpusDRED *)opus_alloc(opus_dred_get_size()); if (dec == NULL)
{ if (error)
*error = OPUS_ALLOC_FAIL; return NULL;
} return dec; #else if (error)
*error = OPUS_UNIMPLEMENTED; return NULL; #endif
}