shithub: opus

Download patch

ref: c2d86f06399780830d04239038265626f94a8d0f
parent: e8dbcb8f087c8e5568fb3942a86d09c35749ad95
author: Jean-Marc Valin <[email protected]>
date: Wed Aug 10 10:17:55 EDT 2011

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

--- a/src/opus.h
+++ b/src/opus.h
@@ -246,9 +246,13 @@
 
 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);
 
--- a/src/repacketizer.c
+++ b/src/repacketizer.c
@@ -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 @@
    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 @@
    {
       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 @@
    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 @@
    }
    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 @@
    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 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 @@
       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;
 }
--- a/src/test_opus.c
+++ b/src/test_opus.c
@@ -104,13 +104,11 @@
     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 @@
     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,15 +338,14 @@
             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++)
-                    in[i] = 0;
+                for (i=curr_read*channels;i<frame_size*channels;i++)
+                   in[i] = 0;
                 stop = 1;
             }
 
@@ -386,13 +384,7 @@
                 }
                 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;
                 }
             }
@@ -399,9 +391,9 @@
         }
 
         /* 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;
         }
 
--- a/src/test_repacketizer.c
+++ b/src/test_repacketizer.c
@@ -2,6 +2,8 @@
 
 #include "opus.h"
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #define MAX_PACKETOUT 32000
 
@@ -26,7 +28,7 @@
 
 int main(int argc, char *argv[])
 {
-   int eof=0;
+   int i, eof=0;
    FILE *fin, *fout;
    unsigned char packets[48][1500];
    int len[48];
@@ -33,6 +35,7 @@
    int rng[48];
    OpusRepacketizer *rp;
    unsigned char output_packet[MAX_PACKETOUT];
+   int merge = 1, split=0;
 
    if (argc < 3)
    {
@@ -39,6 +42,21 @@
       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");
 
@@ -45,8 +63,8 @@
    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,17 +99,42 @@
 
       if (eof)
          break;
-      err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT);
-      if (err>0) {
-          unsigned char int_field[4];
-          int_to_char(err, int_field);
-          fwrite(int_field, 1, 4, fout);
-          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);*/
+
+      if (!split)
+      {
+         err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT);
+         if (err>0) {
+            unsigned char int_field[4];
+            int_to_char(err, int_field);
+            fwrite(int_field, 1, 4, fout);
+            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 {
-         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));
+            }
+
+         }
       }
 
    }