[vlc-commits] aout: fix potential live loop

Rémi Denis-Courmont git at videolan.org
Tue Nov 13 20:36:03 CET 2012


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue Nov 13 21:12:51 2012 +0200| [17b69f2d41f4c71ac51b9196684d3024173983c6] | committer: Rémi Denis-Courmont

aout: fix potential live loop

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=17b69f2d41f4c71ac51b9196684d3024173983c6
---

 src/audio_output/dec.c |   78 +++++++++++++++++++++++++++++-------------------
 1 file changed, 47 insertions(+), 31 deletions(-)

diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c
index 4857a99..87310e6 100644
--- a/src/audio_output/dec.c
+++ b/src/audio_output/dec.c
@@ -270,7 +270,6 @@ static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
     aout_owner_t *owner = aout_owner (aout);
     mtime_t aout_pts, drift;
 
-retry:
     /**
      * Depending on the drift between the actual and intended playback times,
      * the audio core may ignore the drift, trigger upsampling or downsampling,
@@ -289,46 +288,52 @@ retry:
      */
     if (aout_OutputTimeGet (aout, &aout_pts) != 0)
         return; /* nothing can be done if timing is unknown */
-
     drift = aout_pts - dec_pts;
 
-    if (drift < (owner->sync.discontinuity ? 0
-                : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
-    {   /* If the audio output is very early (which is rare other than during
-         * prebuffering), hold with silence. */
-        if (!owner->sync.discontinuity)
-            msg_Err (aout, "playback way too early (%"PRId64"): "
-                     "playing silence", drift);
-        aout_StopResampling (aout);
-        aout_DecSilence (aout, -drift);
-        owner->sync.discontinuity = false;
-        drift = 0;
-    }
-    else
+    /* Late audio output.
+     * This can happen due to insufficient caching, scheduling jitter
+     * or bug in the decoder. Ideally, the output would seek backward. But that
+     * is not portable, not supported by some hardware and often unsafe/buggy
+     * where supported. The other alternative is to flush the buffers
+     * completely. */
     if (drift > (owner->sync.discontinuity ? 0
                   : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
-    {   /* If the audio output is very late, drop the buffers.
-         * This should make some room and advance playback quickly. */
+    {
         if (!owner->sync.discontinuity)
-            msg_Err (aout, "playback way too late (%"PRId64"): "
+            msg_Warn (aout, "playback way too late (%"PRId64"): "
+                      "flushing buffers", drift);
+        else
+            msg_Dbg (aout, "playback too late (%"PRId64"): "
                      "flushing buffers", drift);
+        aout_OutputFlush (aout, false);
+
         aout_StopResampling (aout);
         owner->sync.end = VLC_TS_INVALID;
-        aout_OutputFlush (aout, false);
-        goto retry; /* may be too early now... retry */
+        owner->sync.discontinuity = true;
+
+        /* Now the output might be too early... Recheck. */
+        if (aout_OutputTimeGet (aout, &aout_pts) != 0)
+            return; /* nothing can be done if timing is unknown */
+        drift = aout_pts - dec_pts;
     }
 
-    if (drift < -AOUT_MAX_PTS_ADVANCE)
+    /* Early audio output.
+     * This is rare except at startup when the buffers are still empty. */
+    if (drift < (owner->sync.discontinuity ? 0
+                : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
     {
-        if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
-        {
-            msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
-                      drift);
-            owner->sync.resamp_start_drift = -drift;
-        }
-        owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
+        if (!owner->sync.discontinuity)
+            msg_Warn (aout, "playback way too early (%"PRId64"): "
+                      "playing silence", drift);
+        aout_DecSilence (aout, -drift);
+
+        aout_StopResampling (aout);
+        owner->sync.discontinuity = true;
+        drift = 0;
     }
-    else
+
+    /* Resampling */
+
     if (drift > +AOUT_MAX_PTS_DELAY)
     {
         if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
@@ -340,6 +345,17 @@ retry:
         owner->sync.resamp_type = AOUT_RESAMPLING_UP;
     }
 
+    if (drift < -AOUT_MAX_PTS_ADVANCE)
+    {
+        if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
+        {
+            msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
+                      drift);
+            owner->sync.resamp_start_drift = -drift;
+        }
+        owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
+    }
+
     if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
         return; /* Everything is fine. Nothing to do. */
 
@@ -368,8 +384,8 @@ retry:
     if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
     {   /* If the drift is ever increasing, then something is seriously wrong.
          * Cease resampling and hope for the best. */
-        msg_Err (aout, "timing screwed (drift: %"PRId64" us): "
-                 "stopping resampling", drift);
+        msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
+                  "stopping resampling", drift);
         aout_StopResampling (aout);
     }
 }



More information about the vlc-commits mailing list