#include "config.h"
#endif
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <stdarg.h>
#include "celt.h"
-#include "opus_decoder.h"
+#include "opus.h"
#include "entdec.h"
#include "modes.h"
#include "silk_API.h"
+#include "stack_alloc.h"
+#include "float_cast.h"
+#include "opus_private.h"
+#include "os_support.h"
+
+#ifdef FIXED_POINT
+#define celt_decode_native celt_decode
+#else
+#define celt_decode_native celt_decode_float
+#endif
-#define MAX_PACKET (1275)
+struct OpusDecoder {
+ int celt_dec_offset;
+ int silk_dec_offset;
+ int channels;
+ int stream_channels;
+
+ int bandwidth;
+ /* Sampling rate (at the API level) */
+ int Fs;
+ int mode;
+ int prev_mode;
+ int frame_size;
+ int prev_redundancy;
+
+ int rangeFinal;
+};
+
+#ifdef FIXED_POINT
+static inline opus_int16 SAT16(opus_int32 x) {
+ return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
+};
+#endif
-/* Make sure everything's aligned to 4 bytes (this may need to be increased
- on really weird architectures) */
-static inline int align(int i)
-{
- return (i+3)&-4;
-}
int opus_decoder_get_size(int channels)
{
}
-OpusDecoder *opus_decoder_init(OpusDecoder *st, int Fs, int channels)
+int opus_decoder_init(OpusDecoder *st, int Fs, int channels)
{
void *silk_dec;
CELTDecoder *celt_dec;
int ret, silkDecSizeBytes;
if (channels<1 || channels > 2)
- return NULL;
- memset(st, 0, opus_decoder_get_size(channels));
+ 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 NULL;
+ return OPUS_INTERNAL_ERROR;
}
silkDecSizeBytes = align(silkDecSizeBytes);
st->silk_dec_offset = align(sizeof(OpusDecoder));
celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0));
st->prev_mode = 0;
- return st;
+ st->frame_size = Fs/400;
+ return OPUS_OK;
failure:
- free(st);
- return NULL;
+ opus_free(st);
+ return OPUS_INTERNAL_ERROR;
}
-OpusDecoder *opus_decoder_create(int Fs, int channels)
+OpusDecoder *opus_decoder_create(int Fs, int channels, int *error)
{
- char *raw_state = (char*)malloc(opus_decoder_get_size(channels));
- if (raw_state == NULL)
- return NULL;
- return opus_decoder_init((OpusDecoder*)raw_state, Fs, channels);
+ int ret;
+ OpusDecoder *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 (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ return st;
}
-static void smooth_fade(const short *in1, const short *in2, short *out,
- int overlap, int channels, const celt_word16 *window, int Fs)
+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;
int inc = 48000/Fs;
{
for (i=0;i<overlap;i++)
{
- celt_word16 w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ 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_decode_frame(OpusDecoder *st, const unsigned char *data,
- int len, short *pcm, int frame_size, int decode_fec)
+ int len, opus_val16 *pcm, int frame_size, int decode_fec)
{
void *silk_dec;
CELTDecoder *celt_dec;
ec_dec dec;
silk_DecControlStruct DecControl;
opus_int32 silk_frame_size;
- short pcm_celt[960*2];
- short pcm_transition[480*2];
+ VARDECL(opus_int16, pcm_silk);
+ VARDECL(opus_val16, pcm_transition);
+ VARDECL(opus_val16, redundant_audio);
int audiosize;
int mode;
int redundancy=0;
int redundancy_bytes = 0;
int celt_to_silk=0;
- short redundant_audio[240*2];
int c;
int F2_5, F5, F10, F20;
- const celt_word16 *window;
+ 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);
F10 = F20>>1;
F5 = F10>>1;
F2_5 = F5>>1;
+ if (frame_size < F2_5)
+ return OPUS_BUFFER_TOO_SMALL;
/* 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 */
+ /* FIXME: What if st->frame_size has never been set? */
frame_size = IMIN(frame_size, st->frame_size);
}
if (data != NULL)
ec_dec_init(&dec,(unsigned char*)data,len);
} else {
audiosize = frame_size;
+
if (st->prev_mode == 0)
{
/* If we haven't got any packet yet, all we can do is return zeros */
- for (i=0;i<audiosize;i++)
+ for (i=0;i<audiosize*st->channels;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);
+ /*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 );
do {
/* Call SILK decoder */
int first_frame = decoded_samples == 0;
- silk_ret = silk_Decode( silk_dec, &DecControl,
+ silk_ret = silk_Decode( silk_dec, &DecControl,
lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size );
if( silk_ret ) {
if (lost_flag) {
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;
}
}
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;
}
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_GET_RANGE(&redundant_rng));
celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
}
{
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
}
{
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);
+ celt_decoder_ctl(celt_dec, CELT_GET_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);
}
st->channels, window, st->Fs);
}
- st->rangeFinal = dec.rng;
+ if (len <= 1)
+ st->rangeFinal = 0;
+ else
+ st->rangeFinal = dec.rng ^ redundant_rng;
st->prev_mode = mode;
st->prev_redundancy = redundancy;
+ RESTORE_STACK;
return celt_ret<0 ? celt_ret : audiosize;
}
}
}
-int opus_decode(OpusDecoder *st, const unsigned char *data,
- int len, short *pcm, int frame_size, int decode_fec)
+static int opus_packet_parse_impl(const unsigned char *data, int len,
+ int self_delimited, unsigned char *out_toc,
+ const unsigned char *frames[48], short size[48], int *payload_offset)
{
- int i, bytes, nb_samples;
- int count;
- unsigned char ch, toc;
+ int i, bytes;
+ int count;
+ int cbr;
+ unsigned char ch, toc;
+ int framesize;
+ int last_size;
+ const unsigned char *data0 = data;
+
+ if (size==NULL)
+ return OPUS_BAD_ARG;
+
+ framesize = opus_packet_get_samples_per_frame(data, 48000);
+
+ cbr = 0;
+ toc = *data++;
+ len--;
+ last_size = len;
+ switch (toc&0x3)
+ {
+ /* One frame */
+ case 0:
+ count=1;
+ break;
+ /* Two CBR frames */
+ case 1:
+ count=2;
+ cbr = 1;
+ if (!self_delimited)
+ {
+ if (len&0x1)
+ return OPUS_CORRUPTED_DATA;
+ size[0] = last_size = len/2;
+ }
+ break;
+ /* Two VBR frames */
+ case 2:
+ count = 2;
+ bytes = parse_size(data, len, size);
+ len -= bytes;
+ if (size[0]<0 || size[0] > len)
+ return OPUS_CORRUPTED_DATA;
+ data += bytes;
+ last_size = len-size[0];
+ break;
+ /* Multiple CBR/VBR frames (from 0 to 120 ms) */
+ case 3:
+ if (len<1)
+ return OPUS_CORRUPTED_DATA;
+ /* Number of frames encoded in bits 0 to 5 */
+ ch = *data++;
+ count = ch&0x3F;
+ if (count <= 0 || framesize*count > 5760)
+ return OPUS_CORRUPTED_DATA;
+ len--;
+ /* Padding flag is bit 6 */
+ if (ch&0x40)
+ {
+ int padding=0;
+ int p;
+ do {
+ if (len<=0)
+ return OPUS_CORRUPTED_DATA;
+ p = *data++;
+ len--;
+ padding += p==255 ? 254: p;
+ } while (p==255);
+ len -= padding;
+ }
+ if (len<0)
+ return OPUS_CORRUPTED_DATA;
+ /* VBR flag is bit 7 */
+ cbr = !(ch&0x80);
+ if (cbr)
+ {
+ /* VBR case */
+ last_size = len;
+ for (i=0;i<count-1;i++)
+ {
+ bytes = parse_size(data, len, size+i);
+ len -= bytes;
+ if (size[i]<0 || size[i] > len)
+ return OPUS_CORRUPTED_DATA;
+ data += bytes;
+ last_size -= bytes+size[i];
+ }
+ if (last_size<0)
+ return OPUS_CORRUPTED_DATA;
+ } else if (!self_delimited)
+ {
+ /* CBR case */
+ last_size = len/count;
+ if (last_size*count!=len)
+ return OPUS_CORRUPTED_DATA;
+ for (i=0;i<count-1;i++)
+ size[i] = last_size;
+ }
+ break;
+ }
+ /* Self-delimited framing has an extra size for the last frame. */
+ if (self_delimited)
+ {
+ bytes = parse_size(data, len, size+count-1);
+ len -= bytes;
+ if (size[count-1]<0 || size[count-1] > len)
+ return OPUS_CORRUPTED_DATA;
+ data += bytes;
+ /* For CBR packets, apply the size to all the frames. */
+ if (cbr)
+ {
+ if (size[count-1]*count > len)
+ return OPUS_CORRUPTED_DATA;
+ for (i=0;i<count-1;i++)
+ size[i] = size[count-1];
+ } else if(size[count-1] > last_size)
+ return OPUS_CORRUPTED_DATA;
+ } else
+ {
+ /* Because it's not encoded explicitly, it's possible the size of the
+ last packet (or all the packets, for the CBR case) is larger than
+ 1275.
+ Reject them here.*/
+ if (last_size > 1275)
+ return OPUS_CORRUPTED_DATA;
+ size[count-1] = last_size;
+ }
+
+ if (frames)
+ {
+ for (i=0;i<count;i++)
+ {
+ frames[i] = data;
+ data += size[i];
+ }
+ }
+
+ if (out_toc)
+ *out_toc = toc;
+
+ if (payload_offset)
+ *payload_offset = data-data0;
+
+ return count;
+}
+
+int opus_packet_parse(const unsigned char *data, int len,
+ unsigned char *out_toc, const unsigned char *frames[48],
+ short size[48], int *payload_offset)
+{
+ return opus_packet_parse_impl(data, len, 0,
+ out_toc, frames, size, payload_offset);
+}
+
+int opus_decode_native(OpusDecoder *st, const unsigned char *data,
+ int len, opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, int *packet_offset)
+{
+ int i, nb_samples;
+ int count, offset;
+ unsigned char toc;
+ int tot_offset;
/* 48 x 2.5 ms = 120 ms */
short size[48];
if (len==0 || data==NULL)
return opus_decode_frame(st, NULL, 0, pcm, frame_size, 0);
else if (len<0)
return OPUS_BAD_ARG;
+
+ tot_offset = 0;
st->mode = opus_packet_get_mode(data);
st->bandwidth = opus_packet_get_bandwidth(data);
st->frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
st->stream_channels = opus_packet_get_nb_channels(data);
- toc = *data++;
- len--;
- switch (toc&0x3)
- {
- /* One frame */
- case 0:
- count=1;
- size[0] = len;
- break;
- /* Two CBR frames */
- case 1:
- count=2;
- if (len&0x1)
- return OPUS_CORRUPTED_DATA;
- size[0] = size[1] = len/2;
- break;
- /* Two VBR frames */
- case 2:
- count = 2;
- bytes = parse_size(data, len, size);
- len -= bytes;
- if (size[0]<0 || size[0] > len)
- return OPUS_CORRUPTED_DATA;
- data += bytes;
- size[1] = len-size[0];
- break;
- /* Multiple CBR/VBR frames (from 0 to 120 ms) */
- case 3:
- if (len<1)
- return OPUS_CORRUPTED_DATA;
- /* Number of frames encoded in bits 0 to 5 */
- ch = *data++;
- count = ch&0x3F;
- if (count <= 0 || st->frame_size*count*25 > 3*st->Fs)
- return OPUS_CORRUPTED_DATA;
- len--;
- /* Padding flag is bit 6 */
- if (ch&0x40)
- {
- int padding=0;
- int p;
- do {
- if (len<=0)
- return OPUS_CORRUPTED_DATA;
- p = *data++;
- len--;
- padding += p==255 ? 254: p;
- } while (p==255);
- len -= padding;
- }
- if (len<0)
- return OPUS_CORRUPTED_DATA;
- /* VBR flag is bit 7 */
- if (ch&0x80)
- {
- /* VBR case */
- int last_size=len;
- for (i=0;i<count-1;i++)
- {
- bytes = parse_size(data, len, size+i);
- len -= bytes;
- if (size[i]<0 || size[i] > len)
- return OPUS_CORRUPTED_DATA;
- data += bytes;
- last_size -= bytes+size[i];
- }
- if (last_size<0)
- return OPUS_CORRUPTED_DATA;
- size[count-1]=last_size;
- } else {
- /* CBR case */
- int sz = len/count;
- if (sz*count!=len)
- return OPUS_CORRUPTED_DATA;
- for (i=0;i<count;i++)
- size[i] = sz;
- }
- break;
- }
- /* Because it's not encoded explicitly, it's possible the size of the
- last packet (or all the packets, for the CBR case) is larger than
- 1275.
- Reject them here.*/
- if (size[count-1] > MAX_PACKET)
- return OPUS_CORRUPTED_DATA;
+
+ count = opus_packet_parse_impl(data, len, 0, &toc, NULL, size, &offset);
+ if (count < 0)
+ return count;
+
+ data += offset;
+ tot_offset += offset;
+
if (count*st->frame_size > frame_size)
return OPUS_BAD_ARG;
nb_samples=0;
if (ret<0)
return ret;
data += size[i];
+ tot_offset += size[i];
pcm += ret*st->channels;
nb_samples += ret;
}
+ if (packet_offset != NULL)
+ *packet_offset = tot_offset;
return nb_samples;
}
-int opus_decoder_ctl(OpusDecoder *st, int request, ...)
+
+#ifdef FIXED_POINT
+
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+ int len, opus_val16 *pcm, int frame_size, int decode_fec)
{
- va_list ap;
+ return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL);
+}
- va_start(ap, request);
+#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_native(st, data, len, out, frame_size, decode_fec, 0, NULL);
+ if (ret > 0)
+ {
+ for (i=0;i<ret*st->channels;i++)
+ pcm[i] = (1./32768.)*(out[i]);
+ }
+ RESTORE_STACK;
+ return ret;
+}
+#endif
- switch (request)
- {
- case OPUS_GET_MODE_REQUEST:
- {
- int *value = va_arg(ap, int*);
- *value = st->prev_mode;
- }
- break;
- case OPUS_SET_BANDWIDTH_REQUEST:
- {
- int value = va_arg(ap, int);
- st->bandwidth = value;
- }
- break;
- case OPUS_GET_BANDWIDTH_REQUEST:
- {
- int *value = va_arg(ap, int*);
- *value = st->bandwidth;
- }
- break;
- default:
- fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);
- break;
- }
- va_end(ap);
- return OPUS_OK;
+#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_native(st, data, len, out, frame_size, decode_fec, 0, NULL);
+ if (ret > 0)
+ {
+ for (i=0;i<ret*st->channels;i++)
+ pcm[i] = FLOAT2INT16(out[i]);
+ }
+ RESTORE_STACK;
+ return ret;
}
-void opus_decoder_destroy(OpusDecoder *st)
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+ int len, opus_val16 *pcm, int frame_size, int decode_fec)
{
- free(st);
+ return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL);
}
-int opus_decoder_get_final_range(OpusDecoder *st)
+#endif
+
+int opus_decoder_ctl(OpusDecoder *st, int request, ...)
+{
+ int ret = OPUS_OK;
+ va_list ap;
+
+ va_start(ap, request);
+
+ switch (request)
+ {
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ *value = st->bandwidth;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ *value = st->rangeFinal;
+ }
+ break;
+ default:
+ /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
+ ret = OPUS_BAD_ARG;
+ break;
+ }
+
+ va_end(ap);
+ return ret;
+}
+
+void opus_decoder_destroy(OpusDecoder *st)
{
- return st->rangeFinal;
+ opus_free(st);
}
+
int opus_packet_get_bandwidth(const unsigned char *data)
{
int bandwidth;