Adds code for parsing self-delimited packets

This commit is contained in:
Timothy B. Terriberry 2011-08-18 23:29:52 -04:00 committed by Jean-Marc Valin
parent 69549ac05b
commit 7954065c77

View file

@ -444,14 +444,16 @@ static int parse_size(const unsigned char *data, int len, short *size)
} }
} }
int opus_packet_parse(const unsigned char *data, int len, static int opus_packet_parse_impl(const unsigned char *data, int len,
unsigned char *out_toc, const unsigned char *frames[48], int self_delimited, unsigned char *out_toc,
short size[48], int *payload_offset) const unsigned char *frames[48], short size[48], int *payload_offset)
{ {
int i, bytes; int i, bytes;
int count; int count;
int cbr;
unsigned char ch, toc; unsigned char ch, toc;
int framesize; int framesize;
int last_size;
const unsigned char *data0 = data; const unsigned char *data0 = data;
if (size==NULL) if (size==NULL)
@ -459,21 +461,26 @@ int opus_packet_parse(const unsigned char *data, int len,
framesize = opus_packet_get_samples_per_frame(data, 48000); framesize = opus_packet_get_samples_per_frame(data, 48000);
cbr = 0;
toc = *data++; toc = *data++;
len--; len--;
last_size = len;
switch (toc&0x3) switch (toc&0x3)
{ {
/* One frame */ /* One frame */
case 0: case 0:
count=1; count=1;
size[0] = len;
break; break;
/* Two CBR frames */ /* Two CBR frames */
case 1: case 1:
count=2; count=2;
cbr = 1;
if (!self_delimited)
{
if (len&0x1) if (len&0x1)
return OPUS_CORRUPTED_DATA; return OPUS_CORRUPTED_DATA;
size[0] = size[1] = len/2; size[0] = last_size = len/2;
}
break; break;
/* Two VBR frames */ /* Two VBR frames */
case 2: case 2:
@ -483,7 +490,7 @@ int opus_packet_parse(const unsigned char *data, int len,
if (size[0]<0 || size[0] > len) if (size[0]<0 || size[0] > len)
return OPUS_CORRUPTED_DATA; return OPUS_CORRUPTED_DATA;
data += bytes; data += bytes;
size[1] = len-size[0]; last_size = len-size[0];
break; break;
/* Multiple CBR/VBR frames (from 0 to 120 ms) */ /* Multiple CBR/VBR frames (from 0 to 120 ms) */
case 3: case 3:
@ -512,10 +519,11 @@ int opus_packet_parse(const unsigned char *data, int len,
if (len<0) if (len<0)
return OPUS_CORRUPTED_DATA; return OPUS_CORRUPTED_DATA;
/* VBR flag is bit 7 */ /* VBR flag is bit 7 */
if (ch&0x80) cbr = !(ch&0x80);
if (cbr)
{ {
/* VBR case */ /* VBR case */
int last_size=len; last_size = len;
for (i=0;i<count-1;i++) for (i=0;i<count-1;i++)
{ {
bytes = parse_size(data, len, size+i); bytes = parse_size(data, len, size+i);
@ -527,23 +535,44 @@ int opus_packet_parse(const unsigned char *data, int len,
} }
if (last_size<0) if (last_size<0)
return OPUS_CORRUPTED_DATA; return OPUS_CORRUPTED_DATA;
size[count-1]=last_size; } else if (!self_delimited)
} else { {
/* CBR case */ /* CBR case */
int sz = len/count; last_size = len/count;
if (sz*count!=len) if (last_size*count!=len)
return OPUS_CORRUPTED_DATA; return OPUS_CORRUPTED_DATA;
for (i=0;i<count;i++) for (i=0;i<count-1;i++)
size[i] = sz; size[i] = last_size;
} }
break; 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 /* 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 last packet (or all the packets, for the CBR case) is larger than
1275. 1275.
Reject them here.*/ Reject them here.*/
if (size[count-1] > 1275) if (last_size > 1275)
return OPUS_CORRUPTED_DATA; return OPUS_CORRUPTED_DATA;
size[count-1] = last_size;
}
if (frames) if (frames)
{ {
@ -563,6 +592,14 @@ int opus_packet_parse(const unsigned char *data, int len,
return count; 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);
}
#ifdef FIXED_POINT #ifdef FIXED_POINT
int opus_decode(OpusDecoder *st, const unsigned char *data, int opus_decode(OpusDecoder *st, const unsigned char *data,
int len, opus_val16 *pcm, int frame_size, int decode_fec) int len, opus_val16 *pcm, int frame_size, int decode_fec)
@ -585,7 +622,7 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data,
st->frame_size = opus_packet_get_samples_per_frame(data, st->Fs); st->frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
st->stream_channels = opus_packet_get_nb_channels(data); st->stream_channels = opus_packet_get_nb_channels(data);
count = opus_packet_parse(data, len, &toc, NULL, size, &offset); count = opus_packet_parse_impl(data, len, 0, &toc, NULL, size, &offset);
if (count < 0) if (count < 0)
return count; return count;