| Index: src/opus_decoder.c
|
| diff --git a/src/opus_decoder.c b/src/opus_decoder.c
|
| index f0188cdaedbb4866967d267b5c041c20202634f5..ad5f747016242b43a042e4f44217a5a377412096 100644
|
| --- a/src/opus_decoder.c
|
| +++ b/src/opus_decoder.c
|
| @@ -30,7 +30,7 @@
|
| #endif
|
|
|
| #ifndef OPUS_BUILD
|
| -#error "OPUS_BUILD _MUST_ be defined to build Opus and you probably want a decent config.h, see README for more details."
|
| +#error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details."
|
| #endif
|
|
|
| #include <stdarg.h>
|
| @@ -64,6 +64,7 @@ struct OpusDecoder {
|
| int prev_mode;
|
| int frame_size;
|
| int prev_redundancy;
|
| + int last_packet_duration;
|
|
|
| opus_uint32 rangeFinal;
|
| };
|
| @@ -257,23 +258,10 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
| }
|
| }
|
|
|
| - /* For CELT/hybrid PLC of more than 20 ms, do multiple calls */
|
| - if (data==NULL && frame_size > F20 && mode != MODE_SILK_ONLY)
|
| - {
|
| - int nb_samples = 0;
|
| - do {
|
| - int ret = opus_decode_frame(st, NULL, 0, pcm, F20, 0);
|
| - if (ret != F20)
|
| - {
|
| - RESTORE_STACK;
|
| - return OPUS_INTERNAL_ERROR;
|
| - }
|
| - pcm += F20*st->channels;
|
| - nb_samples += F20;
|
| - } while (nb_samples < frame_size);
|
| - RESTORE_STACK;
|
| - return frame_size;
|
| - }
|
| + /* For CELT/hybrid PLC of more than 20 ms, opus_decode_native() will do
|
| + multiple calls */
|
| + if (data==NULL && mode != MODE_SILK_ONLY)
|
| + frame_size = IMIN(frame_size, F20);
|
| ALLOC(pcm_transition, F5*st->channels, opus_val16);
|
|
|
| if (data!=NULL && st->prev_mode > 0 && (
|
| @@ -560,7 +548,7 @@ static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
|
| int cbr;
|
| unsigned char ch, toc;
|
| int framesize;
|
| - int last_size;
|
| + opus_int32 last_size;
|
| const unsigned char *data0 = data;
|
|
|
| if (size==NULL)
|
| @@ -586,7 +574,9 @@ static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
|
| {
|
| if (len&0x1)
|
| return OPUS_INVALID_PACKET;
|
| - size[0] = last_size = len/2;
|
| + last_size = len/2;
|
| + /* If last_size doesn't fit in size[0], we'll catch it later */
|
| + size[0] = (short)last_size;
|
| }
|
| break;
|
| /* Two VBR frames */
|
| @@ -647,7 +637,7 @@ static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
|
| if (last_size*count!=len)
|
| return OPUS_INVALID_PACKET;
|
| for (i=0;i<count-1;i++)
|
| - size[i] = last_size;
|
| + size[i] = (short)last_size;
|
| }
|
| break;
|
| }
|
| @@ -675,7 +665,7 @@ static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
|
| 1275. Reject them here.*/
|
| if (last_size > 1275)
|
| return OPUS_INVALID_PACKET;
|
| - size[count-1] = last_size;
|
| + size[count-1] = (short)last_size;
|
| }
|
|
|
| if (frames)
|
| @@ -712,30 +702,81 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
|
| int count, offset;
|
| unsigned char toc;
|
| int tot_offset;
|
| + int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
|
| /* 48 x 2.5 ms = 120 ms */
|
| short size[48];
|
| if (decode_fec<0 || decode_fec>1)
|
| return OPUS_BAD_ARG;
|
| + /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
|
| + if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
|
| + return OPUS_BAD_ARG;
|
| if (len==0 || data==NULL)
|
| - return opus_decode_frame(st, NULL, 0, pcm, frame_size, 0);
|
| - else if (len<0)
|
| + {
|
| + int pcm_count=0;
|
| + do {
|
| + int ret;
|
| + ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-pcm_count, 0);
|
| + if (ret<0)
|
| + return ret;
|
| + pcm += st->channels*ret;
|
| + pcm_count += ret;
|
| + } while (pcm_count < frame_size);
|
| + st->last_packet_duration = pcm_count;
|
| + return pcm_count;
|
| + } 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);
|
| + packet_mode = opus_packet_get_mode(data);
|
| + packet_bandwidth = opus_packet_get_bandwidth(data);
|
| + packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
|
| + packet_stream_channels = opus_packet_get_nb_channels(data);
|
|
|
| count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset);
|
| +
|
| + data += offset;
|
| +
|
| + if (decode_fec)
|
| + {
|
| + int duration_copy;
|
| + int ret;
|
| + /* If no FEC can be present, run the PLC (recursive call) */
|
| + if (frame_size <= packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
|
| + return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL);
|
| + /* Otherwise, run the PLC on everything except the size for which we might have FEC */
|
| + duration_copy = st->last_packet_duration;
|
| + ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL);
|
| + if (ret<0)
|
| + {
|
| + st->last_packet_duration = duration_copy;
|
| + return ret;
|
| + }
|
| + /* Complete with FEC */
|
| + st->mode = packet_mode;
|
| + st->bandwidth = packet_bandwidth;
|
| + st->frame_size = packet_frame_size;
|
| + st->stream_channels = packet_stream_channels;
|
| + ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
|
| + packet_frame_size, 1);
|
| + if (ret<0)
|
| + return ret;
|
| + st->last_packet_duration = frame_size;
|
| + return frame_size;
|
| + }
|
| + tot_offset = 0;
|
| if (count < 0)
|
| return count;
|
|
|
| - data += offset;
|
| tot_offset += offset;
|
|
|
| - if (count*st->frame_size > frame_size)
|
| + if (count*packet_frame_size > frame_size)
|
| return OPUS_BUFFER_TOO_SMALL;
|
| +
|
| + /* Update the state as the last step to avoid updating it on an invalid packet */
|
| + st->mode = packet_mode;
|
| + st->bandwidth = packet_bandwidth;
|
| + st->frame_size = packet_frame_size;
|
| + st->stream_channels = packet_stream_channels;
|
| +
|
| nb_samples=0;
|
| for (i=0;i<count;i++)
|
| {
|
| @@ -750,6 +791,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
|
| }
|
| if (packet_offset != NULL)
|
| *packet_offset = tot_offset;
|
| + st->last_packet_duration = nb_samples;
|
| return nb_samples;
|
| }
|
|
|
| @@ -903,6 +945,12 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
|
| st->decode_gain = value;
|
| }
|
| break;
|
| + case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
|
| + {
|
| + opus_uint32 *value = va_arg(ap, opus_uint32*);
|
| + *value = st->last_packet_duration;
|
| + }
|
| + break;
|
| default:
|
| /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
|
| ret = OPUS_UNIMPLEMENTED;
|
| @@ -979,8 +1027,8 @@ int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len)
|
| return packet[1]&0x3F;
|
| }
|
|
|
| -int opus_decoder_get_nb_samples(const OpusDecoder *dec,
|
| - const unsigned char packet[], opus_int32 len)
|
| +int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len,
|
| + opus_int32 Fs)
|
| {
|
| int samples;
|
| int count = opus_packet_get_nb_frames(packet, len);
|
| @@ -988,10 +1036,16 @@ int opus_decoder_get_nb_samples(const OpusDecoder *dec,
|
| if (count<0)
|
| return count;
|
|
|
| - samples = count*opus_packet_get_samples_per_frame(packet, dec->Fs);
|
| + samples = count*opus_packet_get_samples_per_frame(packet, Fs);
|
| /* Can't have more than 120 ms */
|
| - if (samples*25 > dec->Fs*3)
|
| + if (samples*25 > Fs*3)
|
| return OPUS_INVALID_PACKET;
|
| else
|
| return samples;
|
| }
|
| +
|
| +int opus_decoder_get_nb_samples(const OpusDecoder *dec,
|
| + const unsigned char packet[], opus_int32 len)
|
| +{
|
| + return opus_packet_get_nb_samples(packet, len, dec->Fs);
|
| +}
|
|
|