Fixed multiple bugs in the repacketizer

Repacketizer now seems to work, though it doesn't yet handle
unmergeable packets. Also, test_opis no longer attempt to do proper
gapless at the end of the file, which was causing problems for
repacketization, but also with 32 bit overflows
This commit is contained in:
Jean-Marc Valin 2011-08-10 14:17:55 -04:00
parent e8dbcb8f08
commit c2d86f0639
4 changed files with 104 additions and 48 deletions

View file

@ -246,10 +246,14 @@ OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp);
OPUS_EXPORT OpusRepacketizer *opus_repacketizer_create(void);
OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);
OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, int len);
OPUS_EXPORT int opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, int maxlen);
OPUS_EXPORT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp);
OPUS_EXPORT int opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, int maxlen);
#ifdef __cplusplus

View file

@ -32,6 +32,7 @@
#include <stdio.h>
#include "string.h"
#include "opus.h"
#include "stdlib.h"
struct OpusRepacketizer {
unsigned char toc;
@ -70,6 +71,11 @@ OpusRepacketizer *opus_repacketizer_create(void)
return opus_repacketizer_init(malloc(opus_repacketizer_get_size()));
}
void opus_repacketizer_destroy(OpusRepacketizer *rp)
{
free(rp);
}
int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, int len)
{
unsigned char tmp_toc;
@ -79,7 +85,7 @@ int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, int l
{
rp->toc = data[0];
rp->framesize = opus_packet_get_samples_per_frame(data, 48000);
} else if (rp->toc != data[0])
} else if (rp->toc&0xFC != data[0]&0xFC)
{
/*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
return OPUS_CORRUPTED_DATA;
@ -98,9 +104,16 @@ int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, int l
return OPUS_OK;
}
int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
{
return rp->nb_frames;
}
int opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, int maxlen)
{
int i, count, tot_size;
short *len;
const unsigned char **frames;
if (begin<0 || begin>=end || end>rp->nb_frames)
{
@ -109,12 +122,14 @@ int opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsign
}
count = end-begin;
len = rp->len+begin;
frames = rp->frames+begin;
switch (count)
{
case 1:
{
/* Code 0 */
tot_size = rp->len[0]+1;
tot_size = len[0]+1;
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*data++ = rp->toc&0xFC;
@ -122,20 +137,20 @@ int opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsign
break;
case 2:
{
if (rp->len[1] == rp->len[0])
if (len[1] == len[0])
{
/* Code 1 */
tot_size = 2*rp->len[0]+1;
tot_size = 2*len[0]+1;
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*data++ = (rp->toc&0xFC) | 0x1;
} else {
/* Code 2 */
tot_size = rp->len[0]+rp->len[0]+2+(rp->len[0]>=252);
tot_size = len[0]+len[1]+2+(len[0]>=252);
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*data++ = (rp->toc&0xFC) | 0x2;
data += encode_size(rp->len[0], data);
data += encode_size(len[0], data);
}
}
break;
@ -145,9 +160,9 @@ int opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsign
int vbr;
vbr = 0;
for (i=1;i<rp->nb_frames;i++)
for (i=1;i<count;i++)
{
if (rp->len[i] != rp->len[0])
if (len[i] != len[0])
{
vbr=1;
break;
@ -156,28 +171,30 @@ int opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsign
if (vbr)
{
tot_size = 2;
for (i=0;i<rp->nb_frames;i++)
tot_size += 1 + (rp->len[i]>=252) + rp->len[i];
for (i=0;i<count-1;i++)
tot_size += 1 + (len[i]>=252) + len[i];
tot_size += len[count-1];
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*data++ = (rp->toc&0xFC) | 0x3;
*data++ = rp->nb_frames | 0x80;
for (i=0;i<rp->nb_frames-1;i++)
data += encode_size(rp->len[i], data);
*data++ = count | 0x80;
for (i=0;i<count-1;i++)
data += encode_size(len[i], data);
} else {
tot_size = rp->nb_frames*rp->len[0]+2;
tot_size = count*len[0]+2;
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*data++ = (rp->toc&0xFC) | 0x3;
*data++ = rp->nb_frames;
*data++ = count;
}
}
}
/* Copy the actual data */
for (i=0;i<rp->nb_frames;i++)
for (i=0;i<count;i++)
{
memcpy(data, rp->frames[i], rp->len[i]);
data += rp->len[i];
memcpy(data, frames[i], len[i]);
data += len[i];
}
return tot_size;
}

View file

@ -104,13 +104,11 @@ int main(int argc, char *argv[])
int count=0, count_act=0, k;
int skip;
int stop=0;
int tot_read=0, tot_written=0;
short *in, *out;
int application;
double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
int bandwidth=-1;
const char *bandwidth_string;
int write_samples;
int lost = 0, lost_prev = 1;
int toggle = 0;
int enc_final_range[2];
@ -158,7 +156,8 @@ int main(int argc, char *argv[])
forcemono = 0;
use_dtx = 0;
packet_loss_perc = 0;
int max_frame_size = 960*3;
int max_frame_size = 960*6;
int curr_read=0;
args = 5;
while( args < argc - 2 ) {
@ -339,14 +338,13 @@ int main(int argc, char *argv[])
err = fread(data[toggle], 1, len[toggle], fin);
if (feof(fin))
break;
tot_read += frame_size*channels;
} else {
err = fread(in, sizeof(short), frame_size*channels, fin);
tot_read += err;
if (err < frame_size*channels)
curr_read = err;
if (curr_read < frame_size*channels)
{
int i;
for (i=err;i<frame_size*channels;i++)
for (i=curr_read*channels;i<frame_size*channels;i++)
in[i] = 0;
stop = 1;
}
@ -386,22 +384,16 @@ int main(int argc, char *argv[])
}
if (output_samples>0)
{
write_samples = output_samples-skip;
tot_written += write_samples*channels;
if (tot_written > tot_read)
{
write_samples -= (tot_written-tot_read)/channels;
}
fwrite(out+skip, sizeof(short), write_samples*channels, fout);
fwrite(out+skip, sizeof(short), output_samples-skip*channels, fout);
skip = 0;
}
}
}
/* compare final range encoder rng values of encoder and decoder */
if( !encode_only && !lost && !lost_prev &&
if( enc_final_range[toggle^use_inbandfec]!=0 && !encode_only && !lost && !lost_prev &&
opus_decoder_get_final_range( dec ) != enc_final_range[toggle^use_inbandfec] ) {
fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder in frame %d.\n", count);
fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder in frame %d: 0x%8x vs 0x%8x\n", count, enc_final_range[toggle^use_inbandfec], opus_decoder_get_final_range( dec ));
return 0;
}

View file

@ -2,6 +2,8 @@
#include "opus.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_PACKETOUT 32000
@ -26,27 +28,43 @@ static opus_uint32 char_to_int(unsigned char ch[4])
int main(int argc, char *argv[])
{
int eof=0;
int i, eof=0;
FILE *fin, *fout;
unsigned char packets[48][1500];
int len[48];
int rng[48];
OpusRepacketizer *rp;
unsigned char output_packet[MAX_PACKETOUT];
int merge = 1, split=0;
if (argc < 3)
{
usage(argv[0]);
return 1;
}
for (i=1;i<argc-2;i++)
{
if (strcmp(argv[i], "-merge")==0)
{
merge = atoi(argv[i+1]);
i++;
} else if (strcmp(argv[i], "-split")==0)
split = 1;
else
{
fprintf(stderr, "Unknown option: %s\n", argv[i]);
usage(argv[0]);
return 1;
}
}
fin = fopen(argv[argc-2], "r");
fout = fopen(argv[argc-1], "w");
rp = opus_repacketizer_create();
while (!eof)
{
int i, err;
int nb_packets=2;
int err;
int nb_packets=merge;
opus_repacketizer_init(rp);
for (i=0;i<nb_packets;i++)
{
@ -81,6 +99,9 @@ int main(int argc, char *argv[])
if (eof)
break;
if (!split)
{
err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT);
if (err>0) {
unsigned char int_field[4];
@ -93,6 +114,28 @@ int main(int argc, char *argv[])
} else {
fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err));
}
} else {
int nb_frames = opus_repacketizer_get_nb_frames(rp);
for (i=0;i<nb_frames;i++)
{
err = opus_repacketizer_out_range(rp, i, i+1, output_packet, MAX_PACKETOUT);
if (err>0) {
unsigned char int_field[4];
int_to_char(err, int_field);
fwrite(int_field, 1, 4, fout);
if (i==nb_frames-1)
int_to_char(rng[nb_packets-1], int_field);
else
int_to_char(0, int_field);
fwrite(int_field, 1, 4, fout);
fwrite(output_packet, 1, err, fout);
/*fprintf(stderr, "out len = %d\n", err);*/
} else {
fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err));
}
}
}
}