]> git.sesse.net Git - vlc/commitdiff
* 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 cc788d520e8e72ac57503155b4b8d531c6ffd2f5..3db013e3de0877bdf519259eff08f25bd5eb7273 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 c32c6d5d2cc7e815ba2f7962c713b970063dc381..f5cf253e2e5f3eedebc7951d448ce58e02a00eb8 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 11752df5cd09e55f3e05b91e5e9348cff9f011a8..47486d9c8f4fa3738d19e9f2b9df2a302084e705 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 a792af75bf8e8b72a6705e0c1586dfc2873c364f..a1a414f6c51489c59e2f0e0051f24d8740c785cf 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 382ca6a2f89ab17d671e7a5be7cd3e9540572162..be5f7aefda42a6f915566b19beb66258de0dd77c 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 b111555377c574963c0a266cceffc35c05a8b86b..7bb8a2c9292199e778800587eb7f90b38f594b04 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 );