* src/audio_output/filters.c, src/audio_output/input.c, include/aout_internal.h,
authorGildas Bazin <gbazin@videolan.org>
Mon, 11 Nov 2002 22:27:01 +0000 (22:27 +0000)
committerGildas Bazin <gbazin@videolan.org>
Mon, 11 Nov 2002 22:27:01 +0000 (22:27 +0000)
   modules/audio_filter/resampler/*: Changes that allow the resamplers to set
   the start and end date of the frame it outputs.
   This allows us for instance to output a smaller frame than what we should, and
   keep the rest of the data to compute the resampling of the next frame.
   In short, we can implement much more complex resampling algorithms than before.

* modules/audio_filter/resampler/linear.c: rewrote the linear resampler. The audio
   quality doesn't seem to be better than the ugly resampler, maybe I shouldn't
   have wasted my time on this...

include/aout_internal.h
modules/audio_filter/resampler/linear.c
modules/audio_filter/resampler/trivial.c
modules/audio_filter/resampler/ugly.c
src/audio_output/filters.c
src/audio_output/input.c

index cc788d5..3db013e 100644 (file)
@@ -2,7 +2,7 @@
  * aout_internal.h : internal defines for audio output
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: aout_internal.h,v 1.31 2002/11/11 14:39:11 sam Exp $
+ * $Id: aout_internal.h,v 1.32 2002/11/11 22:27:00 gbazin Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -112,6 +112,7 @@ typedef struct aout_filter_t
                                          struct aout_buffer_t *,
                                          struct aout_buffer_t * );
     vlc_bool_t              b_in_place;
+    vlc_bool_t              b_reinit;
 } aout_filter_t;
 
 /*****************************************************************************
index c32c6d5..f5cf253 100644 (file)
@@ -1,10 +1,11 @@
 /*****************************************************************************
- * ugly.c : linear interpolation resampler
+ * linear.c : linear interpolation resampler
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: linear.c,v 1.3 2002/11/11 19:16:21 gbazin Exp $
+ * $Id: linear.c,v 1.4 2002/11/11 22:27:01 gbazin Exp $
  *
- * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
+ * Authors: Gildas Bazin <gbazin@netcourrier.com>
+ *          Sigmund Augdal <sigmunau@idi.ntnu.no>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Local prototypes
  *****************************************************************************/
 static int  Create    ( vlc_object_t * );
-
+static void Close     ( vlc_object_t * );
 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
                         aout_buffer_t * );
 
+/*****************************************************************************
+ * Local structures
+ *****************************************************************************/
+struct aout_filter_sys_t
+{
+    int32_t *p_prev_sample;       /* this filter introduces a 1 sample delay */
+
+    int     i_remainder;                     /* remainder of previous sample */
+
+    audio_date_t end_date;
+};
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
 vlc_module_begin();
     set_description( _("audio filter for linear interpolation resampling") );
-    set_capability( "audio filter", 0 );
-    set_callbacks( Create, NULL );
+    set_capability( "audio filter", 10 );
+    set_callbacks( Create, Close );
 vlc_module_end();
 
 /*****************************************************************************
- * Create: allocate ugly resampler
+ * Create: allocate linear resampler
  *****************************************************************************/
 static int Create( vlc_object_t *p_this )
 {
@@ -63,12 +76,37 @@ static int Create( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
+    /* Allocate the memory needed to store the module's structure */
+    p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
+    if( p_filter->p_sys == NULL )
+    {
+        msg_Err( p_filter, "out of memory" );
+        return VLC_ENOMEM;
+    }
+    p_filter->p_sys->p_prev_sample = malloc( p_filter->input.i_channels
+                                            * sizeof(int32_t) );
+    if( p_filter->p_sys->p_prev_sample == NULL )
+    {
+        msg_Err( p_filter, "out of memory" );
+        return VLC_ENOMEM;
+    }
+
     p_filter->pf_do_work = DoWork;
     p_filter->b_in_place = VLC_FALSE;
 
     return VLC_SUCCESS;
 }
 
+/*****************************************************************************
+ * Close: free our resources
+ *****************************************************************************/
+static void Close( vlc_object_t * p_this )
+{
+    aout_filter_t * p_filter = (aout_filter_t *)p_this;
+    free( p_filter->p_sys->p_prev_sample );
+    free( p_filter->p_sys );
+}
+
 /*****************************************************************************
  * DoWork: convert a buffer
  *****************************************************************************/
@@ -77,41 +115,82 @@ static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
 {
     float* p_in = (float*)p_in_buf->p_buffer;
     float* p_out = (float*)p_out_buf->p_buffer;
+    float* p_prev_sample = (float*)p_filter->p_sys->p_prev_sample;
 
     int i_nb_channels = aout_FormatNbChannels( &p_filter->input );
     int i_in_nb = p_in_buf->i_nb_samples;
-    int i_out_nb = i_in_nb * p_filter->output.i_rate
-                    / p_filter->input.i_rate;
-    int i_frame_bytes = i_nb_channels * sizeof(s32);
-    int i_in, i_chan, i_out = 0;
-    double f_step = (float)p_filter->input.i_rate / p_filter->output.i_rate;
-    float f_pos = 1;
-    
-    for( i_in = 0 ; i_in < i_in_nb - 1; i_in++ )
+    int i_chan, i_in, i_out = 0;
+
+    /* Take care of the previous input sample (if any) */
+    if( p_filter->b_reinit )
     {
-        f_pos--;
-        while( f_pos <= 1 )
+        p_filter->b_reinit = VLC_FALSE;
+       p_filter->p_sys->i_remainder = 0;
+        aout_DateInit( &p_filter->p_sys->end_date, p_filter->output.i_rate );
+    }
+    else
+    {
+        while( p_filter->p_sys->i_remainder < p_filter->output.i_rate )
         {
             for( i_chan = i_nb_channels ; i_chan ; )
             {
                 i_chan--;
-                p_out[i_chan] = p_in[i_chan] +
-                    ( p_in[i_chan + i_nb_channels] - p_in[i_chan] ) * f_pos;
-                i_out++;
+                p_out[i_chan] = p_prev_sample[i_chan];
+               p_out[i_chan] += ( (p_prev_sample[i_chan] - p_in[i_chan])
+                                  * p_filter->p_sys->i_remainder
+                                  / p_filter->output.i_rate );
             }
-            f_pos += f_step;
             p_out += i_nb_channels;
+           i_out++;
+
+            p_filter->p_sys->i_remainder += p_filter->input.i_rate;
         }
+        p_filter->p_sys->i_remainder -= p_filter->output.i_rate;
+    }
+
+    /* Take care of the current input samples (minus last one) */
+    for( i_in = 0; i_in < i_in_nb - 1; i_in++ )
+    {
+        while( p_filter->p_sys->i_remainder < p_filter->output.i_rate )
+        {
+            for( i_chan = i_nb_channels ; i_chan ; )
+            {
+                i_chan--;
+                p_out[i_chan] = p_in[i_chan];
+               p_out[i_chan] += ( (p_in[i_chan] -
+                   p_in[i_chan + i_nb_channels])
+                   * p_filter->p_sys->i_remainder / p_filter->output.i_rate );
+            }
+            p_out += i_nb_channels;
+           i_out++;
+
+            p_filter->p_sys->i_remainder += p_filter->input.i_rate;
+        }
+
         p_in += i_nb_channels;
+        p_filter->p_sys->i_remainder -= p_filter->output.i_rate;
     }
-    
-    if ( i_out != i_out_nb * i_nb_channels )
+
+    /* Backup the last input sample for next time */
+    for( i_chan = i_nb_channels ; i_chan ; )
     {
-        msg_Warn( p_aout, "mismatch in sample numbers: %d requested, "
-                  "%d generated", i_out_nb* i_nb_channels, i_out);
+        i_chan--;
+        p_prev_sample[i_chan] = p_in[i_chan];
     }
-                                              
-    p_out_buf->i_nb_samples = i_out_nb;
-    p_out_buf->i_nb_bytes = i_out_nb * i_frame_bytes;
-}
 
+    p_out_buf->i_nb_samples = i_out;
+    p_out_buf->start_date = p_in_buf->start_date;
+
+    if( p_in_buf->start_date !=
+       aout_DateGet( &p_filter->p_sys->end_date ) )
+    {
+        aout_DateSet( &p_filter->p_sys->end_date, p_in_buf->start_date );
+    }
+
+    p_out_buf->end_date = aout_DateIncrement( &p_filter->p_sys->end_date,
+                                              p_out_buf->i_nb_samples );
+
+    p_out_buf->i_nb_bytes = p_out_buf->i_nb_samples *
+        i_nb_channels * sizeof(int32_t);
+
+}
index 11752df..47486d9 100644 (file)
@@ -2,7 +2,7 @@
  * trivial.c : trivial resampler (skips samples or pads with zeroes)
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: trivial.c,v 1.7 2002/10/15 23:10:54 massiot Exp $
+ * $Id: trivial.c,v 1.8 2002/11/11 22:27:01 gbazin Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -80,24 +80,27 @@ static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
     int i_in_nb = p_in_buf->i_nb_samples;
     int i_out_nb = i_in_nb * p_filter->output.i_rate
                     / p_filter->input.i_rate;
-    int i_frame_bytes = aout_FormatNbChannels( &p_filter->input ) * sizeof(s32);
+    int i_sample_bytes = aout_FormatNbChannels( &p_filter->input )
+                          * sizeof(int32_t);
 
     if ( p_out_buf != p_in_buf )
     {
         /* For whatever reason the buffer allocator decided to allocate
          * a new buffer. Currently, this never happens. */
         p_aout->p_vlc->pf_memcpy( p_out_buf->p_buffer, p_in_buf->p_buffer,
-                                  __MIN(i_out_nb, i_in_nb) * i_frame_bytes );
+                                  __MIN(i_out_nb, i_in_nb) * i_sample_bytes );
     }
 
     if ( i_out_nb > i_in_nb )
     {
         /* Pad with zeroes. */
-        memset( p_out_buf->p_buffer + i_in_nb * i_frame_bytes,
-                0, (i_out_nb - i_in_nb) * i_frame_bytes );
+        memset( p_out_buf->p_buffer + i_in_nb * i_sample_bytes,
+                0, (i_out_nb - i_in_nb) * i_sample_bytes );
     }
 
     p_out_buf->i_nb_samples = i_out_nb;
-    p_out_buf->i_nb_bytes = i_out_nb * i_frame_bytes;
+    p_out_buf->i_nb_bytes = i_out_nb * i_sample_bytes;
+    p_out_buf->start_date = p_in_buf->start_date;
+    p_out_buf->end_date = p_out_buf->start_date + p_out_buf->i_nb_samples *
+        1000000 / p_filter->output.i_rate;
 }
-
index a792af7..a1a414f 100644 (file)
@@ -2,7 +2,7 @@
  * ugly.c : ugly resampler (changes pitch)
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: ugly.c,v 1.4 2002/10/15 23:10:54 massiot Exp $
+ * $Id: ugly.c,v 1.5 2002/11/11 22:27:01 gbazin Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
@@ -77,14 +77,14 @@ static int Create( vlc_object_t *p_this )
 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
 {
-    s32* p_in = (s32*)p_in_buf->p_buffer;
-    s32* p_out = (s32*)p_out_buf->p_buffer;
+    int32_t* p_in = (int32_t*)p_in_buf->p_buffer;
+    int32_t* p_out = (int32_t*)p_out_buf->p_buffer;
 
     int i_nb_channels = aout_FormatNbChannels( &p_filter->input );
     int i_in_nb = p_in_buf->i_nb_samples;
     int i_out_nb = i_in_nb * p_filter->output.i_rate
                     / p_filter->input.i_rate;
-    int i_frame_bytes = i_nb_channels * sizeof(s32);
+    int i_sample_bytes = i_nb_channels * sizeof(int32_t);
     int i_out, i_chan, i_remainder = 0;
 
     for( i_out = i_out_nb ; i_out-- ; )
@@ -105,6 +105,8 @@ static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
     }
 
     p_out_buf->i_nb_samples = i_out_nb;
-    p_out_buf->i_nb_bytes = i_out_nb * i_frame_bytes;
+    p_out_buf->i_nb_bytes = i_out_nb * i_sample_bytes;
+    p_out_buf->start_date = p_in_buf->start_date;
+    p_out_buf->end_date = p_out_buf->start_date + p_out_buf->i_nb_samples *
+        1000000 / p_filter->output.i_rate;
 }
-
index 382ca6a..be5f7ae 100644 (file)
@@ -2,7 +2,7 @@
  * filters.c : audio output filters management
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: filters.c,v 1.12 2002/10/20 12:23:48 massiot Exp $
+ * $Id: filters.c,v 1.13 2002/11/11 22:27:00 gbazin Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -60,6 +60,8 @@ static aout_filter_t * FindFilter( aout_instance_t * p_aout,
         return NULL;
     }
 
+    p_filter->b_reinit = VLC_TRUE;
+
     return p_filter;
 }
 
@@ -292,10 +294,15 @@ void aout_FiltersPlay( aout_instance_t * p_aout,
         aout_filter_t * p_filter = pp_filters[i];
         aout_buffer_t * p_output_buffer;
 
+        /* We need this because resamplers can produce more samples than
+           (i_in_nb * p_filter->output.i_rate / p_filter->input.i_rate) */
+        int i_compensate_rounding = 2 * p_filter->input.i_rate
+            / p_filter->output.i_rate;
+
         aout_BufferAlloc( &p_filter->output_alloc,
-                          (mtime_t)(*pp_input_buffer)->i_nb_samples * 1000000
-                            / p_filter->input.i_rate, *pp_input_buffer,
-                          p_output_buffer );
+            ((mtime_t)(*pp_input_buffer)->i_nb_samples + i_compensate_rounding)
+            * 1000000 / p_filter->input.i_rate,
+            *pp_input_buffer, p_output_buffer );
         if ( p_output_buffer == NULL )
         {
             msg_Err( p_aout, "out of memory" );
index b111555..7bb8a2c 100644 (file)
@@ -2,7 +2,7 @@
  * input.c : internal management of input streams for the audio output
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: input.c,v 1.19 2002/11/10 14:31:46 gbazin Exp $
+ * $Id: input.c,v 1.20 2002/11/11 22:27:00 gbazin Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -98,13 +98,14 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
             return -1;
         }
 
+        aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
+                                 p_input->i_nb_resamplers,
+                                 &p_input->input_alloc );
+
         /* Setup the initial rate of the resampler */
         p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
         p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
 
-        aout_FiltersHintBuffers( p_aout, p_input->pp_resamplers,
-                                 p_input->i_nb_resamplers,
-                                 &p_input->input_alloc );
     }
 
     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
@@ -153,7 +154,7 @@ int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
 int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
                     aout_buffer_t * p_buffer )
 {
-    mtime_t start_date, duration;
+    mtime_t start_date;
 
     /* We don't care if someone changes the start date behind our back after
      * this. We'll deal with that when pushing the buffer, and compensate
@@ -172,9 +173,11 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
         vlc_mutex_lock( &p_aout->input_fifos_lock );
         aout_FifoSet( p_aout, &p_input->fifo, 0 );
         vlc_mutex_unlock( &p_aout->input_fifos_lock );
+        if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
+            msg_Warn( p_aout, "timing screwed, stopping resampling" );
         p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
         p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
-        msg_Warn( p_aout, "timing screwed, stopping resampling" );
+        p_input->pp_resamplers[0]->b_reinit = VLC_TRUE;
         start_date = 0;
     }
 
@@ -261,7 +264,7 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
         }
         else if( p_input->i_resamp_start_drift &&
                  ( abs( p_buffer->start_date - start_date ) >
-                   abs( p_input->i_resamp_start_drift ) ) )
+                   abs( p_input->i_resamp_start_drift ) * 3 / 2 ) )
         {
             /* If the drift is increasing and not decreasing, than something
              * is bad. We'd better stop the resampling right now. */
@@ -269,8 +272,14 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
             p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
             p_input->pp_resamplers[0]->input.i_rate = p_input->input.i_rate;
         }
+
     }
 
+    /* Adding the start date will be managed by aout_FifoPush(). */
+    p_buffer->start_date = start_date;
+    p_buffer->end_date = start_date +
+        (p_buffer->end_date - p_buffer->start_date);
+
     /* Actually run the resampler now. */
     if ( p_aout->mixer.mixer.i_rate !=
          p_input->pp_resamplers[0]->input.i_rate )
@@ -280,13 +289,6 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
                           &p_buffer );
     }
 
-    /* Adding the start date will be managed by aout_FifoPush(). */
-    duration = ( p_buffer->end_date - p_buffer->start_date ) *
-               p_input->pp_resamplers[0]->input.i_rate / p_input->input.i_rate;
-
-    p_buffer->start_date = start_date;
-    p_buffer->end_date = start_date + duration;
-
     vlc_mutex_lock( &p_aout->input_fifos_lock );
     aout_FifoPush( p_aout, &p_input->fifo, p_buffer );
     vlc_mutex_unlock( &p_aout->input_fifos_lock );