Jean-Marc Valin | fbaabc1 | 2010-07-05 15:47:04 -0400 | [diff] [blame] | 1 | /* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited |
| 2 | Written by Jean-Marc Valin and Koen Vos */ |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 3 | /* |
| 4 | Redistribution and use in source and binary forms, with or without |
| 5 | modification, are permitted provided that the following conditions |
| 6 | are met: |
| 7 | |
| 8 | - Redistributions of source code must retain the above copyright |
| 9 | notice, this list of conditions and the following disclaimer. |
| 10 | |
| 11 | - Redistributions in binary form must reproduce the above copyright |
| 12 | notice, this list of conditions and the following disclaimer in the |
| 13 | documentation and/or other materials provided with the distribution. |
| 14 | |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
Jean-Marc Valin | cb05e7c | 2012-04-20 16:40:24 -0400 | [diff] [blame] | 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
| 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | #ifdef HAVE_CONFIG_H |
| 29 | #include "config.h" |
| 30 | #endif |
| 31 | |
Gregory Maxwell | 936f52c | 2012-05-13 11:40:19 -0400 | [diff] [blame] | 32 | #ifndef OPUS_BUILD |
Ralph Giles | 799b170 | 2012-11-29 11:40:04 -0800 | [diff] [blame] | 33 | #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." |
Gregory Maxwell | 936f52c | 2012-05-13 11:40:19 -0400 | [diff] [blame] | 34 | #endif |
| 35 | |
Jean-Marc Valin | 24f36e0 | 2010-07-06 14:41:20 -0400 | [diff] [blame] | 36 | #include <stdarg.h> |
Jean-Marc Valin | 8ea6704 | 2011-03-11 17:49:10 -0500 | [diff] [blame] | 37 | #include "celt.h" |
Jean-Marc Valin | d9920f3 | 2011-08-19 13:00:49 -0400 | [diff] [blame] | 38 | #include "opus.h" |
Jean-Marc Valin | a0cbeca | 2010-07-08 11:27:20 -0400 | [diff] [blame] | 39 | #include "entdec.h" |
| 40 | #include "modes.h" |
Jean-Marc Valin | 1c2f563 | 2011-09-16 01:16:53 -0700 | [diff] [blame] | 41 | #include "API.h" |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 42 | #include "stack_alloc.h" |
| 43 | #include "float_cast.h" |
Jean-Marc Valin | 6696a14 | 2011-08-22 10:40:38 -0400 | [diff] [blame] | 44 | #include "opus_private.h" |
Jean-Marc Valin | 07f8840 | 2011-08-29 15:08:51 -0400 | [diff] [blame] | 45 | #include "os_support.h" |
Jean-Marc Valin | 1c2f563 | 2011-09-16 01:16:53 -0700 | [diff] [blame] | 46 | #include "structs.h" |
| 47 | #include "define.h" |
Gregory Maxwell | 28b41ae | 2012-07-11 00:04:24 -0400 | [diff] [blame] | 48 | #include "mathops.h" |
Aurélien Zanelli | cd4c824 | 2013-05-31 15:07:00 +0200 | [diff] [blame] | 49 | #include "cpu_support.h" |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 50 | |
Jean-Marc Valin | d9920f3 | 2011-08-19 13:00:49 -0400 | [diff] [blame] | 51 | struct OpusDecoder { |
| 52 | int celt_dec_offset; |
| 53 | int silk_dec_offset; |
| 54 | int channels; |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 55 | opus_int32 Fs; /** Sampling rate (at the API level) */ |
Jean-Marc Valin | 0c5085a | 2011-10-04 01:10:32 -0400 | [diff] [blame] | 56 | silk_DecControlStruct DecControl; |
Gregory Maxwell | 03105f5 | 2012-07-11 02:33:55 -0400 | [diff] [blame] | 57 | int decode_gain; |
Jean-Marc Valin | 0446563 | 2011-08-30 18:01:06 -0400 | [diff] [blame] | 58 | |
| 59 | /* Everything beyond this point gets cleared on a reset */ |
| 60 | #define OPUS_DECODER_RESET_START stream_channels |
Jean-Marc Valin | d9920f3 | 2011-08-19 13:00:49 -0400 | [diff] [blame] | 61 | int stream_channels; |
| 62 | |
Jean-Marc Valin | 0446563 | 2011-08-30 18:01:06 -0400 | [diff] [blame] | 63 | int bandwidth; |
| 64 | int mode; |
| 65 | int prev_mode; |
| 66 | int frame_size; |
| 67 | int prev_redundancy; |
Jean-Marc Valin | 512d849 | 2012-12-04 14:13:46 -0500 | [diff] [blame] | 68 | int last_packet_duration; |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 69 | #ifndef FIXED_POINT |
| 70 | opus_val16 softclip_mem[2]; |
| 71 | #endif |
Jean-Marc Valin | d9920f3 | 2011-08-19 13:00:49 -0400 | [diff] [blame] | 72 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 73 | opus_uint32 rangeFinal; |
Aurélien Zanelli | cd4c824 | 2013-05-31 15:07:00 +0200 | [diff] [blame] | 74 | int arch; |
Jean-Marc Valin | d9920f3 | 2011-08-19 13:00:49 -0400 | [diff] [blame] | 75 | }; |
| 76 | |
| 77 | #ifdef FIXED_POINT |
| 78 | static inline opus_int16 SAT16(opus_int32 x) { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 79 | return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; |
Jean-Marc Valin | 14d63d1 | 2012-05-16 17:47:17 -0400 | [diff] [blame] | 80 | } |
Jean-Marc Valin | d9920f3 | 2011-08-19 13:00:49 -0400 | [diff] [blame] | 81 | #endif |
| 82 | |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 83 | |
Jean-Marc Valin | 280c060 | 2011-05-05 20:47:42 -0400 | [diff] [blame] | 84 | int opus_decoder_get_size(int channels) |
| 85 | { |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 86 | int silkDecSizeBytes, celtDecSizeBytes; |
| 87 | int ret; |
Gregory Maxwell | f451b33 | 2011-09-04 10:47:15 -0400 | [diff] [blame] | 88 | if (channels<1 || channels > 2) |
| 89 | return 0; |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 90 | ret = silk_Get_Decoder_Size( &silkDecSizeBytes ); |
| 91 | if(ret) |
| 92 | return 0; |
| 93 | silkDecSizeBytes = align(silkDecSizeBytes); |
| 94 | celtDecSizeBytes = celt_decoder_get_size(channels); |
| 95 | return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes; |
Jean-Marc Valin | 280c060 | 2011-05-05 20:47:42 -0400 | [diff] [blame] | 96 | } |
| 97 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 98 | int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 99 | { |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 100 | void *silk_dec; |
| 101 | CELTDecoder *celt_dec; |
| 102 | int ret, silkDecSizeBytes; |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 103 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 104 | if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) |
| 105 | || (channels!=1&&channels!=2)) |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 106 | return OPUS_BAD_ARG; |
Gregory Maxwell | 220a7d4 | 2011-10-01 20:30:16 -0400 | [diff] [blame] | 107 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 108 | OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); |
| 109 | /* Initialize SILK encoder */ |
Gregory Maxwell | e03af44 | 2011-09-04 04:43:11 -0400 | [diff] [blame] | 110 | ret = silk_Get_Decoder_Size(&silkDecSizeBytes); |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 111 | if (ret) |
| 112 | return OPUS_INTERNAL_ERROR; |
Gregory Maxwell | e03af44 | 2011-09-04 04:43:11 -0400 | [diff] [blame] | 113 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 114 | silkDecSizeBytes = align(silkDecSizeBytes); |
| 115 | st->silk_dec_offset = align(sizeof(OpusDecoder)); |
| 116 | st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes; |
| 117 | silk_dec = (char*)st+st->silk_dec_offset; |
| 118 | celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); |
| 119 | st->stream_channels = st->channels = channels; |
Jean-Marc Valin | 2e8a55c | 2010-08-31 11:31:54 -0400 | [diff] [blame] | 120 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 121 | st->Fs = Fs; |
Jean-Marc Valin | 0c5085a | 2011-10-04 01:10:32 -0400 | [diff] [blame] | 122 | st->DecControl.API_sampleRate = st->Fs; |
| 123 | st->DecControl.nChannelsAPI = st->channels; |
Aurélien Zanelli | cd4c824 | 2013-05-31 15:07:00 +0200 | [diff] [blame] | 124 | st->arch = opus_select_arch(); |
Jean-Marc Valin | 62dda62 | 2010-07-05 11:35:40 -0400 | [diff] [blame] | 125 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 126 | /* Reset decoder */ |
| 127 | ret = silk_InitDecoder( silk_dec ); |
Gregory Maxwell | e03af44 | 2011-09-04 04:43:11 -0400 | [diff] [blame] | 128 | if(ret)return OPUS_INTERNAL_ERROR; |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 129 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 130 | /* Initialize CELT decoder */ |
| 131 | ret = celt_decoder_init(celt_dec, Fs, channels); |
Gregory Maxwell | e03af44 | 2011-09-04 04:43:11 -0400 | [diff] [blame] | 132 | if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR; |
| 133 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 134 | celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0)); |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 135 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 136 | st->prev_mode = 0; |
| 137 | st->frame_size = Fs/400; |
| 138 | return OPUS_OK; |
Jean-Marc Valin | 280c060 | 2011-05-05 20:47:42 -0400 | [diff] [blame] | 139 | } |
| 140 | |
Gregory Maxwell | 64a3541 | 2011-09-02 10:31:17 -0400 | [diff] [blame] | 141 | OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error) |
Jean-Marc Valin | 280c060 | 2011-05-05 20:47:42 -0400 | [diff] [blame] | 142 | { |
Jean-Marc Valin | 9d8dc3a | 2011-08-29 09:40:57 -0400 | [diff] [blame] | 143 | int ret; |
Gregory Maxwell | e98f1f5 | 2011-10-05 01:59:28 -0400 | [diff] [blame] | 144 | OpusDecoder *st; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 145 | if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) |
| 146 | || (channels!=1&&channels!=2)) |
Gregory Maxwell | 220a7d4 | 2011-10-01 20:30:16 -0400 | [diff] [blame] | 147 | { |
| 148 | if (error) |
| 149 | *error = OPUS_BAD_ARG; |
| 150 | return NULL; |
| 151 | } |
Gregory Maxwell | e98f1f5 | 2011-10-05 01:59:28 -0400 | [diff] [blame] | 152 | st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels)); |
Jean-Marc Valin | 85b8e62 | 2011-08-29 16:10:08 -0400 | [diff] [blame] | 153 | if (st == NULL) |
Jean-Marc Valin | 9d8dc3a | 2011-08-29 09:40:57 -0400 | [diff] [blame] | 154 | { |
| 155 | if (error) |
| 156 | *error = OPUS_ALLOC_FAIL; |
| 157 | return NULL; |
| 158 | } |
Jean-Marc Valin | 85b8e62 | 2011-08-29 16:10:08 -0400 | [diff] [blame] | 159 | ret = opus_decoder_init(st, Fs, channels); |
Gregory Maxwell | a40721a | 2011-09-04 04:25:12 -0400 | [diff] [blame] | 160 | if (error) |
| 161 | *error = ret; |
Jean-Marc Valin | 9d8dc3a | 2011-08-29 09:40:57 -0400 | [diff] [blame] | 162 | if (ret != OPUS_OK) |
| 163 | { |
Jean-Marc Valin | 85b8e62 | 2011-08-29 16:10:08 -0400 | [diff] [blame] | 164 | opus_free(st); |
| 165 | st = NULL; |
Jean-Marc Valin | 9d8dc3a | 2011-08-29 09:40:57 -0400 | [diff] [blame] | 166 | } |
Jean-Marc Valin | 85b8e62 | 2011-08-29 16:10:08 -0400 | [diff] [blame] | 167 | return st; |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 168 | } |
Koen Vos | 8f67b20 | 2011-02-03 09:31:12 -0500 | [diff] [blame] | 169 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 170 | static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, |
| 171 | opus_val16 *out, int overlap, int channels, |
| 172 | const opus_val16 *window, opus_int32 Fs) |
Jean-Marc Valin | 0c0c5f9 | 2011-03-07 20:54:33 -0500 | [diff] [blame] | 173 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 174 | int i, c; |
| 175 | int inc = 48000/Fs; |
| 176 | for (c=0;c<channels;c++) |
| 177 | { |
| 178 | for (i=0;i<overlap;i++) |
| 179 | { |
| 180 | opus_val16 w = MULT16_16_Q15(window[i*inc], window[i*inc]); |
| 181 | out[i*channels+c] = SHR32(MAC16_16(MULT16_16(w,in2[i*channels+c]), |
| 182 | Q15ONE-w, in1[i*channels+c]), 15); |
| 183 | } |
| 184 | } |
Jean-Marc Valin | 0c0c5f9 | 2011-03-07 20:54:33 -0500 | [diff] [blame] | 185 | } |
| 186 | |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 187 | static int opus_packet_get_mode(const unsigned char *data) |
| 188 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 189 | int mode; |
| 190 | if (data[0]&0x80) |
| 191 | { |
| 192 | mode = MODE_CELT_ONLY; |
| 193 | } else if ((data[0]&0x60) == 0x60) |
| 194 | { |
| 195 | mode = MODE_HYBRID; |
| 196 | } else { |
| 197 | mode = MODE_SILK_ONLY; |
| 198 | } |
| 199 | return mode; |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 200 | } |
| 201 | |
Jean-Marc Valin | a7d31b7 | 2011-03-13 20:41:52 -0400 | [diff] [blame] | 202 | static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 203 | opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 204 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 205 | void *silk_dec; |
| 206 | CELTDecoder *celt_dec; |
| 207 | int i, silk_ret=0, celt_ret=0; |
| 208 | ec_dec dec; |
| 209 | opus_int32 silk_frame_size; |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 210 | int pcm_silk_size; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 211 | VARDECL(opus_int16, pcm_silk); |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 212 | int pcm_transition_silk_size; |
| 213 | VARDECL(opus_val16, pcm_transition_silk); |
| 214 | int pcm_transition_celt_size; |
| 215 | VARDECL(opus_val16, pcm_transition_celt); |
| 216 | opus_val16 *pcm_transition; |
| 217 | int redundant_audio_size; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 218 | VARDECL(opus_val16, redundant_audio); |
Jean-Marc Valin | a0653ed | 2011-07-05 13:18:59 -0400 | [diff] [blame] | 219 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 220 | int audiosize; |
| 221 | int mode; |
| 222 | int transition=0; |
| 223 | int start_band; |
| 224 | int redundancy=0; |
| 225 | int redundancy_bytes = 0; |
| 226 | int celt_to_silk=0; |
| 227 | int c; |
| 228 | int F2_5, F5, F10, F20; |
| 229 | const opus_val16 *window; |
| 230 | opus_uint32 redundant_rng = 0; |
| 231 | ALLOC_STACK; |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 232 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 233 | silk_dec = (char*)st+st->silk_dec_offset; |
| 234 | celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); |
| 235 | F20 = st->Fs/50; |
| 236 | F10 = F20>>1; |
| 237 | F5 = F10>>1; |
| 238 | F2_5 = F5>>1; |
| 239 | if (frame_size < F2_5) |
Jean-Marc Valin | c792108 | 2012-03-05 19:56:13 -0500 | [diff] [blame] | 240 | { |
| 241 | RESTORE_STACK; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 242 | return OPUS_BUFFER_TOO_SMALL; |
Jean-Marc Valin | c792108 | 2012-03-05 19:56:13 -0500 | [diff] [blame] | 243 | } |
Timothy B. Terriberry | a40689e | 2012-09-07 06:01:53 -0700 | [diff] [blame] | 244 | /* Limit frame_size to avoid excessive stack allocations. */ |
| 245 | frame_size = IMIN(frame_size, st->Fs/25*3); |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 246 | /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ |
| 247 | if (len<=1) |
| 248 | { |
| 249 | data = NULL; |
| 250 | /* In that case, don't conceal more than what the ToC says */ |
| 251 | frame_size = IMIN(frame_size, st->frame_size); |
| 252 | } |
| 253 | if (data != NULL) |
| 254 | { |
| 255 | audiosize = st->frame_size; |
| 256 | mode = st->mode; |
| 257 | ec_dec_init(&dec,(unsigned char*)data,len); |
| 258 | } else { |
| 259 | audiosize = frame_size; |
Jean-Marc Valin | 8fe8b8e | 2011-08-18 15:00:59 -0400 | [diff] [blame] | 260 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 261 | if (st->prev_mode == 0) |
| 262 | { |
| 263 | /* If we haven't got any packet yet, all we can do is return zeros */ |
| 264 | for (i=0;i<audiosize*st->channels;i++) |
| 265 | pcm[i] = 0; |
| 266 | RESTORE_STACK; |
| 267 | return audiosize; |
| 268 | } else { |
| 269 | mode = st->prev_mode; |
| 270 | } |
| 271 | } |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 272 | |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 273 | /* For CELT/hybrid PLC of more than 20 ms, opus_decode_native() will do |
| 274 | multiple calls */ |
| 275 | if (data==NULL && mode != MODE_SILK_ONLY) |
| 276 | frame_size = IMIN(frame_size, F20); |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 277 | |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 278 | pcm_transition_silk_size = 0; |
| 279 | pcm_transition_celt_size = 0; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 280 | if (data!=NULL && st->prev_mode > 0 && ( |
| 281 | (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) |
| 282 | || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) |
| 283 | ) |
| 284 | { |
| 285 | transition = 1; |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 286 | /* Decide where to allocate the stack memory for pcm_transition */ |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 287 | if (mode == MODE_CELT_ONLY) |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 288 | pcm_transition_celt_size = F5*st->channels; |
| 289 | else |
| 290 | pcm_transition_silk_size = F5*st->channels; |
| 291 | } |
| 292 | ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16); |
| 293 | if (transition && mode == MODE_CELT_ONLY) |
| 294 | { |
| 295 | pcm_transition = pcm_transition_celt; |
| 296 | opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 297 | } |
| 298 | if (audiosize > frame_size) |
| 299 | { |
| 300 | /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ |
| 301 | RESTORE_STACK; |
| 302 | return OPUS_BAD_ARG; |
| 303 | } else { |
| 304 | frame_size = audiosize; |
| 305 | } |
Jean-Marc Valin | 53fb0f7 | 2011-01-31 15:56:38 -0500 | [diff] [blame] | 306 | |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 307 | /* Don't allocate any memory when in CELT-only mode */ |
| 308 | pcm_silk_size = (mode != MODE_CELT_ONLY) ? IMAX(F10, frame_size)*st->channels : 0; |
| 309 | ALLOC(pcm_silk, pcm_silk_size, opus_int16); |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 310 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 311 | /* SILK processing */ |
| 312 | if (mode != MODE_CELT_ONLY) |
| 313 | { |
| 314 | int lost_flag, decoded_samples; |
| 315 | opus_int16 *pcm_ptr = pcm_silk; |
Jean-Marc Valin | 606250a | 2011-02-15 14:31:21 -0500 | [diff] [blame] | 316 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 317 | if (st->prev_mode==MODE_CELT_ONLY) |
| 318 | silk_InitDecoder( silk_dec ); |
Jean-Marc Valin | 606250a | 2011-02-15 14:31:21 -0500 | [diff] [blame] | 319 | |
Jean-Marc Valin | 7227300 | 2012-04-20 10:26:08 -0400 | [diff] [blame] | 320 | /* The SILK PLC cannot produce frames of less than 10 ms */ |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 321 | st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); |
Jean-Marc Valin | 0c5085a | 2011-10-04 01:10:32 -0400 | [diff] [blame] | 322 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 323 | if (data != NULL) |
| 324 | { |
| 325 | st->DecControl.nChannelsInternal = st->stream_channels; |
| 326 | if( mode == MODE_SILK_ONLY ) { |
| 327 | if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { |
| 328 | st->DecControl.internalSampleRate = 8000; |
| 329 | } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { |
| 330 | st->DecControl.internalSampleRate = 12000; |
| 331 | } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { |
| 332 | st->DecControl.internalSampleRate = 16000; |
| 333 | } else { |
| 334 | st->DecControl.internalSampleRate = 16000; |
| 335 | silk_assert( 0 ); |
| 336 | } |
| 337 | } else { |
| 338 | /* Hybrid mode */ |
| 339 | st->DecControl.internalSampleRate = 16000; |
Jean-Marc Valin | b5be826 | 2010-11-12 06:47:46 +0800 | [diff] [blame] | 340 | } |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 341 | } |
Jean-Marc Valin | 67008d2 | 2010-07-20 11:13:30 -0400 | [diff] [blame] | 342 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 343 | lost_flag = data == NULL ? 1 : 2 * decode_fec; |
| 344 | decoded_samples = 0; |
| 345 | do { |
| 346 | /* Call SILK decoder */ |
| 347 | int first_frame = decoded_samples == 0; |
| 348 | silk_ret = silk_Decode( silk_dec, &st->DecControl, |
| 349 | lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size ); |
| 350 | if( silk_ret ) { |
| 351 | if (lost_flag) { |
| 352 | /* PLC failure should not be fatal */ |
| 353 | silk_frame_size = frame_size; |
| 354 | for (i=0;i<frame_size*st->channels;i++) |
| 355 | pcm_ptr[i] = 0; |
| 356 | } else { |
| 357 | RESTORE_STACK; |
| 358 | return OPUS_INVALID_PACKET; |
| 359 | } |
Jean-Marc Valin | 0c0c5f9 | 2011-03-07 20:54:33 -0500 | [diff] [blame] | 360 | } |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 361 | pcm_ptr += silk_frame_size * st->channels; |
| 362 | decoded_samples += silk_frame_size; |
| 363 | } while( decoded_samples < frame_size ); |
| 364 | } |
Jean-Marc Valin | 0c0c5f9 | 2011-03-07 20:54:33 -0500 | [diff] [blame] | 365 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 366 | start_band = 0; |
| 367 | if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL |
| 368 | && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) |
| 369 | { |
| 370 | /* Check if we have a redundant 0-8 kHz band */ |
| 371 | if (mode == MODE_HYBRID) |
| 372 | redundancy = ec_dec_bit_logp(&dec, 12); |
| 373 | else |
| 374 | redundancy = 1; |
| 375 | if (redundancy) |
| 376 | { |
| 377 | celt_to_silk = ec_dec_bit_logp(&dec, 1); |
| 378 | /* redundancy_bytes will be at least two, in the non-hybrid |
| 379 | case due to the ec_tell() check above */ |
| 380 | redundancy_bytes = mode==MODE_HYBRID ? |
| 381 | (opus_int32)ec_dec_uint(&dec, 256)+2 : |
| 382 | len-((ec_tell(&dec)+7)>>3); |
| 383 | len -= redundancy_bytes; |
| 384 | /* This is a sanity check. It should never happen for a valid |
| 385 | packet, so the exact behaviour is not normative. */ |
| 386 | if (len*8 < ec_tell(&dec)) |
| 387 | { |
| 388 | len = 0; |
| 389 | redundancy_bytes = 0; |
| 390 | redundancy = 0; |
| 391 | } |
| 392 | /* Shrink decoder because of raw bits */ |
| 393 | dec.storage -= redundancy_bytes; |
| 394 | } |
| 395 | } |
| 396 | if (mode != MODE_CELT_ONLY) |
| 397 | start_band = 17; |
Jean-Marc Valin | 0c0c5f9 | 2011-03-07 20:54:33 -0500 | [diff] [blame] | 398 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 399 | { |
| 400 | int endband=21; |
Jean-Marc Valin | 0c0c5f9 | 2011-03-07 20:54:33 -0500 | [diff] [blame] | 401 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 402 | switch(st->bandwidth) |
| 403 | { |
| 404 | case OPUS_BANDWIDTH_NARROWBAND: |
| 405 | endband = 13; |
| 406 | break; |
| 407 | case OPUS_BANDWIDTH_MEDIUMBAND: |
| 408 | case OPUS_BANDWIDTH_WIDEBAND: |
| 409 | endband = 17; |
| 410 | break; |
| 411 | case OPUS_BANDWIDTH_SUPERWIDEBAND: |
| 412 | endband = 19; |
| 413 | break; |
| 414 | case OPUS_BANDWIDTH_FULLBAND: |
| 415 | endband = 21; |
| 416 | break; |
| 417 | } |
| 418 | celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband)); |
| 419 | celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels)); |
| 420 | } |
Jean-Marc Valin | e2a09db | 2011-03-02 17:54:43 -0500 | [diff] [blame] | 421 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 422 | if (redundancy) |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 423 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 424 | transition = 0; |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 425 | pcm_transition_silk_size=0; |
| 426 | } |
| 427 | |
| 428 | ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16); |
Jean-Marc Valin | 0c0c5f9 | 2011-03-07 20:54:33 -0500 | [diff] [blame] | 429 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 430 | if (transition && mode != MODE_CELT_ONLY) |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 431 | { |
| 432 | pcm_transition = pcm_transition_silk; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 433 | opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); |
Jean-Marc Valin | cc83f6b | 2012-11-05 10:25:20 -0500 | [diff] [blame] | 434 | } |
| 435 | |
| 436 | /* Only allocation memory for redundancy if/when needed */ |
| 437 | redundant_audio_size = redundancy ? F5*st->channels : 0; |
| 438 | ALLOC(redundant_audio, redundant_audio_size, opus_val16); |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 439 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 440 | /* 5 ms redundant frame for CELT->SILK*/ |
| 441 | if (redundancy && celt_to_silk) |
| 442 | { |
| 443 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
| 444 | celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, |
| 445 | redundant_audio, F5, NULL); |
| 446 | celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); |
| 447 | } |
Jean-Marc Valin | a93f501 | 2011-03-03 15:50:08 -0500 | [diff] [blame] | 448 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 449 | /* MUST be after PLC */ |
| 450 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band)); |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 451 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 452 | if (mode != MODE_SILK_ONLY) |
| 453 | { |
| 454 | int celt_frame_size = IMIN(F20, frame_size); |
| 455 | /* Make sure to discard any previous CELT state */ |
| 456 | if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) |
| 457 | celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); |
| 458 | /* Decode CELT */ |
| 459 | celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, |
| 460 | len, pcm, celt_frame_size, &dec); |
| 461 | } else { |
| 462 | unsigned char silence[2] = {0xFF, 0xFF}; |
| 463 | for (i=0;i<frame_size*st->channels;i++) |
| 464 | pcm[i] = 0; |
| 465 | /* For hybrid -> SILK transitions, we let the CELT MDCT |
| 466 | do a fade-out by decoding a silence frame */ |
Jean-Marc Valin | 17c5966 | 2012-02-17 16:09:21 -0500 | [diff] [blame] | 467 | if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 468 | { |
| 469 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
| 470 | celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL); |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | if (mode != MODE_CELT_ONLY) |
| 475 | { |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 476 | #ifdef FIXED_POINT |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 477 | for (i=0;i<frame_size*st->channels;i++) |
| 478 | pcm[i] = SAT16(pcm[i] + pcm_silk[i]); |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 479 | #else |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 480 | for (i=0;i<frame_size*st->channels;i++) |
Gregory Maxwell | 37f5659 | 2012-07-17 17:40:55 -0400 | [diff] [blame] | 481 | pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 482 | #endif |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 483 | } |
Koen Vos | 8f67b20 | 2011-02-03 09:31:12 -0500 | [diff] [blame] | 484 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 485 | { |
| 486 | const CELTMode *celt_mode; |
| 487 | celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode)); |
| 488 | window = celt_mode->window; |
| 489 | } |
Koen Vos | d8765e5 | 2011-04-26 23:21:27 -0400 | [diff] [blame] | 490 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 491 | /* 5 ms redundant frame for SILK->CELT */ |
| 492 | if (redundancy && !celt_to_silk) |
| 493 | { |
| 494 | celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); |
| 495 | celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); |
Jean-Marc Valin | 0c0c5f9 | 2011-03-07 20:54:33 -0500 | [diff] [blame] | 496 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 497 | celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL); |
| 498 | celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); |
| 499 | smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, |
| 500 | pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); |
| 501 | } |
| 502 | if (redundancy && celt_to_silk) |
| 503 | { |
| 504 | for (c=0;c<st->channels;c++) |
| 505 | { |
| 506 | for (i=0;i<F2_5;i++) |
| 507 | pcm[st->channels*i+c] = redundant_audio[st->channels*i+c]; |
| 508 | } |
| 509 | smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, |
| 510 | pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); |
| 511 | } |
| 512 | if (transition) |
| 513 | { |
| 514 | if (audiosize >= F5) |
| 515 | { |
| 516 | for (i=0;i<st->channels*F2_5;i++) |
| 517 | pcm[i] = pcm_transition[i]; |
| 518 | smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, |
| 519 | pcm+st->channels*F2_5, F2_5, |
| 520 | st->channels, window, st->Fs); |
| 521 | } else { |
| 522 | /* Not enough time to do a clean transition, but we do it anyway |
| 523 | This will not preserve amplitude perfectly and may introduce |
| 524 | a bit of temporal aliasing, but it shouldn't be too bad and |
| 525 | that's pretty much the best we can do. In any case, generating this |
| 526 | transition it pretty silly in the first place */ |
| 527 | smooth_fade(pcm_transition, pcm, |
| 528 | pcm, F2_5, |
| 529 | st->channels, window, st->Fs); |
| 530 | } |
| 531 | } |
Ralph Giles | 3f0962c | 2011-07-29 14:01:54 -0700 | [diff] [blame] | 532 | |
Gregory Maxwell | 28b41ae | 2012-07-11 00:04:24 -0400 | [diff] [blame] | 533 | if(st->decode_gain) |
| 534 | { |
| 535 | opus_val32 gain; |
| 536 | gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); |
| 537 | for (i=0;i<frame_size*st->channels;i++) |
| 538 | { |
| 539 | opus_val32 x; |
| 540 | x = MULT16_32_P16(pcm[i],gain); |
| 541 | pcm[i] = SATURATE(x, 32767); |
| 542 | } |
| 543 | } |
| 544 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 545 | if (len <= 1) |
| 546 | st->rangeFinal = 0; |
| 547 | else |
| 548 | st->rangeFinal = dec.rng ^ redundant_rng; |
Koen Vos | 8f67b20 | 2011-02-03 09:31:12 -0500 | [diff] [blame] | 549 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 550 | st->prev_mode = mode; |
| 551 | st->prev_redundancy = redundancy && !celt_to_silk; |
Jean-Marc Valin | 9283114 | 2012-12-05 00:50:53 -0500 | [diff] [blame] | 552 | |
| 553 | if (celt_ret>=0) |
| 554 | { |
| 555 | if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels)) |
| 556 | OPUS_PRINT_INT(audiosize); |
| 557 | } |
| 558 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 559 | RESTORE_STACK; |
| 560 | return celt_ret < 0 ? celt_ret : audiosize; |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 561 | |
| 562 | } |
| 563 | |
Jean-Marc Valin | 3593069 | 2013-05-18 02:50:40 -0400 | [diff] [blame] | 564 | static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size) |
Jean-Marc Valin | a7d31b7 | 2011-03-13 20:41:52 -0400 | [diff] [blame] | 565 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 566 | if (len<1) |
| 567 | { |
| 568 | *size = -1; |
| 569 | return -1; |
| 570 | } else if (data[0]<252) |
| 571 | { |
| 572 | *size = data[0]; |
| 573 | return 1; |
| 574 | } else if (len<2) |
| 575 | { |
| 576 | *size = -1; |
| 577 | return -1; |
| 578 | } else { |
| 579 | *size = 4*data[1] + data[0]; |
| 580 | return 2; |
| 581 | } |
Jean-Marc Valin | a7d31b7 | 2011-03-13 20:41:52 -0400 | [diff] [blame] | 582 | } |
| 583 | |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 584 | static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 585 | int self_delimited, unsigned char *out_toc, |
Jean-Marc Valin | 3593069 | 2013-05-18 02:50:40 -0400 | [diff] [blame] | 586 | const unsigned char *frames[48], opus_int16 size[48], int *payload_offset) |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 587 | { |
| 588 | int i, bytes; |
| 589 | int count; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 590 | int cbr; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 591 | unsigned char ch, toc; |
| 592 | int framesize; |
Jean-Marc Valin | 259e166 | 2012-12-03 13:05:24 -0500 | [diff] [blame] | 593 | opus_int32 last_size; |
Jean-Marc Valin | 6bb1c18 | 2011-08-18 15:54:00 -0400 | [diff] [blame] | 594 | const unsigned char *data0 = data; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 595 | |
| 596 | if (size==NULL) |
| 597 | return OPUS_BAD_ARG; |
| 598 | |
| 599 | framesize = opus_packet_get_samples_per_frame(data, 48000); |
| 600 | |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 601 | cbr = 0; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 602 | toc = *data++; |
| 603 | len--; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 604 | last_size = len; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 605 | switch (toc&0x3) |
| 606 | { |
| 607 | /* One frame */ |
| 608 | case 0: |
| 609 | count=1; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 610 | break; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 611 | /* Two CBR frames */ |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 612 | case 1: |
| 613 | count=2; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 614 | cbr = 1; |
| 615 | if (!self_delimited) |
| 616 | { |
| 617 | if (len&0x1) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 618 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 259e166 | 2012-12-03 13:05:24 -0500 | [diff] [blame] | 619 | last_size = len/2; |
| 620 | /* If last_size doesn't fit in size[0], we'll catch it later */ |
Jean-Marc Valin | 3593069 | 2013-05-18 02:50:40 -0400 | [diff] [blame] | 621 | size[0] = (opus_int16)last_size; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 622 | } |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 623 | break; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 624 | /* Two VBR frames */ |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 625 | case 2: |
| 626 | count = 2; |
| 627 | bytes = parse_size(data, len, size); |
| 628 | len -= bytes; |
| 629 | if (size[0]<0 || size[0] > len) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 630 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 631 | data += bytes; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 632 | last_size = len-size[0]; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 633 | break; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 634 | /* Multiple CBR/VBR frames (from 0 to 120 ms) */ |
Jean-Marc Valin | 7227300 | 2012-04-20 10:26:08 -0400 | [diff] [blame] | 635 | default: /*case 3:*/ |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 636 | if (len<1) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 637 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 638 | /* Number of frames encoded in bits 0 to 5 */ |
| 639 | ch = *data++; |
| 640 | count = ch&0x3F; |
| 641 | if (count <= 0 || framesize*count > 5760) |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 642 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 643 | len--; |
| 644 | /* Padding flag is bit 6 */ |
| 645 | if (ch&0x40) |
| 646 | { |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 647 | int p; |
| 648 | do { |
| 649 | if (len<=0) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 650 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 651 | p = *data++; |
| 652 | len--; |
Jean-Marc Valin | 9345aaa | 2012-11-30 17:36:36 -0500 | [diff] [blame] | 653 | len -= p==255 ? 254: p; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 654 | } while (p==255); |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 655 | } |
| 656 | if (len<0) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 657 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 658 | /* VBR flag is bit 7 */ |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 659 | cbr = !(ch&0x80); |
Jean-Marc Valin | 823a054 | 2011-09-08 16:26:54 -0400 | [diff] [blame] | 660 | if (!cbr) |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 661 | { |
| 662 | /* VBR case */ |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 663 | last_size = len; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 664 | for (i=0;i<count-1;i++) |
| 665 | { |
| 666 | bytes = parse_size(data, len, size+i); |
| 667 | len -= bytes; |
| 668 | if (size[i]<0 || size[i] > len) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 669 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 670 | data += bytes; |
| 671 | last_size -= bytes+size[i]; |
| 672 | } |
| 673 | if (last_size<0) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 674 | return OPUS_INVALID_PACKET; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 675 | } else if (!self_delimited) |
| 676 | { |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 677 | /* CBR case */ |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 678 | last_size = len/count; |
| 679 | if (last_size*count!=len) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 680 | return OPUS_INVALID_PACKET; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 681 | for (i=0;i<count-1;i++) |
Jean-Marc Valin | 3593069 | 2013-05-18 02:50:40 -0400 | [diff] [blame] | 682 | size[i] = (opus_int16)last_size; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 683 | } |
| 684 | break; |
| 685 | } |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 686 | /* Self-delimited framing has an extra size for the last frame. */ |
| 687 | if (self_delimited) |
| 688 | { |
| 689 | bytes = parse_size(data, len, size+count-1); |
| 690 | len -= bytes; |
| 691 | if (size[count-1]<0 || size[count-1] > len) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 692 | return OPUS_INVALID_PACKET; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 693 | data += bytes; |
| 694 | /* For CBR packets, apply the size to all the frames. */ |
| 695 | if (cbr) |
| 696 | { |
| 697 | if (size[count-1]*count > len) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 698 | return OPUS_INVALID_PACKET; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 699 | for (i=0;i<count-1;i++) |
| 700 | size[i] = size[count-1]; |
| 701 | } else if(size[count-1] > last_size) |
Jean-Marc Valin | 331e9fe | 2011-09-06 14:30:19 -0400 | [diff] [blame] | 702 | return OPUS_INVALID_PACKET; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 703 | } else |
| 704 | { |
| 705 | /* Because it's not encoded explicitly, it's possible the size of the |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 706 | last packet (or all the packets, for the CBR case) is larger than |
| 707 | 1275. Reject them here.*/ |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 708 | if (last_size > 1275) |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 709 | return OPUS_INVALID_PACKET; |
Jean-Marc Valin | 3593069 | 2013-05-18 02:50:40 -0400 | [diff] [blame] | 710 | size[count-1] = (opus_int16)last_size; |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 711 | } |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 712 | |
| 713 | if (frames) |
| 714 | { |
| 715 | for (i=0;i<count;i++) |
| 716 | { |
| 717 | frames[i] = data; |
| 718 | data += size[i]; |
| 719 | } |
| 720 | } |
| 721 | |
| 722 | if (out_toc) |
| 723 | *out_toc = toc; |
| 724 | |
Jean-Marc Valin | 6bb1c18 | 2011-08-18 15:54:00 -0400 | [diff] [blame] | 725 | if (payload_offset) |
Koen Vos | 0b00b31 | 2012-07-12 14:55:49 -0400 | [diff] [blame] | 726 | *payload_offset = (int)(data-data0); |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 727 | |
| 728 | return count; |
| 729 | } |
| 730 | |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 731 | int opus_packet_parse(const unsigned char *data, opus_int32 len, |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 732 | unsigned char *out_toc, const unsigned char *frames[48], |
Jean-Marc Valin | 3593069 | 2013-05-18 02:50:40 -0400 | [diff] [blame] | 733 | opus_int16 size[48], int *payload_offset) |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 734 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 735 | return opus_packet_parse_impl(data, len, 0, out_toc, |
| 736 | frames, size, payload_offset); |
Timothy B. Terriberry | 7954065 | 2011-08-18 23:29:52 -0400 | [diff] [blame] | 737 | } |
| 738 | |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 739 | int opus_decode_native(OpusDecoder *st, const unsigned char *data, |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 740 | opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 741 | int self_delimited, int *packet_offset, int soft_clip) |
Jean-Marc Valin | a7d31b7 | 2011-03-13 20:41:52 -0400 | [diff] [blame] | 742 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 743 | int i, nb_samples; |
| 744 | int count, offset; |
| 745 | unsigned char toc; |
| 746 | int tot_offset; |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 747 | int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 748 | /* 48 x 2.5 ms = 120 ms */ |
Jean-Marc Valin | 3593069 | 2013-05-18 02:50:40 -0400 | [diff] [blame] | 749 | opus_int16 size[48]; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 750 | if (decode_fec<0 || decode_fec>1) |
| 751 | return OPUS_BAD_ARG; |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 752 | /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ |
| 753 | if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) |
| 754 | return OPUS_BAD_ARG; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 755 | if (len==0 || data==NULL) |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 756 | { |
| 757 | int pcm_count=0; |
| 758 | do { |
| 759 | int ret; |
Jean-Marc Valin | 9283114 | 2012-12-05 00:50:53 -0500 | [diff] [blame] | 760 | ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0); |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 761 | if (ret<0) |
| 762 | return ret; |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 763 | pcm_count += ret; |
| 764 | } while (pcm_count < frame_size); |
Jean-Marc Valin | 9283114 | 2012-12-05 00:50:53 -0500 | [diff] [blame] | 765 | celt_assert(pcm_count == frame_size); |
| 766 | if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels)) |
| 767 | OPUS_PRINT_INT(pcm_count); |
Jean-Marc Valin | a0737d1 | 2012-12-05 21:48:45 -0500 | [diff] [blame] | 768 | st->last_packet_duration = pcm_count; |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 769 | return pcm_count; |
| 770 | } else if (len<0) |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 771 | return OPUS_BAD_ARG; |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 772 | |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 773 | packet_mode = opus_packet_get_mode(data); |
| 774 | packet_bandwidth = opus_packet_get_bandwidth(data); |
| 775 | packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); |
| 776 | packet_stream_channels = opus_packet_get_nb_channels(data); |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 777 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 778 | count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset); |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 779 | |
| 780 | data += offset; |
| 781 | |
| 782 | if (decode_fec) |
| 783 | { |
Jean-Marc Valin | a0737d1 | 2012-12-05 21:48:45 -0500 | [diff] [blame] | 784 | int duration_copy; |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 785 | int ret; |
| 786 | /* If no FEC can be present, run the PLC (recursive call) */ |
Jean-Marc Valin | 1bf32bb | 2013-04-23 02:41:28 -0400 | [diff] [blame] | 787 | if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 788 | return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip); |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 789 | /* Otherwise, run the PLC on everything except the size for which we might have FEC */ |
Jean-Marc Valin | a0737d1 | 2012-12-05 21:48:45 -0500 | [diff] [blame] | 790 | duration_copy = st->last_packet_duration; |
Jean-Marc Valin | 1bf32bb | 2013-04-23 02:41:28 -0400 | [diff] [blame] | 791 | if (frame_size-packet_frame_size!=0) |
Jean-Marc Valin | a0737d1 | 2012-12-05 21:48:45 -0500 | [diff] [blame] | 792 | { |
Jean-Marc Valin | 1bf32bb | 2013-04-23 02:41:28 -0400 | [diff] [blame] | 793 | ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip); |
| 794 | if (ret<0) |
| 795 | { |
| 796 | st->last_packet_duration = duration_copy; |
| 797 | return ret; |
| 798 | } |
| 799 | celt_assert(ret==frame_size-packet_frame_size); |
Jean-Marc Valin | a0737d1 | 2012-12-05 21:48:45 -0500 | [diff] [blame] | 800 | } |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 801 | /* Complete with FEC */ |
| 802 | st->mode = packet_mode; |
| 803 | st->bandwidth = packet_bandwidth; |
| 804 | st->frame_size = packet_frame_size; |
| 805 | st->stream_channels = packet_stream_channels; |
| 806 | ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), |
| 807 | packet_frame_size, 1); |
| 808 | if (ret<0) |
| 809 | return ret; |
Jean-Marc Valin | 9283114 | 2012-12-05 00:50:53 -0500 | [diff] [blame] | 810 | else { |
| 811 | if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels)) |
| 812 | OPUS_PRINT_INT(frame_size); |
Jean-Marc Valin | a0737d1 | 2012-12-05 21:48:45 -0500 | [diff] [blame] | 813 | st->last_packet_duration = frame_size; |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 814 | return frame_size; |
Jean-Marc Valin | 9283114 | 2012-12-05 00:50:53 -0500 | [diff] [blame] | 815 | } |
Jean-Marc Valin | 7fcd66c | 2012-12-04 15:07:45 -0500 | [diff] [blame] | 816 | } |
| 817 | tot_offset = 0; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 818 | if (count < 0) |
| 819 | return count; |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 820 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 821 | tot_offset += offset; |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 822 | |
Jean-Marc Valin | a5bd440 | 2012-12-04 14:13:00 -0500 | [diff] [blame] | 823 | if (count*packet_frame_size > frame_size) |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 824 | return OPUS_BUFFER_TOO_SMALL; |
Jean-Marc Valin | a5bd440 | 2012-12-04 14:13:00 -0500 | [diff] [blame] | 825 | |
| 826 | /* Update the state as the last step to avoid updating it on an invalid packet */ |
| 827 | st->mode = packet_mode; |
| 828 | st->bandwidth = packet_bandwidth; |
| 829 | st->frame_size = packet_frame_size; |
| 830 | st->stream_channels = packet_stream_channels; |
| 831 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 832 | nb_samples=0; |
| 833 | for (i=0;i<count;i++) |
| 834 | { |
| 835 | int ret; |
Jean-Marc Valin | 9283114 | 2012-12-05 00:50:53 -0500 | [diff] [blame] | 836 | ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0); |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 837 | if (ret<0) |
| 838 | return ret; |
Jean-Marc Valin | 9283114 | 2012-12-05 00:50:53 -0500 | [diff] [blame] | 839 | celt_assert(ret==packet_frame_size); |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 840 | data += size[i]; |
| 841 | tot_offset += size[i]; |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 842 | nb_samples += ret; |
| 843 | } |
| 844 | if (packet_offset != NULL) |
| 845 | *packet_offset = tot_offset; |
Jean-Marc Valin | 512d849 | 2012-12-04 14:13:46 -0500 | [diff] [blame] | 846 | st->last_packet_duration = nb_samples; |
Jean-Marc Valin | 9283114 | 2012-12-05 00:50:53 -0500 | [diff] [blame] | 847 | if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels)) |
| 848 | OPUS_PRINT_INT(nb_samples); |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 849 | #ifndef FIXED_POINT |
| 850 | if (soft_clip) |
| 851 | opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem); |
| 852 | else |
| 853 | st->softclip_mem[0]=st->softclip_mem[1]=0; |
| 854 | #endif |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 855 | return nb_samples; |
Jean-Marc Valin | a7d31b7 | 2011-03-13 20:41:52 -0400 | [diff] [blame] | 856 | } |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 857 | |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 858 | #ifdef FIXED_POINT |
| 859 | |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 860 | int opus_decode(OpusDecoder *st, const unsigned char *data, |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 861 | opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 862 | { |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 863 | return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 864 | } |
| 865 | |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 866 | #ifndef DISABLE_FLOAT_API |
| 867 | int opus_decode_float(OpusDecoder *st, const unsigned char *data, |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 868 | opus_int32 len, float *pcm, int frame_size, int decode_fec) |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 869 | { |
| 870 | VARDECL(opus_int16, out); |
| 871 | int ret, i; |
| 872 | ALLOC_STACK; |
| 873 | |
| 874 | ALLOC(out, frame_size*st->channels, opus_int16); |
| 875 | |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 876 | ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 877 | if (ret > 0) |
| 878 | { |
| 879 | for (i=0;i<ret*st->channels;i++) |
Jean-Marc Valin | 294bfec | 2011-10-20 00:39:41 -0400 | [diff] [blame] | 880 | pcm[i] = (1.f/32768.f)*(out[i]); |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 881 | } |
| 882 | RESTORE_STACK; |
| 883 | return ret; |
| 884 | } |
| 885 | #endif |
| 886 | |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 887 | |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 888 | #else |
| 889 | int opus_decode(OpusDecoder *st, const unsigned char *data, |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 890 | opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 891 | { |
| 892 | VARDECL(float, out); |
| 893 | int ret, i; |
| 894 | ALLOC_STACK; |
| 895 | |
Jean-Marc Valin | c792108 | 2012-03-05 19:56:13 -0500 | [diff] [blame] | 896 | if(frame_size<0) |
| 897 | { |
| 898 | RESTORE_STACK; |
| 899 | return OPUS_BAD_ARG; |
| 900 | } |
Gregory Maxwell | e699c19 | 2011-11-25 23:53:15 -0500 | [diff] [blame] | 901 | |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 902 | ALLOC(out, frame_size*st->channels, float); |
| 903 | |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 904 | ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 905 | if (ret > 0) |
| 906 | { |
| 907 | for (i=0;i<ret*st->channels;i++) |
| 908 | pcm[i] = FLOAT2INT16(out[i]); |
| 909 | } |
| 910 | RESTORE_STACK; |
| 911 | return ret; |
| 912 | } |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 913 | |
| 914 | int opus_decode_float(OpusDecoder *st, const unsigned char *data, |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 915 | opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 916 | { |
Jean-Marc Valin | 32c4a0c | 2013-03-01 15:18:23 -0500 | [diff] [blame] | 917 | return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); |
Jean-Marc Valin | d4e9340 | 2011-08-27 00:52:26 -0400 | [diff] [blame] | 918 | } |
| 919 | |
Jean-Marc Valin | 222494f | 2011-08-17 15:53:37 -0400 | [diff] [blame] | 920 | #endif |
Jean-Marc Valin | 4154dad | 2011-08-08 11:57:13 -0400 | [diff] [blame] | 921 | |
Jean-Marc Valin | 955f94c | 2011-03-08 22:12:43 -0500 | [diff] [blame] | 922 | int opus_decoder_ctl(OpusDecoder *st, int request, ...) |
Jean-Marc Valin | 24f36e0 | 2010-07-06 14:41:20 -0400 | [diff] [blame] | 923 | { |
Jean-Marc Valin | be89c39 | 2011-08-30 12:39:51 -0400 | [diff] [blame] | 924 | int ret = OPUS_OK; |
| 925 | va_list ap; |
Jean-Marc Valin | 25f7f35 | 2011-09-14 09:50:06 -0700 | [diff] [blame] | 926 | void *silk_dec; |
| 927 | CELTDecoder *celt_dec; |
| 928 | |
| 929 | silk_dec = (char*)st+st->silk_dec_offset; |
| 930 | celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); |
| 931 | |
Jean-Marc Valin | 24f36e0 | 2010-07-06 14:41:20 -0400 | [diff] [blame] | 932 | |
Jean-Marc Valin | be89c39 | 2011-08-30 12:39:51 -0400 | [diff] [blame] | 933 | va_start(ap, request); |
Jean-Marc Valin | 24f36e0 | 2010-07-06 14:41:20 -0400 | [diff] [blame] | 934 | |
Jean-Marc Valin | be89c39 | 2011-08-30 12:39:51 -0400 | [diff] [blame] | 935 | switch (request) |
| 936 | { |
| 937 | case OPUS_GET_BANDWIDTH_REQUEST: |
| 938 | { |
| 939 | opus_int32 *value = va_arg(ap, opus_int32*); |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame^] | 940 | if (!value) |
| 941 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 942 | goto bad_arg; |
| 943 | } |
Jean-Marc Valin | be89c39 | 2011-08-30 12:39:51 -0400 | [diff] [blame] | 944 | *value = st->bandwidth; |
| 945 | } |
| 946 | break; |
| 947 | case OPUS_GET_FINAL_RANGE_REQUEST: |
| 948 | { |
| 949 | opus_uint32 *value = va_arg(ap, opus_uint32*); |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame^] | 950 | if (!value) |
| 951 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 952 | goto bad_arg; |
| 953 | } |
Jean-Marc Valin | be89c39 | 2011-08-30 12:39:51 -0400 | [diff] [blame] | 954 | *value = st->rangeFinal; |
| 955 | } |
| 956 | break; |
Jean-Marc Valin | 0446563 | 2011-08-30 18:01:06 -0400 | [diff] [blame] | 957 | case OPUS_RESET_STATE: |
| 958 | { |
Jean-Marc Valin | 0446563 | 2011-08-30 18:01:06 -0400 | [diff] [blame] | 959 | OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START, |
Gregory Maxwell | d32f948 | 2011-09-04 07:48:20 -0400 | [diff] [blame] | 960 | sizeof(OpusDecoder)- |
Jean-Marc Valin | 0446563 | 2011-08-30 18:01:06 -0400 | [diff] [blame] | 961 | ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); |
| 962 | |
Jean-Marc Valin | f9e701a | 2011-08-31 17:47:48 -0400 | [diff] [blame] | 963 | celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); |
Jean-Marc Valin | 0446563 | 2011-08-30 18:01:06 -0400 | [diff] [blame] | 964 | silk_InitDecoder( silk_dec ); |
| 965 | st->stream_channels = st->channels; |
| 966 | st->frame_size = st->Fs/400; |
| 967 | } |
| 968 | break; |
Timothy B. Terriberry | a40689e | 2012-09-07 06:01:53 -0700 | [diff] [blame] | 969 | case OPUS_GET_SAMPLE_RATE_REQUEST: |
| 970 | { |
| 971 | opus_int32 *value = va_arg(ap, opus_int32*); |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame^] | 972 | if (!value) |
| 973 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 974 | goto bad_arg; |
| 975 | } |
Timothy B. Terriberry | a40689e | 2012-09-07 06:01:53 -0700 | [diff] [blame] | 976 | *value = st->Fs; |
| 977 | } |
| 978 | break; |
Jean-Marc Valin | 25f7f35 | 2011-09-14 09:50:06 -0700 | [diff] [blame] | 979 | case OPUS_GET_PITCH_REQUEST: |
| 980 | { |
Jean-Marc Valin | c0387ff | 2012-03-05 19:19:59 -0500 | [diff] [blame] | 981 | opus_int32 *value = va_arg(ap, opus_int32*); |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame^] | 982 | if (!value) |
| 983 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 984 | goto bad_arg; |
| 985 | } |
Jean-Marc Valin | 25f7f35 | 2011-09-14 09:50:06 -0700 | [diff] [blame] | 986 | if (st->prev_mode == MODE_CELT_ONLY) |
| 987 | celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); |
| 988 | else |
Jean-Marc Valin | b24e574 | 2011-10-11 21:09:14 -0400 | [diff] [blame] | 989 | *value = st->DecControl.prevPitchLag; |
Jean-Marc Valin | 25f7f35 | 2011-09-14 09:50:06 -0700 | [diff] [blame] | 990 | } |
| 991 | break; |
Gregory Maxwell | 28b41ae | 2012-07-11 00:04:24 -0400 | [diff] [blame] | 992 | case OPUS_GET_GAIN_REQUEST: |
| 993 | { |
| 994 | opus_int32 *value = va_arg(ap, opus_int32*); |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame^] | 995 | if (!value) |
| 996 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 997 | goto bad_arg; |
| 998 | } |
Gregory Maxwell | 28b41ae | 2012-07-11 00:04:24 -0400 | [diff] [blame] | 999 | *value = st->decode_gain; |
| 1000 | } |
| 1001 | break; |
| 1002 | case OPUS_SET_GAIN_REQUEST: |
| 1003 | { |
| 1004 | opus_int32 value = va_arg(ap, opus_int32); |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame^] | 1005 | if (value<-32768 || value>32767) |
| 1006 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 1007 | goto bad_arg; |
| 1008 | } |
Gregory Maxwell | 28b41ae | 2012-07-11 00:04:24 -0400 | [diff] [blame] | 1009 | st->decode_gain = value; |
| 1010 | } |
| 1011 | break; |
Jean-Marc Valin | 512d849 | 2012-12-04 14:13:46 -0500 | [diff] [blame] | 1012 | case OPUS_GET_LAST_PACKET_DURATION_REQUEST: |
| 1013 | { |
| 1014 | opus_uint32 *value = va_arg(ap, opus_uint32*); |
Gregory Maxwell | a0d096f | 2013-06-29 20:33:32 -0700 | [diff] [blame^] | 1015 | if (!value) |
| 1016 | { |
Gregory Maxwell | b271dae | 2013-06-29 20:25:55 -0700 | [diff] [blame] | 1017 | goto bad_arg; |
| 1018 | } |
Jean-Marc Valin | 512d849 | 2012-12-04 14:13:46 -0500 | [diff] [blame] | 1019 | *value = st->last_packet_duration; |
| 1020 | } |
| 1021 | break; |
Jean-Marc Valin | be89c39 | 2011-08-30 12:39:51 -0400 | [diff] [blame] | 1022 | default: |
| 1023 | /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ |
Jean-Marc Valin | 06237d7 | 2011-09-01 13:20:40 -0400 | [diff] [blame] | 1024 | ret = OPUS_UNIMPLEMENTED; |
Jean-Marc Valin | be89c39 | 2011-08-30 12:39:51 -0400 | [diff] [blame] | 1025 | break; |
| 1026 | } |
Alfred E. Heggestad | 3d31d70 | 2010-07-27 16:38:04 +0200 | [diff] [blame] | 1027 | |
Jean-Marc Valin | be89c39 | 2011-08-30 12:39:51 -0400 | [diff] [blame] | 1028 | va_end(ap); |
| 1029 | return ret; |
Gregory Maxwell | dd7b0da | 2013-06-29 20:06:07 -0700 | [diff] [blame] | 1030 | bad_arg: |
| 1031 | va_end(ap); |
| 1032 | return OPUS_BAD_ARG; |
Jean-Marc Valin | 24f36e0 | 2010-07-06 14:41:20 -0400 | [diff] [blame] | 1033 | } |
| 1034 | |
Jean-Marc Valin | 05dd36a | 2010-10-18 12:50:49 -0400 | [diff] [blame] | 1035 | void opus_decoder_destroy(OpusDecoder *st) |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 1036 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1037 | opus_free(st); |
Jean-Marc Valin | 04584ea | 2010-06-30 15:03:35 -0400 | [diff] [blame] | 1038 | } |
Koen Vos | 8f67b20 | 2011-02-03 09:31:12 -0500 | [diff] [blame] | 1039 | |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1040 | |
| 1041 | int opus_packet_get_bandwidth(const unsigned char *data) |
| 1042 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1043 | int bandwidth; |
| 1044 | if (data[0]&0x80) |
| 1045 | { |
| 1046 | bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3); |
| 1047 | if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) |
| 1048 | bandwidth = OPUS_BANDWIDTH_NARROWBAND; |
| 1049 | } else if ((data[0]&0x60) == 0x60) |
| 1050 | { |
| 1051 | bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND : |
| 1052 | OPUS_BANDWIDTH_SUPERWIDEBAND; |
| 1053 | } else { |
| 1054 | bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3); |
| 1055 | } |
| 1056 | return bandwidth; |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1057 | } |
| 1058 | |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1059 | int opus_packet_get_samples_per_frame(const unsigned char *data, |
| 1060 | opus_int32 Fs) |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1061 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1062 | int audiosize; |
| 1063 | if (data[0]&0x80) |
| 1064 | { |
| 1065 | audiosize = ((data[0]>>3)&0x3); |
| 1066 | audiosize = (Fs<<audiosize)/400; |
| 1067 | } else if ((data[0]&0x60) == 0x60) |
| 1068 | { |
| 1069 | audiosize = (data[0]&0x08) ? Fs/50 : Fs/100; |
| 1070 | } else { |
| 1071 | audiosize = ((data[0]>>3)&0x3); |
| 1072 | if (audiosize == 3) |
| 1073 | audiosize = Fs*60/1000; |
| 1074 | else |
| 1075 | audiosize = (Fs<<audiosize)/100; |
| 1076 | } |
| 1077 | return audiosize; |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1078 | } |
| 1079 | |
| 1080 | int opus_packet_get_nb_channels(const unsigned char *data) |
| 1081 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1082 | return (data[0]&0x4) ? 2 : 1; |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1083 | } |
| 1084 | |
Gregory Maxwell | e702817 | 2011-11-19 23:58:09 -0500 | [diff] [blame] | 1085 | int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1086 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1087 | int count; |
| 1088 | if (len<1) |
| 1089 | return OPUS_BAD_ARG; |
| 1090 | count = packet[0]&0x3; |
| 1091 | if (count==0) |
| 1092 | return 1; |
| 1093 | else if (count!=3) |
| 1094 | return 2; |
| 1095 | else if (len<2) |
| 1096 | return OPUS_INVALID_PACKET; |
| 1097 | else |
| 1098 | return packet[1]&0x3F; |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1099 | } |
| 1100 | |
Jean-Marc Valin | d0fd9d4 | 2012-12-04 15:45:31 -0500 | [diff] [blame] | 1101 | int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, |
| 1102 | opus_int32 Fs) |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1103 | { |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1104 | int samples; |
| 1105 | int count = opus_packet_get_nb_frames(packet, len); |
Jean-Marc Valin | ee8adbe | 2012-01-24 14:45:08 +1300 | [diff] [blame] | 1106 | |
| 1107 | if (count<0) |
| 1108 | return count; |
| 1109 | |
Jean-Marc Valin | d0fd9d4 | 2012-12-04 15:45:31 -0500 | [diff] [blame] | 1110 | samples = count*opus_packet_get_samples_per_frame(packet, Fs); |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1111 | /* Can't have more than 120 ms */ |
Jean-Marc Valin | d0fd9d4 | 2012-12-04 15:45:31 -0500 | [diff] [blame] | 1112 | if (samples*25 > Fs*3) |
Ralph Giles | da025d5 | 2011-10-26 20:24:49 -0700 | [diff] [blame] | 1113 | return OPUS_INVALID_PACKET; |
| 1114 | else |
| 1115 | return samples; |
Jean-Marc Valin | 0fe4078 | 2011-03-13 12:41:08 -0400 | [diff] [blame] | 1116 | } |
Jean-Marc Valin | d0fd9d4 | 2012-12-04 15:45:31 -0500 | [diff] [blame] | 1117 | |
| 1118 | int opus_decoder_get_nb_samples(const OpusDecoder *dec, |
| 1119 | const unsigned char packet[], opus_int32 len) |
| 1120 | { |
| 1121 | return opus_packet_get_nb_samples(packet, len, dec->Fs); |
| 1122 | } |