shithub: opus-tools

Download patch

ref: 29724d050411fb5794c493e30f9324b52da6bdd3
parent: 380f6e642d66978365ce93a32f6466773a438240
author: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
date: Wed Aug 3 13:21:45 EDT 2011

Fixes granulepos computation in opusenc and ensures there's enough audio

--- a/src/opusdec.c
+++ b/src/opusdec.c
@@ -605,6 +605,8 @@
 
                      new_frame_size = frame_size - preskip;
                      frame_offset = preskip;
+                     /* FIXME: This is not the ideal way to do gapless. It would be best to do the skip
+                        *after* resampling */
                      if (new_frame_size>0)
                      {
                         audio_write(out+frame_offset*channels, channels, new_frame_size, fout, resampler);
--- a/src/opusenc.c
+++ b/src/opusenc.c
@@ -1,5 +1,5 @@
-/* Copyright (c) 2002-2010 Jean-Marc Valin
-   Copyright (c) 2007-2010 Xiph.Org Foundation
+/* Copyright (c) 2002-2011 Jean-Marc Valin
+   Copyright (c) 2007-2011 Xiph.Org Foundation
    Copyright (c) 2008-2010 Gregory Maxwell
    File: opusenc.c
 
@@ -76,34 +76,42 @@
 #define IMAX(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum int value.   */
 
 /* Convert input audio bits, endians and channels */
-static int read_samples_pcm(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, opus_int32 *size)
-{   
+static int read_samples_pcm(FILE *fin,int frame_size, int bits, int channels, 
+                            int lsb, short * input, char *buff, opus_int32 *size,
+                            int *extra_samples)
+{
    short s[MAX_FRAME_SIZE];
    unsigned char *in = (unsigned char*)s;
    int i;
    int nb_read;
+   int extra=0;
 
-   if (size && *size<=0)
-   {
-      return 0;
-   }
    /*Read input audio*/
-   if (size)
-      *size -= bits/8*channels*frame_size;
    if (buff)
    {
       for (i=0;i<12;i++)
          in[i]=buff[i];
-      nb_read = fread(in+12,1,bits/8*channels*frame_size-12, fin) + 12;
+      nb_read = fread(in+12, 1, bits/8*channels*frame_size-12, fin) + 12;
       if (size)
          *size += 12;
    } else {
-      nb_read = fread(in,1,bits/8*channels* frame_size, fin);
+      int tmp = frame_size;
+      if (size && tmp > *size)
+         tmp = *size;
+      nb_read = fread(in, 1, bits/8*channels* tmp, fin);
    }
    nb_read /= bits/8*channels;
 
+   /* Make sure to return *extra_samples zeros at the end */
+   if (nb_read<frame_size)
+   {
+      extra = frame_size-nb_read;
+      if (extra > *extra_samples)
+         extra = *extra_samples;
+      *extra_samples -= extra;
+   }
    /*fprintf (stderr, "%d\n", nb_read);*/
-   if (nb_read==0)
+   if (nb_read==0 && extra==0)
       return 0;
 
    if(bits==8)
@@ -137,13 +145,21 @@
       input[i]=0;
    }
 
-
+   nb_read += extra;
+   if (size)
+   {
+      int tmp = bits/8*channels*nb_read;
+      if (tmp > *size)
+         *size = 0;
+      else
+         *size -= tmp;
+   }
    return nb_read;
 }
 
 static int read_samples(FILE *fin,int frame_size, int bits, int channels, 
                         int lsb, short * input, char *buff, opus_int32 *size,
-                        SpeexResamplerState *resampler)
+                        SpeexResamplerState *resampler, int *extra_samples)
 {
    if (resampler)
    {
@@ -156,9 +172,8 @@
          int i;
          int reading, ret;
          unsigned in_len, out_len;
-         reading = 1024-channels*inbuf;
-         ret = read_samples_pcm(fin, reading, bits, channels, lsb, pcmbuf+inbuf*channels, buff, size);
-         /* FIXME: We should drain the buffer before stopping */
+         reading = 1024-inbuf;
+         ret = read_samples_pcm(fin, reading, bits, channels, lsb, pcmbuf+inbuf*channels, buff, size, extra_samples);
          inbuf += ret;
          in_len = inbuf;
          out_len = frame_size-out_samples;
@@ -176,7 +191,7 @@
       }
       return out_samples;
    } else {
-      return read_samples_pcm(fin, frame_size, bits, channels, lsb, input, buff, size);
+      return read_samples_pcm(fin, frame_size, bits, channels, lsb, input, buff, size, extra_samples);
    }
 }
 
@@ -300,6 +315,7 @@
    int complexity=-127;
    const char *opus_version;
    SpeexResamplerState *resampler=NULL;
+   int extra_samples;
 
    opus_version = opus_get_version_string();
    /*Process command-line options*/
@@ -436,7 +452,8 @@
    }
 
    {
-      fread(first_bytes, 1, 12, fin);
+      int ret;
+      ret = fread(first_bytes, 1, 12, fin);
       if (strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0)
       {
          if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1)
@@ -457,11 +474,12 @@
       /*speex_resampler_skip_zeros(resampler);*/
    }
    if (bitrate<=0.005)
+   {
      if (chan==1)
        bitrate=64.0;
      else
        bitrate=128.0;
-     
+   }
    bytes_per_packet = MAX_FRAME_BYTES;
    
    snprintf(vendor_string, sizeof(vendor_string), "%s\n",opus_get_version_string());
@@ -471,17 +489,21 @@
    st = opus_encoder_create(48000, chan, OPUS_APPLICATION_AUDIO);
 
    header.channels = chan;
-   opus_encoder_ctl(st, OPUS_GET_LOOKAHEAD(&header.preskip));
+   opus_encoder_ctl(st, OPUS_GET_LOOKAHEAD(&lookahead));
+   header.preskip = lookahead;
    if (resampler)
       header.preskip += speex_resampler_get_output_latency(resampler);
    header.multi_stream = 0;
    header.sample_rate = rate;
    
+   /* Extra samples that need to be read to compensate for the pre-skip */
+   extra_samples = (int)header.preskip * (rate/48000.);
    {
       char *st_string="mono";
       if (chan==2)
          st_string="stereo";
       if (!quiet)
+      {
          if (with_cbr)
            fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet, CBR)\n",
                header.sample_rate/1000., st_string, frame_size/48., bitrate, bytes_per_packet);
@@ -488,6 +510,7 @@
          else
            fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet maximum)\n",
                header.sample_rate/1000., st_string, frame_size/48., bitrate, bytes_per_packet);
+      }
    }
 
    {
@@ -593,16 +616,16 @@
 
    if (!wave_input)
    {
-      nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL, resampler);
+      nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL, resampler, &extra_samples);
    } else {
-      nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size, resampler);
+      nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size, resampler, &extra_samples);
    }
    if (nb_samples==0)
       eos=1;
    total_samples += nb_samples;
-   nb_encoded = -lookahead;
+   nb_encoded = -header.preskip;
    /*Main encoding loop (one frame per iteration)*/
-   while (!eos || total_samples>nb_encoded)
+   while (!eos)
    {
       id++;
       /*Encode current frame*/
@@ -619,9 +642,9 @@
 
       if (wave_input)
       {
-         nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size, resampler);
+         nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size, resampler, &extra_samples);
       } else {
-         nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL, resampler);
+         nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL, resampler, &extra_samples);
       }
       if (nb_samples==0)
       {
@@ -641,7 +664,7 @@
          op.e_o_s = 1;
       else
          op.e_o_s = 0;
-      op.granulepos = (id+1)*frame_size-lookahead;
+      op.granulepos = (id+1)*frame_size;
       if (op.granulepos>total_samples)
          op.granulepos = total_samples;
       op.packetno = 2+id;