ref: e4c9f9150c1a5ff5e026d1935cffdcd153cbecc9
parent: ca2f5b1c1b05a8461267c454e7d8b0b80c5dc434
author: Gregory Maxwell <greg@xiph.org>
date: Wed May 23 14:49:51 EDT 2012
opusdec: Correct lengths for resampled outputs; chaining.
--- a/src/opusdec.c
+++ b/src/opusdec.c
@@ -441,7 +441,7 @@
if (!quiet)
{
- fprintf(stderr, "Decoding %d Hz audio", *rate);
+ fprintf(stderr, "Decoding %d Hz %saudio", *rate, *rate!=(int)header.input_sample_rate?"(forced) ":"");
fprintf(stderr, " (%d channel%s)",*channels,*channels>1?"s":"");
if(header.version!=1)fprintf(stderr, ", Header v%d",header.version);
fprintf(stderr, "\n");
@@ -451,9 +451,11 @@
return st;
}
-void audio_write(float *pcm, int channels, int frame_size, FILE *fout, SpeexResamplerState *resampler, int *skip, shapestate *shapemem, int file)
+opus_int64 audio_write(float *pcm, int channels, int frame_size, FILE *fout, SpeexResamplerState *resampler,
+ int *skip, shapestate *shapemem, int file, opus_int64 maxout)
{
- int i,tmp_skip;
+ opus_int64 sampout=0;
+ int i,ret,tmp_skip;
unsigned out_len;
short out[MAX_FRAME_SIZE*channels];
float buf[MAX_FRAME_SIZE*channels];
@@ -460,27 +462,26 @@
float *output;
do {
+ if (skip){
+ tmp_skip = (*skip>frame_size) ? (int)frame_size : *skip;
+ *skip -= tmp_skip;
+ } else {
+ tmp_skip = 0;
+ }
if (resampler){
output=buf;
unsigned in_len;
- in_len = frame_size;
- out_len = 1024;
- speex_resampler_process_interleaved_float(resampler, pcm, &in_len, buf, &out_len);
+ in_len = frame_size-tmp_skip;
+ out_len = 1024<maxout?1024:maxout;
+ speex_resampler_process_interleaved_float(resampler, pcm+channels*tmp_skip, &in_len, buf, &out_len);
pcm += channels*in_len;
frame_size -= in_len;
} else {
- output=pcm;
- out_len=frame_size;
+ output=pcm+channels*tmp_skip;
+ out_len=frame_size-tmp_skip;
frame_size=0;
}
- if (skip){
- tmp_skip = (*skip>(int)out_len) ? (int)out_len : *skip;
- *skip -= tmp_skip;
- } else {
- tmp_skip = 0;
- }
-
/*Convert to short and save to output file*/
if (shapemem){
shape_dither_toshort(shapemem,out,output,out_len,channels);
@@ -493,8 +494,14 @@
out[i]=le_short(out[i]);
}
- fwrite(out+tmp_skip*channels, 2, (out_len-tmp_skip)*channels, fout);
- } while (frame_size != 0);
+ if(maxout>0)
+ {
+ ret=fwrite(out, 2*channels, out_len<maxout?out_len:maxout, fout);
+ sampout+=ret;
+ maxout-=ret;
+ }
+ } while (frame_size>0 && maxout>0);
+ return sampout;
}
int main(int argc, char **argv)
@@ -506,11 +513,12 @@
float *output;
int frame_size=0;
OpusMSDecoder *st=NULL;
- int packet_count=0;
+ opus_int64 packet_count=0;
+ int total_links=0;
int stream_init = 0;
int quiet = 0;
ogg_int64_t page_granule=0;
- ogg_int64_t decoded=0;
+ ogg_int64_t link_out=0;
struct option long_options[] =
{
{"help", no_argument, NULL, 0},
@@ -532,13 +540,15 @@
int print_bitrate=0;
int close_in=0;
int eos=0;
- int audio_size=0;
+ ogg_int64_t audio_size=0;
float loss_percent=-1;
int channels=-1;
int rate=0;
int wav_format=0;
int preskip=0;
- int opus_serialno = -1;
+ int gran_offset=0;
+ int has_opus_stream=0;
+ ogg_int32_t opus_serialno;
int dither=1;
shapestate shapemem;
SpeexResamplerState *resampler=NULL;
@@ -683,29 +693,35 @@
ogg_stream_pagein(&os, &og);
page_granule = ogg_page_granulepos(&og);
/*Extract all available packets*/
- while (!eos && ogg_stream_packetout(&os, &op) == 1)
+ while (ogg_stream_packetout(&os, &op) == 1)
{
- if (op.bytes>=8 && !memcmp(op.packet, "OpusHead", 8)) {
- opus_serialno = os.serialno;
+ if (op.b_o_s && op.bytes>=8 && !memcmp(op.packet, "OpusHead", 8)) {
+ if(!has_opus_stream)
+ {
+ opus_serialno = os.serialno;
+ has_opus_stream = 1;
+ link_out = 0;
+ packet_count = 0;
+ eos = 0;
+ total_links++;
+ } else {
+ fprintf(stderr,"Warning: ignoring opus stream %lld\n",(long long)os.serialno);
+ }
}
- if (opus_serialno == -1 || os.serialno != opus_serialno)
+ if (!has_opus_stream || os.serialno != opus_serialno)
break;
/*If first packet, process as OPUS header*/
if (packet_count==0)
{
st = process_header(&op, &rate, &channels, &preskip, &gain, &streams, quiet);
- if(shapemem.a_buf)
- free(shapemem.a_buf);
- if(shapemem.b_buf)
- free(shapemem.b_buf);
- shapemem.a_buf=calloc(channels,sizeof(float)*4);
- shapemem.b_buf=calloc(channels,sizeof(float)*4);
- shapemem.fs=rate;
- if(output)
- free(output);
- output=malloc(sizeof(float)*MAX_FRAME_SIZE*channels);
- /* Converting preskip to output sampling rate */
- preskip = preskip*(rate/48000.);
+ gran_offset=preskip;
+ if(!shapemem.a_buf)
+ {
+ shapemem.a_buf=calloc(channels,sizeof(float)*4);
+ shapemem.b_buf=calloc(channels,sizeof(float)*4);
+ shapemem.fs=rate;
+ }
+ if(!output)output=malloc(sizeof(float)*MAX_FRAME_SIZE*channels);
if (!st)
exit(1);
if (rate != 48000)
@@ -716,8 +732,7 @@
fprintf(stderr, "resampler error: %s\n", speex_resampler_strerror(err));
speex_resampler_skip_zeros(resampler);
}
- fout = out_file_open(outFile, rate, &channels);
-
+ if(!fout)fout=out_file_open(outFile, rate, &channels);
} else if (packet_count==1)
{
if (!quiet)
@@ -728,102 +743,91 @@
lost=1;
/*End of stream condition*/
- if (op.e_o_s && os.serialno == opus_serialno) /* don't care for anything except opus eos */
- eos=1;
+ if (op.e_o_s && os.serialno == opus_serialno)eos=1; /* don't care for anything except opus eos */
+ int ret;
+ opus_int64 outsamp;
+ /*Decode frame*/
+ if (!lost)
+ ret = opus_multistream_decode_float(st, (unsigned char*)op.packet, op.bytes, output, MAX_FRAME_SIZE, 0);
+ else
+ ret = opus_multistream_decode_float(st, NULL, 0, output, MAX_FRAME_SIZE, 0);
+
+ if (ret<0)
{
- int trunc;
- int ret;
- /*Decode frame*/
- if (!lost)
- ret = opus_multistream_decode_float(st, (unsigned char*)op.packet, op.bytes, output, MAX_FRAME_SIZE, 0);
- else
- ret = opus_multistream_decode_float(st, NULL, 0, output, MAX_FRAME_SIZE, 0);
+ fprintf (stderr, "Decoding error: %s\n", opus_strerror(ret));
+ break;
+ }
+ frame_size = ret;
- /*for (i=0;i<frame_size*channels;i++)
- printf ("%d\n", (int)output[i]);*/
+ 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);
+ }
- if (ret<0)
- {
- fprintf (stderr, "Decoding error: %s\n", opus_strerror(ret));
- break;
- }
- frame_size = ret;
+ /* Apply header gain */
+ for (i=0;i<frame_size*channels;i++)
+ output[i] *= gain;
- 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;
-
- if (print_bitrate) {
- opus_int32 tmp=op.bytes;
- char ch=13;
- fputc (ch, stderr);
- fprintf (stderr, "Bitrate in use: %d bytes/packet ", tmp);
- }
- decoded += frame_size;
- if (decoded > page_granule)
- trunc = decoded-page_granule;
- else
- trunc = 0;
- {
- int new_frame_size;
- if (trunc > frame_size)
- trunc = frame_size;
- new_frame_size = frame_size - trunc;
- audio_write(output, channels, new_frame_size, fout, resampler, &preskip, dither?&shapemem:0, strlen(outFile)!=0);
- audio_size+=sizeof(short)*new_frame_size*channels;
- }
+ if (print_bitrate) {
+ opus_int32 tmp=op.bytes;
+ char ch=13;
+ fputc (ch, stderr);
+ fprintf (stderr, "Bitrate in use: %d bytes/packet ", tmp);
}
+ outsamp=audio_write(output, channels, frame_size, fout, resampler, &preskip, dither?&shapemem:0, strlen(outFile)!=0,((page_granule-gran_offset)*rate/48000)-link_out);
+ link_out+=outsamp;
+ audio_size+=sizeof(short)*outsamp*channels;
}
packet_count++;
}
+ /* Drain the resampler */
+ if(eos && resampler)
+ {
+ float zeros[100];
+ int drain;
+
+ for (i=0;i<100;i++)zeros[i] = 0;
+ drain = speex_resampler_get_input_latency(resampler);
+ do {
+ opus_int64 outsamp;
+ int tmp = drain;
+ if (tmp > 100)
+ tmp = 100;
+ outsamp=audio_write(zeros, channels, tmp, fout, resampler, NULL, &shapemem, strlen(outFile)==0, ((page_granule-gran_offset)*rate/48000)-link_out);
+ link_out+=outsamp;
+ audio_size+=sizeof(short)*outsamp*channels;
+ drain -= tmp;
+ } while (drain>0);
+ speex_resampler_destroy(resampler);
+ }
+ if(eos)
+ {
+ has_opus_stream=0;
+ if(st)opus_multistream_decoder_destroy(st);
+ }
}
if (feof(fin))
break;
-
}
- /* Drain the resampler */
- if (resampler)
+ if (fout && wav_format && audio_size<0x7FFFFFFF)
{
- int i;
- float zeros[200];
- int drain;
-
- for (i=0;i<200;i++)
- zeros[i] = 0;
- drain = speex_resampler_get_input_latency(resampler);
- do {
- int tmp = drain;
- if (tmp > 100)
- tmp = 100;
- audio_write(zeros, channels, tmp, fout, resampler, NULL, &shapemem, strlen(outFile)==0);
- drain -= tmp;
- } while (drain>0);
- }
-
- if (fout && wav_format)
- {
if (fseek(fout,4,SEEK_SET)==0)
{
int tmp;
tmp = le_int(audio_size+36);
- fwrite(&tmp,4,1,fout);
+ if(fwrite(&tmp,4,1,fout)!=1)fprintf(stderr,"Error writing end length.\n");
if (fseek(fout,32,SEEK_CUR)==0)
{
tmp = le_int(audio_size);
- fwrite(&tmp,4,1,fout);
+ if(fwrite(&tmp,4,1,fout)!=1)fprintf(stderr,"Error writing header length.\n");
} else
{
fprintf (stderr, "First seek worked, second didn't\n");
@@ -833,12 +837,8 @@
}
}
- if (st)
- {
- opus_multistream_decoder_destroy(st);
- } else {
- fprintf (stderr, "This doesn't look like a Opus file\n");
- }
+ if(!total_links)fprintf (stderr, "This doesn't look like a Opus file\n");
+
if (stream_init)
ogg_stream_clear(&os);
ogg_sync_clear(&oy);
@@ -850,8 +850,6 @@
if(shapemem.a_buf)free(shapemem.a_buf);
if(shapemem.b_buf)free(shapemem.b_buf);
-
- if(resampler)speex_resampler_destroy(resampler);
if(output)free(output);
--
⑨