ref: 665f3e69b0477861c48257b1d2d691518ddfbbf0
parent: 768a9c773c9847886b802f6fb3fa0b1df74ed119
author: Gregory Maxwell <greg@xiph.org>
date: Sat Jul 21 07:50:53 EDT 2012
Add some more explanatory comments to opusdec.c.
--- a/src/opusdec.c
+++ b/src/opusdec.c
@@ -503,7 +503,9 @@
if(header.gain!=0 || manual_gain!=0)
{
- /*Gain API added in a newer libopus version..*/
+ /*Gain API added in a newer libopus version, if we don't have it
+ we apply the gain ourselves. We also add in a user provided
+ manual gain at the same time.*/
int gainadj = (int)(manual_gain*256.)+header.gain;
#ifdef OPUS_SET_GAIN
err=opus_multistream_decoder_ctl(st,OPUS_SET_GAIN(gainadj));
@@ -753,12 +755,10 @@
close_in=1;
}
-
/*Init Ogg data struct*/
ogg_sync_init(&oy);
/*Main decoding loop*/
-
while (1)
{
char *data;
@@ -786,6 +786,8 @@
/*Extract all available packets*/
while (ogg_stream_packetout(&os, &op) == 1)
{
+ /*OggOpus streams are identified by a magic string in the initial
+ stream header.*/
if (op.b_o_s && op.bytes>=8 && !memcmp(op.packet, "OpusHead", 8)) {
if(!has_opus_stream)
{
@@ -801,13 +803,18 @@
}
if (!has_opus_stream || os.serialno != opus_serialno)
break;
- /*If first packet, process as OPUS header*/
+ /*If first packet in a logical stream, process the Opus header*/
if (packet_count==0)
{
st = process_header(&op, &rate, &mapping_family, &channels, &preskip, &gain, manual_gain, &streams, wav_format, quiet);
if (!st)
exit(1);
+
+ /*Remember how many samples at the front we were told to skip
+ so that we can adjust the timestamp counting.*/
gran_offset=preskip;
+
+ /*Setup the memory for the dithered output*/
if(!shapemem.a_buf)
{
shapemem.a_buf=calloc(channels,sizeof(float)*4);
@@ -815,6 +822,11 @@
shapemem.fs=rate;
}
if(!output)output=malloc(sizeof(float)*MAX_FRAME_SIZE*channels);
+
+ /*Normal players should just play at 48000 or their maximum rate,
+ as described in the OggOpus spec. But for commandline tools
+ like opusdec it can be desirable to exactly preserve the original
+ sampling rate and duration, so we have a resampler here.*/
if (rate != 48000)
{
int err;
@@ -839,12 +851,12 @@
/*End of stream condition*/
if (op.e_o_s && os.serialno == opus_serialno)eos=1; /* don't care for anything except opus eos */
- /*Decode frame*/
if (!lost){
+ /*Decode Opus packet*/
ret = opus_multistream_decode_float(st, (unsigned char*)op.packet, op.bytes, output, MAX_FRAME_SIZE, 0);
} else {
/*Extract the original duration.
- Normally you wouldn't have it for a lost frame, but normally the
+ Normally you wouldn't have it for a lost packet, but normally the
transports used on lossy channels will effectively tell you.
This avoids opusdec squaking when the decoded samples and
granpos mismatches.*/
@@ -858,6 +870,7 @@
if(spp>0)lost_size=spp;
}
}
+ /*Invoke packet loss concealment.*/
ret = opus_multistream_decode_float(st, NULL, 0, output, lost_size, 0);
}
@@ -868,6 +881,7 @@
}
frame_size = ret;
+ /*If we're collecting --save-range debugging data, collect it now.*/
if(frange!=NULL){
OpusDecoder *od;
opus_uint32 rngs[256];
@@ -879,10 +893,16 @@
rngs,streams);
}
- /* Apply header gain */
- for (i=0;i<frame_size*channels;i++)
- output[i] *= gain;
+ /*Apply header gain, if we're not using an opus library new
+ enough to do this internally.*/
+ if (gain!=0){
+ for (i=0;i<frame_size*channels;i++)
+ output[i] *= gain;
+ }
+ /*This handles making sure that our output duration respects
+ the final end-trim by not letting the output sample count
+ get ahead of the granpos indicated value.*/
maxout=((page_granule-gran_offset)*rate/48000)-link_out;
outsamp=audio_write(output, channels, frame_size, fout, resampler, &preskip, dither?&shapemem:0, strlen(outFile)!=0,0>maxout?0:maxout);
link_out+=outsamp;
@@ -890,7 +910,7 @@
}
packet_count++;
}
- /* Drain the resampler */
+ /*We're done, drain the resampler if we were using it.*/
if(eos && resampler)
{
float *zeros;
@@ -923,6 +943,7 @@
break;
}
+ /*If we were writing wav, go set the duration.*/
if (fout && wav_format>=0 && audio_size<0x7FFFFFFF)
{
if (fseek(fout,4,SEEK_SET)==0)