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 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_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_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); OPUS_EXPORT int opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, int maxlen);
#ifdef __cplusplus #ifdef __cplusplus

View file

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

View file

@ -104,13 +104,11 @@ int main(int argc, char *argv[])
int count=0, count_act=0, k; int count=0, count_act=0, k;
int skip; int skip;
int stop=0; int stop=0;
int tot_read=0, tot_written=0;
short *in, *out; short *in, *out;
int application; int application;
double bits=0.0, bits_act=0.0, bits2=0.0, nrg; double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
int bandwidth=-1; int bandwidth=-1;
const char *bandwidth_string; const char *bandwidth_string;
int write_samples;
int lost = 0, lost_prev = 1; int lost = 0, lost_prev = 1;
int toggle = 0; int toggle = 0;
int enc_final_range[2]; int enc_final_range[2];
@ -158,7 +156,8 @@ int main(int argc, char *argv[])
forcemono = 0; forcemono = 0;
use_dtx = 0; use_dtx = 0;
packet_loss_perc = 0; packet_loss_perc = 0;
int max_frame_size = 960*3; int max_frame_size = 960*6;
int curr_read=0;
args = 5; args = 5;
while( args < argc - 2 ) { while( args < argc - 2 ) {
@ -339,15 +338,14 @@ int main(int argc, char *argv[])
err = fread(data[toggle], 1, len[toggle], fin); err = fread(data[toggle], 1, len[toggle], fin);
if (feof(fin)) if (feof(fin))
break; break;
tot_read += frame_size*channels;
} else { } else {
err = fread(in, sizeof(short), frame_size*channels, fin); err = fread(in, sizeof(short), frame_size*channels, fin);
tot_read += err; curr_read = err;
if (err < frame_size*channels) if (curr_read < frame_size*channels)
{ {
int i; int i;
for (i=err;i<frame_size*channels;i++) for (i=curr_read*channels;i<frame_size*channels;i++)
in[i] = 0; in[i] = 0;
stop = 1; stop = 1;
} }
@ -386,22 +384,16 @@ int main(int argc, char *argv[])
} }
if (output_samples>0) if (output_samples>0)
{ {
write_samples = output_samples-skip; fwrite(out+skip, sizeof(short), output_samples-skip*channels, fout);
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);
skip = 0; skip = 0;
} }
} }
} }
/* compare final range encoder rng values of encoder and decoder */ /* 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] ) { 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; return 0;
} }

View file

@ -2,6 +2,8 @@
#include "opus.h" #include "opus.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_PACKETOUT 32000 #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 main(int argc, char *argv[])
{ {
int eof=0; int i, eof=0;
FILE *fin, *fout; FILE *fin, *fout;
unsigned char packets[48][1500]; unsigned char packets[48][1500];
int len[48]; int len[48];
int rng[48]; int rng[48];
OpusRepacketizer *rp; OpusRepacketizer *rp;
unsigned char output_packet[MAX_PACKETOUT]; unsigned char output_packet[MAX_PACKETOUT];
int merge = 1, split=0;
if (argc < 3) if (argc < 3)
{ {
usage(argv[0]); usage(argv[0]);
return 1; 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"); fin = fopen(argv[argc-2], "r");
fout = fopen(argv[argc-1], "w"); fout = fopen(argv[argc-1], "w");
rp = opus_repacketizer_create(); rp = opus_repacketizer_create();
while (!eof) while (!eof)
{ {
int i, err; int err;
int nb_packets=2; int nb_packets=merge;
opus_repacketizer_init(rp); opus_repacketizer_init(rp);
for (i=0;i<nb_packets;i++) for (i=0;i<nb_packets;i++)
{ {
@ -81,17 +99,42 @@ int main(int argc, char *argv[])
if (eof) if (eof)
break; break;
err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT);
if (err>0) { if (!split)
unsigned char int_field[4]; {
int_to_char(err, int_field); err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT);
fwrite(int_field, 1, 4, fout); if (err>0) {
int_to_char(rng[nb_packets-1], int_field); unsigned char int_field[4];
fwrite(int_field, 1, 4, fout); int_to_char(err, int_field);
fwrite(output_packet, 1, err, fout); fwrite(int_field, 1, 4, fout);
/*fprintf(stderr, "out len = %d\n", err);*/ int_to_char(rng[nb_packets-1], 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));
}
} else { } else {
fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err)); 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));
}
}
} }
} }