]> git.sesse.net Git - vlc/commitdiff
* src/audio_output/output.c: fixed another quality affecting bug.
authorGildas Bazin <gbazin@videolan.org>
Sun, 10 Nov 2002 14:31:46 +0000 (14:31 +0000)
committerGildas Bazin <gbazin@videolan.org>
Sun, 10 Nov 2002 14:31:46 +0000 (14:31 +0000)
* include/aout_internal.h src/audio_output/input.c: major change to the
   resampling algorithm. When resampling is requested to keep the audio stream
   synchronised to the main clock, we trigger it but we change the resampling
   rate only progressively so it doesn't get noticed too much by the listener.

include/aout_internal.h
src/audio_output/input.c
src/audio_output/output.c

index c87702015fe98f2b5d2d59f34e5cdb15f899a220..d1df3a2a65a1f9a388d9d3c8a08f492d74729ff8 100644 (file)
@@ -2,7 +2,7 @@
  * aout_internal.h : internal defines for audio output
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: aout_internal.h,v 1.29 2002/11/09 18:28:36 sam Exp $
+ * $Id: aout_internal.h,v 1.30 2002/11/10 14:31:46 gbazin Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -138,6 +138,9 @@ typedef struct aout_mixer_t
 /*****************************************************************************
  * aout_input_t : input stream for the audio output
  *****************************************************************************/
+#define AOUT_RESAMPLING_NONE     0
+#define AOUT_RESAMPLING_UP       1
+#define AOUT_RESAMPLING_DOWN     2
 struct aout_input_t
 {
     /* When this lock is taken, the pipeline cannot be changed by a
@@ -154,6 +157,9 @@ struct aout_input_t
     /* resamplers */
     aout_filter_t *         pp_resamplers[AOUT_MAX_FILTERS];
     int                     i_nb_resamplers;
+    int                     i_resampling_type;
+    mtime_t                 i_resamp_start_date;
+    int                     i_resamp_start_drift;
 
     aout_fifo_t             fifo;
 
index 8eedcc2db5a435c4dbf6d3a27b98fa0fdbd066df..b111555377c574963c0a266cceffc35c05a8b86b 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.18 2002/11/08 10:26:53 gbazin Exp $
+ * $Id: input.c,v 1.19 2002/11/10 14:31:46 gbazin Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -98,6 +98,10 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
             return -1;
         }
 
+        /* 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 );
@@ -168,8 +172,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 );
+        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" );
         start_date = 0;
-    } 
+    }
 
     if ( p_buffer->start_date < mdate() + AOUT_MIN_PREPARE_TIME )
     {
@@ -188,8 +195,11 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
     aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
                       &p_buffer );
 
-    if ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
-          || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE )
+    /* Run the resampler if needed.
+     * We first need to calculate the output rate of this resampler. */
+    if ( ( p_input->i_resampling_type == AOUT_RESAMPLING_NONE ) &&
+         ( start_date < p_buffer->start_date - AOUT_PTS_TOLERANCE
+           || start_date > p_buffer->start_date + AOUT_PTS_TOLERANCE ) )
     {
         /* Can happen in several circumstances :
          * 1. A problem at the input (clock drift)
@@ -198,48 +208,82 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
          *    synchronization
          * Solution : resample the buffer to avoid a scratch.
          */
-        int i_ratio;
-        mtime_t old_duration;
         mtime_t drift = p_buffer->start_date - start_date;
 
-        msg_Warn( p_aout, "buffer is "I64Fd" %s, resampling",
-                         drift > 0 ? drift : -drift,
-                         drift > 0 ? "in advance" : "late" );
-        old_duration = p_buffer->end_date - p_buffer->start_date;
-        duration = p_buffer->end_date - start_date;
-        i_ratio = (duration * 100) / old_duration;
-        /* If the ratio is too != 100, the sound quality will be awful. */
-        if ( i_ratio < 100 - AOUT_MAX_RESAMPLING /* % */ )
+        p_input->i_resamp_start_date = mdate();
+        p_input->i_resamp_start_drift = drift;
+
+        if ( drift > 0 )
+            p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
+        else
+            p_input->i_resampling_type = AOUT_RESAMPLING_UP;
+
+        msg_Warn( p_aout, "buffer is "I64Fd" %s, triggering %ssampling",
+                          drift > 0 ? drift : -drift,
+                          drift > 0 ? "in advance" : "late",
+                          drift > 0 ? "down" : "up");
+    }
+
+    if ( p_input->i_resampling_type != AOUT_RESAMPLING_NONE )
+    {
+        /* Resampling has been triggered previously (because of dates
+         * mismatch). We want the resampling to happen progressively so
+         * it isn't too audible to the listener. */
+
+        if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
         {
-            duration = (old_duration * (100 - AOUT_MAX_RESAMPLING)) / 100;
+            p_input->pp_resamplers[0]->input.i_rate += 10; /* Hz */
         }
-        if ( i_ratio > 100 + AOUT_MAX_RESAMPLING /* % */ )
+        else
         {
-            duration = (old_duration * (100 + AOUT_MAX_RESAMPLING)) / 100;
+            p_input->pp_resamplers[0]->input.i_rate -= 10; /* Hz */
         }
-        p_input->pp_resamplers[0]->input.i_rate 
-            = (p_input->input.i_rate * old_duration) / duration;
 
-        aout_FiltersPlay( p_aout, p_input->pp_resamplers,
-                          p_input->i_nb_resamplers,
-                          &p_buffer );
-    }
-    else
-    {
-        duration = p_buffer->end_date - p_buffer->start_date;
-
-        if ( p_input->input.i_rate != p_aout->mixer.mixer.i_rate )
+        /* Check if everything is back to normal, in which case we can stop the
+         * resampling */
+        if( p_input->pp_resamplers[0]->input.i_rate ==
+              p_input->input.i_rate )
+        {
+            p_input->i_resampling_type = AOUT_RESAMPLING_NONE;
+            msg_Warn( p_aout, "resampling stopped after "I64Fi" usec",
+                      mdate() - p_input->i_resamp_start_date );
+        }
+        else if( abs( p_buffer->start_date - start_date ) <
+                 abs( p_input->i_resamp_start_drift ) / 2 )
         {
-            /* Standard resampling is needed ! */
+            /* if we reduced the drift from half, then it is time to switch
+             * back the resampling direction. */
+            if( p_input->i_resampling_type == AOUT_RESAMPLING_UP )
+                p_input->i_resampling_type = AOUT_RESAMPLING_DOWN;
+            else
+                p_input->i_resampling_type = AOUT_RESAMPLING_UP;
+            p_input->i_resamp_start_drift = 0;
+        }
+        else if( p_input->i_resamp_start_drift &&
+                 ( abs( p_buffer->start_date - start_date ) >
+                   abs( p_input->i_resamp_start_drift ) ) )
+        {
+            /* If the drift is increasing and not decreasing, than something
+             * is bad. We'd better stop the resampling right now. */
+            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;
-
-            aout_FiltersPlay( p_aout, p_input->pp_resamplers,
-                              p_input->i_nb_resamplers,
-                              &p_buffer );
         }
     }
 
+    /* Actually run the resampler now. */
+    if ( p_aout->mixer.mixer.i_rate !=
+         p_input->pp_resamplers[0]->input.i_rate )
+    {
+        aout_FiltersPlay( p_aout, p_input->pp_resamplers,
+                          p_input->i_nb_resamplers,
+                          &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;
 
index 12097adcd4a9f469b2a352a0fca15d008a45e667..fd0204e6c83a6c7e4d6871220f98a756a6b32989 100644 (file)
@@ -2,7 +2,7 @@
  * output.c : internal management of output streams for the audio output
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: output.c,v 1.22 2002/11/08 10:26:53 gbazin Exp $
+ * $Id: output.c,v 1.23 2002/11/10 14:31:46 gbazin Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -231,9 +231,9 @@ aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
     {
         /* Try to compensate the drift by doing some resampling. */
         int i;
-        mtime_t difference = p_buffer->start_date - start_date;
-        msg_Warn( p_aout, "output date isn't PTS date, resampling ("I64Fd")",
-                  difference );
+        mtime_t difference = start_date - p_buffer->start_date;
+        msg_Warn( p_aout, "output date isn't PTS date, requesting "
+                  "resampling ("I64Fd")", difference );
 
         vlc_mutex_lock( &p_aout->input_fifos_lock );
         for ( i = 0; i < p_aout->i_nb_inputs; i++ )