shithub: opus-tools

Download patch

ref: 65edaa18fdc5adedf197805bc73771585c077bb7
parent: 0ef1f216713415d96b8a8fb3ec139d084c0266f1
author: Gregory Maxwell <greg@xiph.org>
date: Tue Nov 22 18:45:24 EST 2011

Add --save-range for opusdec too.

--- a/src/Makefile
+++ b/src/Makefile
@@ -7,11 +7,11 @@
 .c.o:
 	$(CC) $(CFLAGS) $(INCLUDES) $< -o $@
 
-opusenc: opus_header.o opusenc.o resample.o audio-in.o
-	gcc opus_header.o audio-in.o opusenc.o resample.o -o opusenc ../../opus/.libs/libopus.a -lm -logg
+opusenc: opus_header.o opusenc.o resample.o audio-in.o diag_range.o
+	gcc opus_header.o audio-in.o diag_range.o opusenc.o resample.o -o opusenc ../../opus/.libs/libopus.a -lm -logg
 
-opusdec: opus_header.o wav_io.o wave_out.o opusdec.o resample.o
-	gcc wave_out.o opus_header.o wav_io.o opusdec.o resample.o -o opusdec ../../opus/.libs/libopus.a -lm -logg
+opusdec: opus_header.o wav_io.o wave_out.o opusdec.o resample.o diag_range.o
+	gcc wave_out.o opus_header.o wav_io.o diag_range.o opusdec.o resample.o -o opusdec ../../opus/.libs/libopus.a -lm -logg
 
 clean:
 	rm -f *.o opusenc opusdec
--- /dev/null
+++ b/src/diag_range.c
@@ -1,0 +1,233 @@
+/* Copyright (C)2012 Xiph.Org Foundation
+   Copyright (C)2012 Gregory Maxwell
+   Copyright (C)2012 Jean-Marc Valin
+   File: diag_range.c
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include "opus.h"
+#include "diag_range.h"
+
+/*This is some non-exported code copied wholesale from libopus.
+ *Normal programs shouldn't need these functions, but we use them here
+ *to parse deep inside multichannel packets in order to get diagnostic
+ *data for save-range. If you're thinking about copying it and you aren't
+ *making an opus stream diagnostic tool, you're probably doing something
+ *wrong.*/
+static int parse_size(const unsigned char *data, opus_int32 len, short *size)
+{
+   if (len<1)
+   {
+      *size = -1;
+      return -1;
+   } else if (data[0]<252)
+   {
+      *size = data[0];
+      return 1;
+   } else if (len<2)
+   {
+      *size = -1;
+      return -1;
+   } else {
+      *size = 4*data[1] + data[0];
+      return 2;
+   }
+}
+
+static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+      int self_delimited, unsigned char *out_toc,
+      const unsigned char *frames[48], short size[48], int *payload_offset)
+{
+   int i, bytes;
+   int count;
+   int cbr;
+   unsigned char ch, toc;
+   int framesize;
+   int last_size;
+   const unsigned char *data0 = data;
+
+   if (size==NULL)
+      return OPUS_BAD_ARG;
+
+   framesize = opus_packet_get_samples_per_frame(data, 48000);
+
+   cbr = 0;
+   toc = *data++;
+   len--;
+   last_size = len;
+   switch (toc&0x3)
+   {
+   /* One frame */
+   case 0:
+      count=1;
+      break;
+   /* Two CBR frames */
+   case 1:
+      count=2;
+      cbr = 1;
+      if (!self_delimited)
+      {
+         if (len&0x1)
+            return OPUS_INVALID_PACKET;
+         size[0] = last_size = len/2;
+      }
+      break;
+   /* Two VBR frames */
+   case 2:
+      count = 2;
+      bytes = parse_size(data, len, size);
+      len -= bytes;
+      if (size[0]<0 || size[0] > len)
+         return OPUS_INVALID_PACKET;
+      data += bytes;
+      last_size = len-size[0];
+      break;
+   /* Multiple CBR/VBR frames (from 0 to 120 ms) */
+   case 3:
+      if (len<1)
+         return OPUS_INVALID_PACKET;
+      /* Number of frames encoded in bits 0 to 5 */
+      ch = *data++;
+      count = ch&0x3F;
+      if (count <= 0 || framesize*count > 5760)
+         return OPUS_INVALID_PACKET;
+      len--;
+      /* Padding flag is bit 6 */
+      if (ch&0x40)
+      {
+         int padding=0;
+         int p;
+         do {
+            if (len<=0)
+               return OPUS_INVALID_PACKET;
+            p = *data++;
+            len--;
+            padding += p==255 ? 254: p;
+         } while (p==255);
+         len -= padding;
+      }
+      if (len<0)
+         return OPUS_INVALID_PACKET;
+      /* VBR flag is bit 7 */
+      cbr = !(ch&0x80);
+      if (!cbr)
+      {
+         /* VBR case */
+         last_size = len;
+         for (i=0;i<count-1;i++)
+         {
+            bytes = parse_size(data, len, size+i);
+            len -= bytes;
+            if (size[i]<0 || size[i] > len)
+               return OPUS_INVALID_PACKET;
+            data += bytes;
+            last_size -= bytes+size[i];
+         }
+         if (last_size<0)
+            return OPUS_INVALID_PACKET;
+      } else if (!self_delimited)
+      {
+         /* CBR case */
+         last_size = len/count;
+         if (last_size*count!=len)
+            return OPUS_INVALID_PACKET;
+         for (i=0;i<count-1;i++)
+            size[i] = last_size;
+      }
+      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_INVALID_PACKET;
+      data += bytes;
+      /* For CBR packets, apply the size to all the frames. */
+      if (cbr)
+      {
+         if (size[count-1]*count > len)
+            return OPUS_INVALID_PACKET;
+         for (i=0;i<count-1;i++)
+            size[i] = size[count-1];
+      } else if(size[count-1] > last_size)
+         return OPUS_INVALID_PACKET;
+   } else
+   {
+      /* 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
+         1275. Reject them here.*/
+      if (last_size > 1275)
+         return OPUS_INVALID_PACKET;
+      size[count-1] = last_size;
+   }
+
+   if (frames)
+   {
+      for (i=0;i<count;i++)
+      {
+         frames[i] = data;
+         data += size[i];
+      }
+   }
+
+   if (out_toc)
+      *out_toc = toc;
+
+   if (payload_offset)
+      *payload_offset = data-data0;
+
+   return count;
+}
+
+void save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams){
+  int i, parse_size;
+  const unsigned char *subpkt;
+  static const char *bw_strings[5]={"NB","MB","WB","SWB","FB"};
+  static const char *mode_strings[3]={"LP","HYB","MDCT"};
+  fprintf(frange,"%d, %d, ",frame_size,nbBytes);
+  subpkt=packet;
+  parse_size=nbBytes;
+  for(i=0;i<nb_streams;i++){
+    int j,payload_offset,nf;
+    const unsigned char *frames[48];
+    unsigned char toc;
+    short size[48];
+    payload_offset=0;
+    nf=opus_packet_parse_impl(subpkt,parse_size,i+1!=nb_streams,
+      &toc,frames,size,&payload_offset);
+    fprintf(frange,"[[%d",(int)(frames[0]-subpkt));
+    for(j=0;j<nf;j++)fprintf(frange,", %d",size[j]);
+    fprintf(frange,"], %s, %s, %c, %d",
+       mode_strings[((((subpkt[0]>>3)+48)&92)+4)>>5],
+       bw_strings[opus_packet_get_bandwidth(subpkt)-OPUS_BANDWIDTH_NARROWBAND],
+       subpkt[0]&4?'S':'M',opus_packet_get_samples_per_frame(subpkt,48000));
+    fprintf(frange,", %llu]%s",(unsigned long long)rngs[i],i+1==nb_streams?"\n":", ");
+    parse_size-=payload_offset;
+    subpkt+=payload_offset;
+  }
+}
--- /dev/null
+++ b/src/diag_range.h
@@ -1,0 +1,1 @@
+void save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams);
--- a/src/opusdec.c
+++ b/src/opusdec.c
@@ -82,6 +82,7 @@
 #include <string.h>
 #include "wav_io.h"
 #include "opus_header.h"
+#include "diag_range.h"
 #include "speex_resampler.h"
 
 #define MINI(_a,_b)      ((_a)<(_b)?(_a):(_b))
@@ -371,6 +372,7 @@
    printf (" --rate n              Force decoding at sampling rate n Hz\n");
    printf (" --no-dither           Do not dither 16-bit output\n");
    printf (" --packet-loss n       Simulate n %% random packet loss\n");
+   printf (" --save-range file     Saves check values for every frame to a file\n");
    printf (" -V                    Verbose mode (show bit-rate)\n");
    printf (" -h, --help            This help\n");
    printf (" -v, --version         Version information\n");
@@ -389,7 +391,7 @@
    printf ("Copyright (C) 2008-2011 Jean-Marc Valin\n");
 }
 
-static OpusMSDecoder *process_header(ogg_packet *op, opus_int32 *rate, int *channels, int *preskip, float *gain, int quiet)
+static OpusMSDecoder *process_header(ogg_packet *op, opus_int32 *rate, int *channels, int *preskip, float *gain, int *streams, int quiet)
 {
    int err;
    OpusMSDecoder *st;
@@ -423,6 +425,8 @@
       return NULL;
    }
 
+   *streams=header.nb_streams;
+
    *gain = pow(10., header.gain/5120.);
 
    if (header.gain!=0)
@@ -488,7 +492,8 @@
    int c;
    int option_index = 0;
    char *inFile, *outFile;
-   FILE *fin, *fout=NULL;
+   FILE *fin, *fout=NULL, *frange=NULL;
+   char             *range_file;
    float *output;
    int frame_size=0;
    OpusMSDecoder *st=NULL;
@@ -508,6 +513,7 @@
       {"stereo", no_argument, NULL, 0},
       {"no-dither", no_argument, NULL, 0},
       {"packet-loss", required_argument, NULL, 0},
+      {"save-range", required_argument, NULL, 0},
       {0, 0, 0, 0}
    };
    ogg_sync_state oy;
@@ -528,6 +534,7 @@
    shapestate shapemem;
    SpeexResamplerState *resampler=NULL;
    float gain=1;
+   int streams=0;
 
    output=0;
    shapemem.a_buf=0;
@@ -573,6 +580,15 @@
          } else if (strcmp(long_options[option_index].name,"rate")==0)
          {
             rate=atoi (optarg);
+        }else if(strcmp(long_options[option_index].name,"save-range")==0){
+          frange=fopen(optarg,"w");
+          if(frange==NULL){
+            perror(optarg);
+            fprintf(stderr,"Could not open save-range file: %s\n",optarg);
+            fprintf(stderr,"Must provide a writable file name.\n");
+            exit(1);
+          }
+          range_file=optarg;
          } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
          {
             loss_percent = atof(optarg);
@@ -669,7 +685,7 @@
             /*If first packet, process as OPUS header*/
             if (packet_count==0)
             {
-               st = process_header(&op, &rate, &channels, &preskip, &gain, quiet);
+               st = process_header(&op, &rate, &channels, &preskip, &gain, &streams, quiet);
                if(shapemem.a_buf)
                  free(shapemem.a_buf);
                if(shapemem.b_buf)
@@ -726,6 +742,17 @@
                   }
                   frame_size = ret;
 
+                  if(frange!=NULL){
+                    OpusDecoder *od;
+                    opus_uint32 rngs[streams];
+                    for(i=0;i<streams;i++){
+                      ret=opus_multistream_decoder_ctl(st,OPUS_MULTISTREAM_GET_DECODER_STATE(i,&od));
+                      ret=opus_decoder_ctl(od,OPUS_GET_FINAL_RANGE(&rngs[i]));
+                    }
+                    save_range(frange,frame_size*(48000/48000/*decoding_rate*/),op.packet,op.bytes,
+                               rngs,streams);
+                  }
+
                   /* Apply header gain */
                   for (i=0;i<frame_size*channels;i++)
                      output[i] *= gain;
@@ -817,6 +844,8 @@
    if(shapemem.b_buf)free(shapemem.b_buf);
 
    if(output)free(output);
+
+   if(frange)fclose(frange);
 
    if (close_in)
       fclose(fin);
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -43,14 +43,14 @@
 #define snprintf _snprintf
 #endif
 
-#include "opus.h"
-#include "opus_multistream.h"
-#include "opus_header.h"
+#include <opus.h>
+#include <opus_multistream.h>
 #include <ogg/ogg.h>
 #include "wav_io.h"
 
 #include "opus_header.h"
 #include "opusenc.h"
+#include "diag_range.h"
 
 #if defined WIN32 || defined _WIN32
 /* We need the following two to set stdout to binary */
@@ -146,180 +146,7 @@
   printf(" --raw-endianness n 1 for bigendian, 0 for little (defaults to 0)\n");
 }
 
-/*This is some non-exported code copied wholesale from libopus.
- *Normal programs shouldn't need these functions, but we use them here
- *to parse deep inside multichannel packets in order to get diagnostic
- *data for save-range. If you're thinking about copying it and you aren't
- *making an opus stream diagnostic tool, you're probably doing something
- *wrong.*/
-static int parse_size(const unsigned char *data, opus_int32 len, short *size)
-{
-   if (len<1)
-   {
-      *size = -1;
-      return -1;
-   } else if (data[0]<252)
-   {
-      *size = data[0];
-      return 1;
-   } else if (len<2)
-   {
-      *size = -1;
-      return -1;
-   } else {
-      *size = 4*data[1] + data[0];
-      return 2;
-   }
-}
 
-static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
-      int self_delimited, unsigned char *out_toc,
-      const unsigned char *frames[48], short size[48], int *payload_offset)
-{
-   int i, bytes;
-   int count;
-   int cbr;
-   unsigned char ch, toc;
-   int framesize;
-   int last_size;
-   const unsigned char *data0 = data;
-
-   if (size==NULL)
-      return OPUS_BAD_ARG;
-
-   framesize = opus_packet_get_samples_per_frame(data, 48000);
-
-   cbr = 0;
-   toc = *data++;
-   len--;
-   last_size = len;
-   switch (toc&0x3)
-   {
-   /* One frame */
-   case 0:
-      count=1;
-      break;
-   /* Two CBR frames */
-   case 1:
-      count=2;
-      cbr = 1;
-      if (!self_delimited)
-      {
-         if (len&0x1)
-            return OPUS_INVALID_PACKET;
-         size[0] = last_size = len/2;
-      }
-      break;
-   /* Two VBR frames */
-   case 2:
-      count = 2;
-      bytes = parse_size(data, len, size);
-      len -= bytes;
-      if (size[0]<0 || size[0] > len)
-         return OPUS_INVALID_PACKET;
-      data += bytes;
-      last_size = len-size[0];
-      break;
-   /* Multiple CBR/VBR frames (from 0 to 120 ms) */
-   case 3:
-      if (len<1)
-         return OPUS_INVALID_PACKET;
-      /* Number of frames encoded in bits 0 to 5 */
-      ch = *data++;
-      count = ch&0x3F;
-      if (count <= 0 || framesize*count > 5760)
-         return OPUS_INVALID_PACKET;
-      len--;
-      /* Padding flag is bit 6 */
-      if (ch&0x40)
-      {
-         int padding=0;
-         int p;
-         do {
-            if (len<=0)
-               return OPUS_INVALID_PACKET;
-            p = *data++;
-            len--;
-            padding += p==255 ? 254: p;
-         } while (p==255);
-         len -= padding;
-      }
-      if (len<0)
-         return OPUS_INVALID_PACKET;
-      /* VBR flag is bit 7 */
-      cbr = !(ch&0x80);
-      if (!cbr)
-      {
-         /* VBR case */
-         last_size = len;
-         for (i=0;i<count-1;i++)
-         {
-            bytes = parse_size(data, len, size+i);
-            len -= bytes;
-            if (size[i]<0 || size[i] > len)
-               return OPUS_INVALID_PACKET;
-            data += bytes;
-            last_size -= bytes+size[i];
-         }
-         if (last_size<0)
-            return OPUS_INVALID_PACKET;
-      } else if (!self_delimited)
-      {
-         /* CBR case */
-         last_size = len/count;
-         if (last_size*count!=len)
-            return OPUS_INVALID_PACKET;
-         for (i=0;i<count-1;i++)
-            size[i] = last_size;
-      }
-      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_INVALID_PACKET;
-      data += bytes;
-      /* For CBR packets, apply the size to all the frames. */
-      if (cbr)
-      {
-         if (size[count-1]*count > len)
-            return OPUS_INVALID_PACKET;
-         for (i=0;i<count-1;i++)
-            size[i] = size[count-1];
-      } else if(size[count-1] > last_size)
-         return OPUS_INVALID_PACKET;
-   } else
-   {
-      /* 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
-         1275. Reject them here.*/
-      if (last_size > 1275)
-         return OPUS_INVALID_PACKET;
-      size[count-1] = last_size;
-   }
-
-   if (frames)
-   {
-      for (i=0;i<count;i++)
-      {
-         frames[i] = data;
-         data += size[i];
-      }
-   }
-
-   if (out_toc)
-      *out_toc = toc;
-
-   if (payload_offset)
-      *payload_offset = data-data0;
-
-   return count;
-}
-
-
 static inline void print_time(double seconds)
 {
   long long hours, minutes;
@@ -925,33 +752,14 @@
     min_bytes=IMIN(nbBytes,min_bytes);
 
     if(frange!=NULL){
-      const unsigned char *subpkt;
-      int parse_size;
-      static const char *bw_strings[5]={"NB","MB","WB","SWB","FB"};
-      static const char *mode_strings[3]={"LP","HYB","MDCT"};
       OpusEncoder *oe;
-      opus_uint32 rng;
-      fprintf(frange,"%d, %d, ",frame_size*(48000/coding_rate),nbBytes);
-      subpkt=packet;
-      parse_size=nbBytes;
+      opus_uint32 rngs[header.nb_streams];
       for(i=0;i<header.nb_streams;i++){
-        int payload_offset;
-        const unsigned char *frames[48];
-        unsigned char toc;
-        short size[48];
-        payload_offset=0;
-        opus_packet_parse_impl(subpkt,parse_size,i+1!=header.nb_streams,
-          &toc,frames,size,&payload_offset);
-        fprintf(frange,"[%d, %s, %s, %c, %d",payload_offset,
-           mode_strings[((((subpkt[0]>>3)+48)&92)+4)>>5],
-           bw_strings[opus_packet_get_bandwidth(subpkt)-OPUS_BANDWIDTH_NARROWBAND],
-           subpkt[0]&4?'S':'M',opus_packet_get_samples_per_frame(subpkt,48000));
         ret=opus_multistream_encoder_ctl(st,OPUS_MULTISTREAM_GET_ENCODER_STATE(i,&oe));
-        ret=opus_encoder_ctl(oe,OPUS_GET_FINAL_RANGE(&rng));
-        fprintf(frange,", %llu]%s",(unsigned long long)rng,i+1==header.nb_streams?"\n":", ");
-        parse_size-=payload_offset;
-        subpkt+=payload_offset;
+        ret=opus_encoder_ctl(oe,OPUS_GET_FINAL_RANGE(&rngs[i]));
       }
+      save_range(frange,frame_size*(48000/coding_rate),packet,nbBytes,
+                 rngs,header.nb_streams);
     }
 
     nb_samples = inopt.read_samples(inopt.readdata,input,frame_size);