ref: ed4632345ef8edd8ce07403bb4a4996d8c8f440a
parent: aee4d8057632ea0cfc1d55d88acf8466b47b7b4b
author: Jean-Marc Valin <[email protected]>
date: Fri Oct 11 14:06:00 EDT 2013
Do up-front validation of multistream packets Prevents the decoder from being out-of-sync on an invalid packet. Also returns OPUS_INVALID_PACKET on a corrupted FEC packet.
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -355,7 +355,7 @@
pcm_ptr[i] = 0;
} else {
RESTORE_STACK;
- return OPUS_INVALID_PACKET;
+ return OPUS_INTERNAL_ERROR;
}
}
pcm_ptr += silk_frame_size * st->channels;
@@ -581,7 +581,7 @@
}
}
-static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
int self_delimited, unsigned char *out_toc,
const unsigned char *frames[48], opus_int16 size[48], int *payload_offset)
{
@@ -710,6 +710,9 @@
size[count-1] = (opus_int16)last_size;
}
+ if (payload_offset)
+ *payload_offset = (int)(data-data0);
+
if (frames)
{
for (i=0;i<count;i++)
@@ -722,9 +725,6 @@
if (out_toc)
*out_toc = toc;
- if (payload_offset)
- *payload_offset = (int)(data-data0);
-
return count;
}
@@ -777,6 +777,9 @@
count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset);
+ if (count<0)
+ return count;
+
data += offset;
if (decode_fec)
@@ -814,11 +817,7 @@
return frame_size;
}
}
- tot_offset = 0;
- if (count < 0)
- return count;
-
- tot_offset += offset;
+ tot_offset = offset;
if (count*packet_frame_size > frame_size)
return OPUS_BUFFER_TOO_SMALL;
--- a/src/opus_multistream_decoder.c
+++ b/src/opus_multistream_decoder.c
@@ -152,6 +152,37 @@
int frame_size
);
+static int opus_multistream_packet_validate(const unsigned char *data,
+ opus_int32 len, int nb_streams)
+{
+ int s;
+ int i;
+ int count;
+ unsigned char toc;
+ opus_int16 size[48];
+ int offset;
+ int samples=0;
+
+ for (s=0;s<nb_streams;s++)
+ {
+ int tmp_samples;
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL, size, &offset);
+ if (count<0)
+ return count;
+ for (i=0;i<count;i++)
+ offset += size[i];
+ tmp_samples = opus_packet_get_nb_samples(data, offset, 48000);
+ if (s!=0 && samples != tmp_samples)
+ return OPUS_INVALID_PACKET;
+ samples = tmp_samples;
+ data += offset;
+ len -= offset;
+ }
+ return OPUS_OK;
+}
+
static int opus_multistream_decode_native(
OpusMSDecoder *st,
const unsigned char *data,
@@ -183,9 +214,24 @@
if (len==0)
do_plc = 1;
if (len < 0)
+ {
+ RESTORE_STACK;
return OPUS_BAD_ARG;
+ }
if (!do_plc && len < 2*st->layout.nb_streams-1)
+ {
+ RESTORE_STACK;
return OPUS_INVALID_PACKET;
+ }
+ if (!do_plc)
+ {
+ int ret = opus_multistream_packet_validate(data, len, st->layout.nb_coupled_streams);
+ if (ret < 0)
+ {
+ RESTORE_STACK;
+ return ret;
+ }
+ }
for (s=0;s<st->layout.nb_streams;s++)
{
OpusDecoder *dec;
--- a/src/opus_private.h
+++ b/src/opus_private.h
@@ -112,6 +112,10 @@
return (i+(int)sizeof(void *)-1)&-(int)sizeof(void *);
}
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+ int self_delimited, unsigned char *out_toc,
+ const unsigned char *frames[48], opus_int16 size[48], int *payload_offset);
+
opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen, int self_delimited);
#endif /* OPUS_PRIVATE_H */