Adds a floating-point API to Opus
The high-level Opus encoder and decoder can now be compiled as either fixed or float. Also, we now use the stack_alloc.h macros in the top-level Opus code.
This commit is contained in:
parent
8a23fe977f
commit
222494f3ea
7 changed files with 230 additions and 95 deletions
|
@ -283,14 +283,6 @@ void celt_encoder_destroy(CELTEncoder *st)
|
|||
celt_free(st);
|
||||
}
|
||||
|
||||
static inline opus_int16 FLOAT2INT16(float x)
|
||||
{
|
||||
x = x*CELT_SIG_SCALE;
|
||||
x = MAX32(x, -32768);
|
||||
x = MIN32(x, 32767);
|
||||
return (opus_int16)float2int(x);
|
||||
}
|
||||
|
||||
static inline opus_val16 SIG2WORD16(celt_sig x)
|
||||
{
|
||||
#ifdef FIXED_POINT
|
||||
|
@ -891,15 +883,9 @@ static int stereo_analysis(const CELTMode *m, const celt_norm *X,
|
|||
> MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
|
||||
}
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
CELT_STATIC
|
||||
int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
|
||||
int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
|
||||
{
|
||||
#else
|
||||
CELT_STATIC
|
||||
int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
|
||||
{
|
||||
#endif
|
||||
int i, c, N;
|
||||
opus_int32 bits;
|
||||
ec_enc _enc;
|
||||
|
@ -1675,10 +1661,16 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
|
|||
return nbCompressedBytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
int celt_encode(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
|
||||
{
|
||||
return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
CELT_STATIC
|
||||
int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
|
||||
int celt_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
|
||||
{
|
||||
int j, ret, C, N;
|
||||
VARDECL(opus_int16, in);
|
||||
|
@ -1694,19 +1686,18 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int
|
|||
for (j=0;j<C*N;j++)
|
||||
in[j] = FLOAT2INT16(pcm[j]);
|
||||
|
||||
ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, enc);
|
||||
ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
|
||||
#ifdef RESYNTH
|
||||
for (j=0;j<C*N;j++)
|
||||
((float*)pcm)[j]=in[j]*(1.f/32768.f);
|
||||
#endif
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif /*DISABLE_FLOAT_API*/
|
||||
#endif /* DISABLE_FLOAT_API */
|
||||
#else
|
||||
CELT_STATIC
|
||||
int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
|
||||
|
||||
int celt_encode(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
|
||||
{
|
||||
int j, ret, C, N;
|
||||
VARDECL(celt_sig, in);
|
||||
|
@ -1722,7 +1713,7 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int f
|
|||
in[j] = SCALEOUT(pcm[j]);
|
||||
}
|
||||
|
||||
ret = celt_encode_with_ec_float(st,in,frame_size,compressed,nbCompressedBytes, enc);
|
||||
ret = celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
|
||||
#ifdef RESYNTH
|
||||
for (j=0;j<C*N;j++)
|
||||
((opus_int16*)pcm)[j] = FLOAT2INT16(in[j]);
|
||||
|
@ -1730,20 +1721,14 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int f
|
|||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int celt_encode(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
|
||||
int celt_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
|
||||
{
|
||||
return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
int celt_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
|
||||
{
|
||||
return celt_encode_with_ec_float(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
|
||||
}
|
||||
#endif /* DISABLE_FLOAT_API */
|
||||
|
||||
#endif
|
||||
int celt_encoder_ctl(CELTEncoder * restrict st, int request, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -2252,15 +2237,9 @@ static void celt_decode_lost(CELTDecoder * restrict st, opus_val16 * restrict pc
|
|||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
CELT_STATIC
|
||||
int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size, ec_dec *dec)
|
||||
int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_val16 * restrict pcm, int frame_size, ec_dec *dec)
|
||||
{
|
||||
#else
|
||||
CELT_STATIC
|
||||
int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, celt_sig * restrict pcm, int frame_size, ec_dec *dec)
|
||||
{
|
||||
#endif
|
||||
int c, i, N;
|
||||
int spread_decision;
|
||||
opus_int32 bits;
|
||||
|
@ -2627,10 +2606,16 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
|
|||
return frame_size/st->downsample;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
int celt_decode(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size)
|
||||
{
|
||||
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
CELT_STATIC
|
||||
int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size, ec_dec *dec)
|
||||
int celt_decode_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size)
|
||||
{
|
||||
int j, ret, C, N;
|
||||
VARDECL(opus_int16, out);
|
||||
|
@ -2643,7 +2628,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
|
|||
N = frame_size;
|
||||
|
||||
ALLOC(out, C*N, opus_int16);
|
||||
ret=celt_decode_with_ec(st, data, len, out, frame_size, dec);
|
||||
ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL);
|
||||
if (ret>0)
|
||||
for (j=0;j<C*ret;j++)
|
||||
pcm[j]=out[j]*(1.f/32768.f);
|
||||
|
@ -2651,10 +2636,16 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
|
|||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
#endif /*DISABLE_FLOAT_API*/
|
||||
#endif /* DISABLE_FLOAT_API */
|
||||
|
||||
#else
|
||||
CELT_STATIC
|
||||
int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size, ec_dec *dec)
|
||||
|
||||
int celt_decode_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size)
|
||||
{
|
||||
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
|
||||
}
|
||||
|
||||
int celt_decode(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size)
|
||||
{
|
||||
int j, ret, C, N;
|
||||
VARDECL(celt_sig, out);
|
||||
|
@ -2667,7 +2658,7 @@ int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, in
|
|||
N = frame_size;
|
||||
ALLOC(out, C*N, celt_sig);
|
||||
|
||||
ret=celt_decode_with_ec_float(st, data, len, out, frame_size, dec);
|
||||
ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL);
|
||||
|
||||
if (ret>0)
|
||||
for (j=0;j<C*ret;j++)
|
||||
|
@ -2676,19 +2667,9 @@ int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, in
|
|||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int celt_decode(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size)
|
||||
{
|
||||
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
int celt_decode_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size)
|
||||
{
|
||||
return celt_decode_with_ec_float(st, data, len, pcm, frame_size, NULL);
|
||||
}
|
||||
#endif /* DISABLE_FLOAT_API */
|
||||
|
||||
int celt_decoder_ctl(CELTDecoder * restrict st, int request, ...)
|
||||
{
|
||||
|
|
|
@ -123,4 +123,12 @@
|
|||
#define float2int(flt) ((int)(floor(.5+flt)))
|
||||
#endif
|
||||
|
||||
static inline opus_int16 FLOAT2INT16(float x)
|
||||
{
|
||||
x = x*CELT_SIG_SCALE;
|
||||
x = MAX32(x, -32768);
|
||||
x = MIN32(x, 32767);
|
||||
return (opus_int16)float2int(x);
|
||||
}
|
||||
|
||||
#endif /* FLOAT_CAST_H */
|
||||
|
|
|
@ -102,10 +102,8 @@ struct CELTMode {
|
|||
#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, _celt_check_mode_ptr_ptr(x)
|
||||
|
||||
/* Prototypes for _ec versions of the encoder/decoder calls (not public) */
|
||||
int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
|
||||
int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
|
||||
int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size, ec_dec *dec);
|
||||
int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size, ec_dec *dec);
|
||||
int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
|
||||
int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_val16 * restrict pcm, int frame_size, ec_dec *dec);
|
||||
#endif /* OPUS_BUILD */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,6 +38,14 @@
|
|||
#include "entdec.h"
|
||||
#include "modes.h"
|
||||
#include "silk_API.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "float_cast.h"
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
#define celt_decode_native celt_decode
|
||||
#else
|
||||
#define celt_decode_native celt_decode_float
|
||||
#endif
|
||||
|
||||
/* Make sure everything's aligned to 4 bytes (this may need to be increased
|
||||
on really weird architectures) */
|
||||
|
@ -109,7 +117,7 @@ OpusDecoder *opus_decoder_create(int Fs, int channels)
|
|||
return opus_decoder_init((OpusDecoder*)raw_state, Fs, channels);
|
||||
}
|
||||
|
||||
static void smooth_fade(const opus_int16 *in1, const opus_int16 *in2, opus_int16 *out,
|
||||
static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, opus_val16 *out,
|
||||
int overlap, int channels, const opus_val16 *window, int Fs)
|
||||
{
|
||||
int i, c;
|
||||
|
@ -142,7 +150,7 @@ static int opus_packet_get_mode(const unsigned char *data)
|
|||
}
|
||||
|
||||
static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
||||
int len, opus_int16 *pcm, int frame_size, int decode_fec)
|
||||
int len, opus_val16 *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
void *silk_dec;
|
||||
CELTDecoder *celt_dec;
|
||||
|
@ -150,8 +158,8 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
ec_dec dec;
|
||||
silk_DecControlStruct DecControl;
|
||||
opus_int32 silk_frame_size;
|
||||
opus_int16 pcm_celt[960*2];
|
||||
opus_int16 pcm_transition[480*2];
|
||||
VARDECL(opus_int16, pcm_silk);
|
||||
VARDECL(opus_val16, pcm_transition);
|
||||
|
||||
int audiosize;
|
||||
int mode;
|
||||
|
@ -160,10 +168,10 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
int redundancy=0;
|
||||
int redundancy_bytes = 0;
|
||||
int celt_to_silk=0;
|
||||
opus_int16 redundant_audio[240*2];
|
||||
int c;
|
||||
int F2_5, F5, F10, F20;
|
||||
const opus_val16 *window;
|
||||
ALLOC_STACK;
|
||||
|
||||
silk_dec = (char*)st+st->silk_dec_offset;
|
||||
celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
|
||||
|
@ -176,6 +184,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
{
|
||||
data = NULL;
|
||||
/* In that case, don't conceal more than what the ToC says */
|
||||
/* FIXME: What if st->frame_size has never been set? */
|
||||
frame_size = IMIN(frame_size, st->frame_size);
|
||||
}
|
||||
if (data != NULL)
|
||||
|
@ -190,33 +199,40 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
/* If we haven't got any packet yet, all we can do is return zeros */
|
||||
for (i=0;i<audiosize;i++)
|
||||
pcm[i] = 0;
|
||||
RESTORE_STACK;
|
||||
return audiosize;
|
||||
} else {
|
||||
mode = st->prev_mode;
|
||||
}
|
||||
}
|
||||
|
||||
ALLOC(pcm_transition, F5*st->channels, opus_val16);
|
||||
|
||||
if (data!=NULL && !st->prev_redundancy && mode != st->prev_mode && st->prev_mode > 0
|
||||
&& !(mode == MODE_SILK_ONLY && st->prev_mode == MODE_HYBRID)
|
||||
&& !(mode == MODE_HYBRID && st->prev_mode == MODE_SILK_ONLY))
|
||||
{
|
||||
transition = 1;
|
||||
if (mode == MODE_CELT_ONLY)
|
||||
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F10, audiosize), 0);
|
||||
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
|
||||
}
|
||||
if (audiosize > frame_size)
|
||||
{
|
||||
fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
} else {
|
||||
frame_size = audiosize;
|
||||
}
|
||||
|
||||
ALLOC(pcm_silk, frame_size*st->channels, opus_int16);
|
||||
ALLOC(redundant_audio, F5*st->channels, opus_val16);
|
||||
|
||||
/* SILK processing */
|
||||
if (mode != MODE_CELT_ONLY)
|
||||
{
|
||||
int lost_flag, decoded_samples;
|
||||
opus_int16 *pcm_ptr = pcm;
|
||||
opus_int16 *pcm_ptr = pcm_silk;
|
||||
|
||||
if (st->prev_mode==MODE_CELT_ONLY)
|
||||
silk_InitDecoder( silk_dec );
|
||||
|
@ -254,15 +270,14 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
silk_frame_size = frame_size;
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
pcm_ptr[i] = 0;
|
||||
} else
|
||||
return OPUS_CORRUPTED_DATA;
|
||||
} else {
|
||||
RESTORE_STACK;
|
||||
return OPUS_CORRUPTED_DATA;
|
||||
}
|
||||
}
|
||||
pcm_ptr += silk_frame_size * st->channels;
|
||||
decoded_samples += silk_frame_size;
|
||||
} while( decoded_samples < frame_size );
|
||||
} else {
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
pcm[i] = 0;
|
||||
}
|
||||
|
||||
start_band = 0;
|
||||
|
@ -285,8 +300,10 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
}
|
||||
}
|
||||
len -= redundancy_bytes;
|
||||
if (len<0)
|
||||
return OPUS_CORRUPTED_DATA;
|
||||
if (len<0) {
|
||||
RESTORE_STACK;
|
||||
return OPUS_CORRUPTED_DATA;
|
||||
}
|
||||
/* Shrink decoder because of raw bits */
|
||||
dec.storage -= redundancy_bytes;
|
||||
}
|
||||
|
@ -321,13 +338,13 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
transition = 0;
|
||||
|
||||
if (transition && mode != MODE_CELT_ONLY)
|
||||
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F10, audiosize), 0);
|
||||
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
|
||||
|
||||
/* 5 ms redundant frame for CELT->SILK*/
|
||||
if (redundancy && celt_to_silk)
|
||||
{
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||
celt_decode(celt_dec, data+len, redundancy_bytes, redundant_audio, F5);
|
||||
celt_decode_native(celt_dec, data+len, redundancy_bytes, redundant_audio, F5);
|
||||
celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
|
||||
}
|
||||
|
||||
|
@ -341,9 +358,21 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
{
|
||||
int celt_frame_size = IMIN(F20, frame_size);
|
||||
/* Decode CELT */
|
||||
celt_ret = celt_decode_with_ec(celt_dec, decode_fec?NULL:data, len, pcm_celt, celt_frame_size, &dec);
|
||||
for (i=0;i<celt_frame_size*st->channels;i++)
|
||||
pcm[i] = SAT16(pcm[i] + (int)pcm_celt[i]);
|
||||
celt_ret = celt_decode_with_ec(celt_dec, decode_fec?NULL:data, len, pcm, celt_frame_size, &dec);
|
||||
} else {
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
pcm[i] = 0;
|
||||
}
|
||||
|
||||
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] + (1./32768.)*pcm_silk[i];
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -358,7 +387,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||
|
||||
celt_decode(celt_dec, data+len, redundancy_bytes, redundant_audio, F5);
|
||||
celt_decode_native(celt_dec, data+len, redundancy_bytes, redundant_audio, F5);
|
||||
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);
|
||||
}
|
||||
|
@ -386,6 +415,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
|
||||
st->prev_mode = mode;
|
||||
st->prev_redundancy = redundancy;
|
||||
RESTORE_STACK;
|
||||
return celt_ret<0 ? celt_ret : audiosize;
|
||||
|
||||
}
|
||||
|
@ -528,9 +558,13 @@ int opus_packet_parse(const unsigned char *data, int len,
|
|||
return count;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
int opus_decode(OpusDecoder *st, const unsigned char *data,
|
||||
int len, opus_int16 *pcm, int frame_size, int decode_fec)
|
||||
int len, opus_val16 *pcm, int frame_size, int decode_fec)
|
||||
#else
|
||||
int opus_decode_float(OpusDecoder *st, const unsigned char *data,
|
||||
int len, opus_val16 *pcm, int frame_size, int decode_fec)
|
||||
#endif
|
||||
{
|
||||
int i, nb_samples;
|
||||
int count;
|
||||
|
@ -566,6 +600,49 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
|
|||
return nb_samples;
|
||||
}
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
int opus_decode_float(OpusDecoder *st, const unsigned char *data,
|
||||
int len, float *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
VARDECL(opus_int16, out);
|
||||
int ret, i;
|
||||
ALLOC_STACK;
|
||||
|
||||
ALLOC(out, frame_size*st->channels, opus_int16);
|
||||
|
||||
ret = opus_decode(st, data, len, out, frame_size, decode_fec);
|
||||
if (ret > 0)
|
||||
{
|
||||
for (i=0;i<ret*st->channels;i++)
|
||||
pcm[i] = (1./32768.)*(out[i]);
|
||||
}
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
int opus_decode(OpusDecoder *st, const unsigned char *data,
|
||||
int len, opus_int16 *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
VARDECL(float, out);
|
||||
int ret, i;
|
||||
ALLOC_STACK;
|
||||
|
||||
ALLOC(out, frame_size*st->channels, float);
|
||||
|
||||
ret = opus_decode_float(st, data, len, out, frame_size, decode_fec);
|
||||
if (ret > 0)
|
||||
{
|
||||
for (i=0;i<ret*st->channels;i++)
|
||||
pcm[i] = FLOAT2INT16(out[i]);
|
||||
}
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int opus_decoder_ctl(OpusDecoder *st, int request, ...)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,14 @@
|
|||
#include "entenc.h"
|
||||
#include "modes.h"
|
||||
#include "silk_API.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "float_cast.h"
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
#define celt_encode_native celt_encode
|
||||
#else
|
||||
#define celt_encode_native celt_encode_float
|
||||
#endif
|
||||
|
||||
/* Transition tables for the voice and audio modes. First column is the
|
||||
middle (memoriless) threshold. The second column is the hysteresis
|
||||
|
@ -161,9 +169,13 @@ OpusEncoder *opus_encoder_create(int Fs, int channels, int mode)
|
|||
return NULL;
|
||||
return opus_encoder_init((OpusEncoder*)raw_state, Fs, channels, mode);
|
||||
}
|
||||
|
||||
int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
||||
#ifdef FIXED_POINT
|
||||
int opus_encode(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
|
||||
unsigned char *data, int max_data_bytes)
|
||||
#else
|
||||
int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
|
||||
unsigned char *data, int max_data_bytes)
|
||||
#endif
|
||||
{
|
||||
void *silk_enc;
|
||||
CELTEncoder *celt_enc;
|
||||
|
@ -179,12 +191,11 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
|||
int redundancy = 0;
|
||||
int redundancy_bytes = 0;
|
||||
int celt_to_silk = 0;
|
||||
/* TODO: This is 60 only so we can handle 60ms speech/audio switching
|
||||
it shouldn't be too hard to reduce to 20 ms if needed */
|
||||
opus_int16 pcm_buf[60*48*2];
|
||||
VARDECL(opus_val16, pcm_buf);
|
||||
int nb_compr_bytes;
|
||||
int to_celt = 0;
|
||||
opus_int32 mono_rate;
|
||||
ALLOC_STACK;
|
||||
|
||||
if (400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs &&
|
||||
50*frame_size != st->Fs && 25*frame_size != st->Fs && 50*frame_size != 3*st->Fs)
|
||||
|
@ -378,6 +389,12 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
|||
/* SILK processing */
|
||||
if (st->mode != MODE_CELT_ONLY)
|
||||
{
|
||||
#ifdef FIXED_POINT
|
||||
const opus_int16 *pcm_silk;
|
||||
#else
|
||||
VARDECL(opus_int16, pcm_silk);
|
||||
ALLOC(pcm_silk, st->channels*frame_size, opus_int16);
|
||||
#endif
|
||||
st->silk_mode.bitRate = st->bitrate_bps - 8*st->Fs/frame_size;
|
||||
if( st->mode == MODE_HYBRID ) {
|
||||
st->silk_mode.bitRate /= st->stream_channels;
|
||||
|
@ -429,10 +446,22 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
|||
if (prefill)
|
||||
{
|
||||
int zero=0;
|
||||
silk_Encode( silk_enc, &st->silk_mode, st->delay_buffer, st->encoder_buffer, NULL, &zero, 1 );
|
||||
#ifdef FIXED_POINT
|
||||
pcm_silk = st->delay_buffer;
|
||||
#else
|
||||
for (i=0;i<st->encoder_buffer*st->channels;i++)
|
||||
pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]);
|
||||
#endif
|
||||
silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 );
|
||||
}
|
||||
|
||||
ret = silk_Encode( silk_enc, &st->silk_mode, pcm, frame_size, &enc, &nBytes, 0 );
|
||||
#ifdef FIXED_POINT
|
||||
pcm_silk = pcm;
|
||||
#else
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
pcm_silk[i] = FLOAT2INT16(pcm[i]);
|
||||
#endif
|
||||
ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 );
|
||||
if( ret ) {
|
||||
fprintf (stderr, "SILK encode error: %d\n", ret);
|
||||
/* Handle error */
|
||||
|
@ -487,7 +516,7 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
|||
celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
|
||||
celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
|
||||
/* TODO: This wastes CPU a bit compared to just prefilling the buffer */
|
||||
celt_encode(celt_enc, &st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10);
|
||||
celt_encode_native(celt_enc, &st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10);
|
||||
} else {
|
||||
celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2));
|
||||
}
|
||||
|
@ -519,6 +548,7 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
|||
nb_compr_bytes = 0;
|
||||
}
|
||||
|
||||
ALLOC(pcm_buf, IMAX(frame_size, st->Fs/200)*st->channels, opus_val16);
|
||||
for (i=0;i<IMIN(frame_size, st->delay_compensation)*st->channels;i++)
|
||||
pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation)*st->channels+i];
|
||||
for (;i<frame_size*st->channels;i++)
|
||||
|
@ -588,7 +618,7 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
|||
{
|
||||
celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
|
||||
celt_encoder_ctl(celt_enc, CELT_SET_VBR(0));
|
||||
celt_encode(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes);
|
||||
celt_encode_native(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes);
|
||||
celt_encoder_ctl(celt_enc, CELT_RESET_STATE);
|
||||
}
|
||||
|
||||
|
@ -611,9 +641,9 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
|||
celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
|
||||
|
||||
/* TODO: We could speed up prefilling here */
|
||||
celt_encode(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, data+nb_compr_bytes, redundancy_bytes);
|
||||
celt_encode_native(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, data+nb_compr_bytes, redundancy_bytes);
|
||||
|
||||
celt_encode(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes);
|
||||
celt_encode_native(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes);
|
||||
}
|
||||
|
||||
|
||||
|
@ -669,6 +699,45 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
|||
return ret+1+redundancy_bytes;
|
||||
}
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
int opus_encode_float(OpusEncoder *st, const float *pcm, int frame_size,
|
||||
unsigned char *data, int max_data_bytes)
|
||||
{
|
||||
int i, ret;
|
||||
VARDECL(opus_int16, in);
|
||||
ALLOC_STACK;
|
||||
|
||||
ALLOC(in, frame_size*st->channels, opus_int16);
|
||||
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
in[i] = FLOAT2INT16(pcm[i]);
|
||||
ret = opus_encode(st, in, frame_size, data, max_data_bytes);
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
|
||||
unsigned char *data, int max_data_bytes)
|
||||
{
|
||||
int i, ret;
|
||||
VARDECL(float, in);
|
||||
ALLOC_STACK;
|
||||
|
||||
ALLOC(in, frame_size*st->channels, float);
|
||||
|
||||
for (i=0;i<frame_size*st->channels;i++)
|
||||
in[i] = (1./32768)*pcm[i];
|
||||
ret = opus_encode_float(st, in, frame_size, data, max_data_bytes);
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int opus_encoder_ctl(OpusEncoder *st, int request, ...)
|
||||
{
|
||||
CELTEncoder *celt_enc;
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
#include "celt.h"
|
||||
#include "opus.h"
|
||||
#include "silk_API.h"
|
||||
#include "arch.h"
|
||||
|
||||
/* FIXME: This is only valid for 48 kHz */
|
||||
#define MAX_ENCODER_BUFFER 480
|
||||
|
||||
struct OpusEncoder {
|
||||
|
@ -60,7 +60,7 @@ struct OpusEncoder {
|
|||
int encoder_buffer;
|
||||
int delay_compensation;
|
||||
int first;
|
||||
short delay_buffer[MAX_ENCODER_BUFFER*2];
|
||||
opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2];
|
||||
|
||||
int rangeFinal;
|
||||
};
|
||||
|
|
|
@ -380,6 +380,8 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
fwrite(out+skip, sizeof(short)*channels, output_samples-skip, fout);
|
||||
skip = 0;
|
||||
} else {
|
||||
fprintf(stderr, "error decoding frame: %s\n", opus_strerror(output_samples));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue