mirror of
https://github.com/xiph/opus.git
synced 2025-06-02 08:37:43 +00:00
Reduces the decoder stack use by removing the pcm_silk buffer in fixed-point
We only keep when concealing less than 10ms with SILK.
This commit is contained in:
parent
14ca4ed682
commit
4d07b1357e
4 changed files with 79 additions and 36 deletions
|
@ -108,6 +108,10 @@ typedef opus_val32 celt_ener;
|
||||||
#define ABS16(x) ((x) < 0 ? (-(x)) : (x))
|
#define ABS16(x) ((x) < 0 ? (-(x)) : (x))
|
||||||
#define ABS32(x) ((x) < 0 ? (-(x)) : (x))
|
#define ABS32(x) ((x) < 0 ? (-(x)) : (x))
|
||||||
|
|
||||||
|
static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
|
||||||
|
return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef FIXED_DEBUG
|
#ifdef FIXED_DEBUG
|
||||||
#include "fixed_debug.h"
|
#include "fixed_debug.h"
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -134,7 +134,8 @@ int celt_decoder_get_size(int channels);
|
||||||
|
|
||||||
int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels);
|
int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels);
|
||||||
|
|
||||||
int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec);
|
int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data,
|
||||||
|
int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum);
|
||||||
|
|
||||||
#define celt_encoder_ctl opus_custom_encoder_ctl
|
#define celt_encoder_ctl opus_custom_encoder_ctl
|
||||||
#define celt_decoder_ctl opus_custom_decoder_ctl
|
#define celt_decoder_ctl opus_custom_decoder_ctl
|
||||||
|
|
|
@ -191,7 +191,7 @@ static OPUS_INLINE opus_val16 SIG2WORD16(celt_sig x)
|
||||||
static
|
static
|
||||||
#endif
|
#endif
|
||||||
void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef,
|
void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef,
|
||||||
celt_sig *mem)
|
celt_sig *mem, int accum)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
int Nd;
|
int Nd;
|
||||||
|
@ -199,7 +199,10 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c
|
||||||
opus_val16 coef0;
|
opus_val16 coef0;
|
||||||
VARDECL(celt_sig, scratch);
|
VARDECL(celt_sig, scratch);
|
||||||
SAVE_STACK;
|
SAVE_STACK;
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
(void)accum;
|
||||||
|
celt_assert(accum==0);
|
||||||
|
#endif
|
||||||
ALLOC(scratch, N, celt_sig);
|
ALLOC(scratch, N, celt_sig);
|
||||||
coef0 = coef[0];
|
coef0 = coef[0];
|
||||||
Nd = N/downsample;
|
Nd = N/downsample;
|
||||||
|
@ -238,11 +241,24 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c
|
||||||
apply_downsampling=1;
|
apply_downsampling=1;
|
||||||
} else {
|
} else {
|
||||||
/* Shortcut for the standard (non-custom modes) case */
|
/* Shortcut for the standard (non-custom modes) case */
|
||||||
for (j=0;j<N;j++)
|
#ifdef FIXED_POINT
|
||||||
|
if (accum)
|
||||||
{
|
{
|
||||||
celt_sig tmp = x[j] + m + VERY_SMALL;
|
for (j=0;j<N;j++)
|
||||||
m = MULT16_32_Q15(coef0, tmp);
|
{
|
||||||
y[j*C] = SCALEOUT(SIG2WORD16(tmp));
|
celt_sig tmp = x[j] + m + VERY_SMALL;
|
||||||
|
m = MULT16_32_Q15(coef0, tmp);
|
||||||
|
y[j*C] = SAT16(ADD32(y[j*C], SCALEOUT(SIG2WORD16(tmp))));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
for (j=0;j<N;j++)
|
||||||
|
{
|
||||||
|
celt_sig tmp = x[j] + m + VERY_SMALL;
|
||||||
|
m = MULT16_32_Q15(coef0, tmp);
|
||||||
|
y[j*C] = SCALEOUT(SIG2WORD16(tmp));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mem[c] = m;
|
mem[c] = m;
|
||||||
|
@ -250,8 +266,17 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c
|
||||||
if (apply_downsampling)
|
if (apply_downsampling)
|
||||||
{
|
{
|
||||||
/* Perform down-sampling */
|
/* Perform down-sampling */
|
||||||
for (j=0;j<Nd;j++)
|
#ifdef FIXED_POINT
|
||||||
y[j*C] = SCALEOUT(SIG2WORD16(scratch[j*downsample]));
|
if (accum)
|
||||||
|
{
|
||||||
|
for (j=0;j<Nd;j++)
|
||||||
|
y[j*C] = SAT16(ADD32(y[j*C], SCALEOUT(SIG2WORD16(scratch[j*downsample]))));
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
for (j=0;j<Nd;j++)
|
||||||
|
y[j*C] = SCALEOUT(SIG2WORD16(scratch[j*downsample]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (++c<C);
|
} while (++c<C);
|
||||||
RESTORE_STACK;
|
RESTORE_STACK;
|
||||||
|
@ -378,7 +403,8 @@ static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM,
|
||||||
pitch of 480 Hz. */
|
pitch of 480 Hz. */
|
||||||
#define PLC_PITCH_LAG_MIN (100)
|
#define PLC_PITCH_LAG_MIN (100)
|
||||||
|
|
||||||
static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, opus_val16 * OPUS_RESTRICT pcm, int N, int LM)
|
static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, opus_val16 * OPUS_RESTRICT pcm,
|
||||||
|
int N, int LM, int accum)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
int i;
|
int i;
|
||||||
|
@ -680,15 +706,15 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, opus_val16 * OPUS_R
|
||||||
} while (++c<C);
|
} while (++c<C);
|
||||||
}
|
}
|
||||||
|
|
||||||
deemphasis(out_syn, pcm, N, C, downsample,
|
deemphasis(out_syn, pcm, N, C, downsample, mode->preemph, st->preemph_memD, accum);
|
||||||
mode->preemph, st->preemph_memD);
|
|
||||||
|
|
||||||
st->loss_count = loss_count+1;
|
st->loss_count = loss_count+1;
|
||||||
|
|
||||||
RESTORE_STACK;
|
RESTORE_STACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec)
|
int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data,
|
||||||
|
int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum)
|
||||||
{
|
{
|
||||||
int c, i, N;
|
int c, i, N;
|
||||||
int spread_decision;
|
int spread_decision;
|
||||||
|
@ -803,7 +829,7 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat
|
||||||
|
|
||||||
if (data == NULL || len<=1)
|
if (data == NULL || len<=1)
|
||||||
{
|
{
|
||||||
celt_decode_lost(st, pcm, N, LM);
|
celt_decode_lost(st, pcm, N, LM, accum);
|
||||||
RESTORE_STACK;
|
RESTORE_STACK;
|
||||||
return frame_size/st->downsample;
|
return frame_size/st->downsample;
|
||||||
}
|
}
|
||||||
|
@ -1030,7 +1056,7 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat
|
||||||
st->rng = dec->rng;
|
st->rng = dec->rng;
|
||||||
|
|
||||||
/* We reuse freq[] as scratch space for the de-emphasis */
|
/* We reuse freq[] as scratch space for the de-emphasis */
|
||||||
deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD);
|
deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum);
|
||||||
st->loss_count = 0;
|
st->loss_count = 0;
|
||||||
RESTORE_STACK;
|
RESTORE_STACK;
|
||||||
if (ec_tell(dec) > 8*len)
|
if (ec_tell(dec) > 8*len)
|
||||||
|
@ -1046,7 +1072,7 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
|
int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
|
||||||
{
|
{
|
||||||
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
|
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_FLOAT_API
|
#ifndef DISABLE_FLOAT_API
|
||||||
|
@ -1063,7 +1089,7 @@ int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char
|
||||||
N = frame_size;
|
N = frame_size;
|
||||||
|
|
||||||
ALLOC(out, C*N, opus_int16);
|
ALLOC(out, C*N, opus_int16);
|
||||||
ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL);
|
ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0);
|
||||||
if (ret>0)
|
if (ret>0)
|
||||||
for (j=0;j<C*ret;j++)
|
for (j=0;j<C*ret;j++)
|
||||||
pcm[j]=out[j]*(1.f/32768.f);
|
pcm[j]=out[j]*(1.f/32768.f);
|
||||||
|
@ -1077,7 +1103,7 @@ int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char
|
||||||
|
|
||||||
int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size)
|
int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size)
|
||||||
{
|
{
|
||||||
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
|
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
|
int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
|
||||||
|
@ -1093,7 +1119,7 @@ int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data
|
||||||
N = frame_size;
|
N = frame_size;
|
||||||
ALLOC(out, C*N, celt_sig);
|
ALLOC(out, C*N, celt_sig);
|
||||||
|
|
||||||
ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL);
|
ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0);
|
||||||
|
|
||||||
if (ret>0)
|
if (ret>0)
|
||||||
for (j=0;j<C*ret;j++)
|
for (j=0;j<C*ret;j++)
|
||||||
|
|
|
@ -77,12 +77,6 @@ struct OpusDecoder {
|
||||||
opus_uint32 rangeFinal;
|
opus_uint32 rangeFinal;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
|
||||||
static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
|
|
||||||
return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int opus_decoder_get_size(int channels)
|
int opus_decoder_get_size(int channels)
|
||||||
{
|
{
|
||||||
|
@ -215,7 +209,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||||
VARDECL(opus_val16, pcm_transition_silk);
|
VARDECL(opus_val16, pcm_transition_silk);
|
||||||
int pcm_transition_celt_size;
|
int pcm_transition_celt_size;
|
||||||
VARDECL(opus_val16, pcm_transition_celt);
|
VARDECL(opus_val16, pcm_transition_celt);
|
||||||
opus_val16 *pcm_transition;
|
opus_val16 *pcm_transition=NULL;
|
||||||
int redundant_audio_size;
|
int redundant_audio_size;
|
||||||
VARDECL(opus_val16, redundant_audio);
|
VARDECL(opus_val16, redundant_audio);
|
||||||
|
|
||||||
|
@ -230,6 +224,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||||
int F2_5, F5, F10, F20;
|
int F2_5, F5, F10, F20;
|
||||||
const opus_val16 *window;
|
const opus_val16 *window;
|
||||||
opus_uint32 redundant_rng = 0;
|
opus_uint32 redundant_rng = 0;
|
||||||
|
int celt_accum;
|
||||||
ALLOC_STACK;
|
ALLOC_STACK;
|
||||||
|
|
||||||
silk_dec = (char*)st+st->silk_dec_offset;
|
silk_dec = (char*)st+st->silk_dec_offset;
|
||||||
|
@ -295,6 +290,14 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In fixed-point, we can tell CELT to do the accumulation on top of the
|
||||||
|
SILK PCM buffer. This saves some stack space. */
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10);
|
||||||
|
#else
|
||||||
|
celt_accum = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
pcm_transition_silk_size = ALLOC_NONE;
|
pcm_transition_silk_size = ALLOC_NONE;
|
||||||
pcm_transition_celt_size = ALLOC_NONE;
|
pcm_transition_celt_size = ALLOC_NONE;
|
||||||
if (data!=NULL && st->prev_mode > 0 && (
|
if (data!=NULL && st->prev_mode > 0 && (
|
||||||
|
@ -325,14 +328,20 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't allocate any memory when in CELT-only mode */
|
/* Don't allocate any memory when in CELT-only mode */
|
||||||
pcm_silk_size = (mode != MODE_CELT_ONLY) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE;
|
pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE;
|
||||||
ALLOC(pcm_silk, pcm_silk_size, opus_int16);
|
ALLOC(pcm_silk, pcm_silk_size, opus_int16);
|
||||||
|
|
||||||
/* SILK processing */
|
/* SILK processing */
|
||||||
if (mode != MODE_CELT_ONLY)
|
if (mode != MODE_CELT_ONLY)
|
||||||
{
|
{
|
||||||
int lost_flag, decoded_samples;
|
int lost_flag, decoded_samples;
|
||||||
opus_int16 *pcm_ptr = pcm_silk;
|
opus_int16 *pcm_ptr;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
if (celt_accum)
|
||||||
|
pcm_ptr = pcm;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
pcm_ptr = pcm_silk;
|
||||||
|
|
||||||
if (st->prev_mode==MODE_CELT_ONLY)
|
if (st->prev_mode==MODE_CELT_ONLY)
|
||||||
silk_InitDecoder( silk_dec );
|
silk_InitDecoder( silk_dec );
|
||||||
|
@ -462,7 +471,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||||
{
|
{
|
||||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||||
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
|
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
|
||||||
redundant_audio, F5, NULL);
|
redundant_audio, F5, NULL, 0);
|
||||||
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
|
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,25 +486,28 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||||
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
||||||
/* Decode CELT */
|
/* Decode CELT */
|
||||||
celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
|
celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
|
||||||
len, pcm, celt_frame_size, &dec);
|
len, pcm, celt_frame_size, &dec, celt_accum);
|
||||||
} else {
|
} else {
|
||||||
unsigned char silence[2] = {0xFF, 0xFF};
|
unsigned char silence[2] = {0xFF, 0xFF};
|
||||||
for (i=0;i<frame_size*st->channels;i++)
|
if (!celt_accum)
|
||||||
pcm[i] = 0;
|
{
|
||||||
|
for (i=0;i<frame_size*st->channels;i++)
|
||||||
|
pcm[i] = 0;
|
||||||
|
}
|
||||||
/* For hybrid -> SILK transitions, we let the CELT MDCT
|
/* For hybrid -> SILK transitions, we let the CELT MDCT
|
||||||
do a fade-out by decoding a silence frame */
|
do a fade-out by decoding a silence frame */
|
||||||
if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
|
if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
|
||||||
{
|
{
|
||||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||||
celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL);
|
celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode != MODE_CELT_ONLY)
|
if (mode != MODE_CELT_ONLY && !celt_accum)
|
||||||
{
|
{
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
for (i=0;i<frame_size*st->channels;i++)
|
for (i=0;i<frame_size*st->channels;i++)
|
||||||
pcm[i] = SAT16(pcm[i] + pcm_silk[i]);
|
pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i]));
|
||||||
#else
|
#else
|
||||||
for (i=0;i<frame_size*st->channels;i++)
|
for (i=0;i<frame_size*st->channels;i++)
|
||||||
pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]);
|
pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]);
|
||||||
|
@ -514,7 +526,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||||
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
||||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||||
|
|
||||||
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL);
|
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0);
|
||||||
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
|
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,
|
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);
|
pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue