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);