[vlc-commits] [Git][videolan/vlc][master] 5 commits: aout: don't reset sync.discontinuity

Steve Lhomme (@robUx4) gitlab at videolan.org
Wed Jun 26 08:00:43 UTC 2024



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
d4782410 by Thomas Guillem at 2024-06-26T07:39:03+00:00
aout: don't reset sync.discontinuity

It is set back to false just before aout->play and the variable is not
read in between.

- - - - -
f5e04ec3 by Thomas Guillem at 2024-06-26T07:39:03+00:00
aout: rename sync.discontinuity

It is not used for stream discontinuity but to distinguish if a buffer
had already been played.

- - - - -
5ed6db74 by Thomas Guillem at 2024-06-26T07:39:03+00:00
aout: rename stream_Discontinuity()

- - - - -
87e96c29 by Thomas Guillem at 2024-06-26T07:39:03+00:00
aout: add intermediate function for IsDrained()

No functional changes, this will be needed by next commits.

- - - - -
46a98b84 by Thomas Guillem at 2024-06-26T07:39:03+00:00
aout: fix discontinuity handling

Changing timings of the stream module while playing is an intricate
task, therefore modules don't handle any PTS discontinuity.

The PTS discontinuity is now handled in the core:

 - Drain the current stream in case of discontinuity
 - Check from future Play() calls if the stream is drained
 - Keep blocks in a list while waiting for the drain
 - Flush when the stream is finally drained
 - Play back all blocks that were saved

- - - - -


1 changed file:

- src/audio_output/dec.c


Changes:

=====================================
src/audio_output/dec.c
=====================================
@@ -49,13 +49,20 @@ struct vlc_aout_stream
     atomic_bool drained;
     _Atomic vlc_tick_t drain_deadline;
 
+    struct
+    {
+        bool draining;
+        block_t **fifo_last;
+        block_t *fifo_first;
+    } discontinuity;
+
     struct
     {
         struct vlc_clock_t *clock;
         float rate; /**< Play-out speed rate */
         vlc_tick_t resamp_start_drift; /**< Resampler drift absolute value */
         int resamp_type; /**< Resampler mode (FIXME: redundant / resampling) */
-        bool discontinuity;
+        bool played;
         vlc_tick_t request_delay;
         vlc_tick_t delay;
     } sync;
@@ -155,9 +162,98 @@ static int stream_GetDelay(vlc_aout_stream *stream, vlc_tick_t *delay)
     return 0;
 }
 
-static void stream_Discontinuity(vlc_aout_stream *stream)
+static bool stream_IsDrained(vlc_aout_stream *stream)
+{
+    audio_output_t *aout = aout_stream_aout(stream);
+
+    if (aout->drain == NULL)
+    {
+        vlc_tick_t drain_deadline =
+            atomic_load_explicit(&stream->drain_deadline, memory_order_relaxed);
+        return drain_deadline != VLC_TICK_INVALID
+            && vlc_tick_now() >= drain_deadline;
+    }
+    else
+        return atomic_load_explicit(&stream->drained, memory_order_relaxed);
+}
+
+static int stream_StartDiscontinuity(vlc_aout_stream *stream, block_t *block)
 {
-    stream->sync.discontinuity = true;
+    audio_output_t *aout = aout_stream_aout(stream);
+    assert(!stream->discontinuity.draining);
+
+    /* Changing timings of the stream module while playing is an intricate
+     * task, therefore modules don't handle any PTS discontinuity.
+     *
+     * The PTS discontinuity is handled in the core:
+     *
+     *  - Drain the current stream in case of discontinuity
+     *  - Check from future Play() calls if the stream is drained
+     *  - Keep blocks in a list while waiting for the drain
+     *  - Flush when the stream is finally drained
+     *  - Play back all blocks that were saved
+     */
+
+    msg_Dbg(aout, "discontinuity: at %"PRId64" us, draining output",
+            block->i_pts);
+    vlc_aout_stream_Drain(stream);
+    stream->discontinuity.draining = true;
+
+    stream->discontinuity.fifo_first = NULL;
+    stream->discontinuity.fifo_last = &stream->discontinuity.fifo_first;
+
+    block->i_flags &= ~ BLOCK_FLAG_DISCONTINUITY;
+    block_ChainLastAppend(&stream->discontinuity.fifo_last, block);
+
+    return AOUT_DEC_SUCCESS;
+}
+
+static void stream_ResetDiscontinuity(vlc_aout_stream *stream)
+{
+    block_ChainRelease(stream->discontinuity.fifo_first);
+    stream->discontinuity.draining = false;
+}
+
+static int stream_HandleDiscontinuity(vlc_aout_stream *stream, block_t *block)
+{
+    audio_output_t *aout = aout_stream_aout(stream);
+
+    block_ChainLastAppend(&stream->discontinuity.fifo_last, block);
+
+    /* Will play back all blocks once the draining is finished */
+    if (!stream_IsDrained(stream))
+        return AOUT_DEC_SUCCESS;
+
+    /* Keep block list and stats before flushing */
+    int count;
+    vlc_tick_t length;
+    block_ChainProperties(stream->discontinuity.fifo_first, &count, NULL,
+                          &length);
+    block = stream->discontinuity.fifo_first;
+
+    msg_Dbg(aout, "discontinuity: flushing output");
+
+    /* Reset the discontinuity state, and flush */
+    stream->discontinuity.draining = false;
+    vlc_aout_stream_Flush(stream);
+
+    msg_Dbg(aout, "discontinuity: playing back %d blocks for a total length of "
+            "%"PRId64" us", count, length);
+
+    /* Play back all blocks past the discontinuity */
+    for (block_t *next; block != NULL; block = next)
+    {
+        next = block->p_next;
+        block->p_next = NULL;
+
+        vlc_aout_stream_Play(stream, block);
+    }
+    return AOUT_DEC_SUCCESS;
+}
+
+static void stream_ResetTimings(vlc_aout_stream *stream)
+{
+    stream->sync.played = false;
 
     vlc_mutex_lock(&stream->timing.lock);
     stream->timing.first_pts = VLC_TICK_INVALID;
@@ -203,6 +299,9 @@ static void stream_Reset(vlc_aout_stream *stream)
             stream->sync.request_delay = stream->sync.delay;
             stream->sync.delay = 0;
         }
+
+        if (stream->discontinuity.draining)
+            stream_ResetDiscontinuity(stream);
     }
 
     stream->timing.rate_audio_ts = VLC_TICK_INVALID;
@@ -212,7 +311,7 @@ static void stream_Reset(vlc_aout_stream *stream)
     atomic_store_explicit(&stream->drain_deadline, VLC_TICK_INVALID,
                           memory_order_relaxed);
 
-    stream_Discontinuity(stream);
+    stream_ResetTimings(stream);
 }
 
 /**
@@ -278,7 +377,9 @@ vlc_aout_stream * vlc_aout_stream_New(audio_output_t *p_aout,
     stream->sync.rate = 1.f;
     stream->sync.resamp_type = AOUT_RESAMPLING_NONE;
     stream->sync.delay = stream->sync.request_delay = 0;
-    stream_Discontinuity(stream);
+
+    stream->discontinuity.draining = false;
+    stream_ResetTimings(stream);
 
     atomic_init (&stream->buffers_lost, 0);
     atomic_init (&stream->buffers_played, 0);
@@ -343,6 +444,9 @@ void vlc_aout_stream_Delete (vlc_aout_stream *stream)
     if (stream->volume != NULL)
         aout_volume_Delete(stream->volume);
 
+    if (stream->discontinuity.draining)
+        stream_ResetDiscontinuity(stream);
+
     free(stream);
 }
 
@@ -502,13 +606,13 @@ static void stream_HandleDrift(vlc_aout_stream *stream, vlc_tick_t drift,
      * 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 > (stream->sync.discontinuity ? 0
-                : lroundf(+3 * AOUT_MAX_PTS_DELAY / rate)))
+    if (drift > (stream->sync.played ?
+                 lroundf(+3 * AOUT_MAX_PTS_DELAY / rate) : 0))
     {
         if (tracer != NULL)
             vlc_tracer_TraceEvent(tracer, "RENDER", stream->str_id, "late_flush");
 
-        if (!stream->sync.discontinuity)
+        if (stream->sync.played)
             msg_Warn (aout, "playback way too late (%"PRId64"): "
                       "flushing buffers", drift);
         else
@@ -522,10 +626,10 @@ static void stream_HandleDrift(vlc_aout_stream *stream, vlc_tick_t drift,
 
     /* Early audio output.
      * This is rare except at startup when the buffers are still empty. */
-    if (drift < (stream->sync.discontinuity ? 0
-                : lroundf(-3 * AOUT_MAX_PTS_ADVANCE / rate)))
+    if (drift < (stream->sync.played ?
+                 lroundf(-3 * AOUT_MAX_PTS_ADVANCE / rate) : 0))
     {
-        if (!stream->sync.discontinuity)
+        if (stream->sync.played)
         {
             if (tracer != NULL)
                 vlc_tracer_TraceEvent(tracer, "RENDER", stream->str_id, "early_silence");
@@ -536,7 +640,6 @@ static void stream_HandleDrift(vlc_aout_stream *stream, vlc_tick_t drift,
         stream_Silence(stream, -drift, audio_ts);
 
         stream_StopResampling(stream);
-        stream->sync.discontinuity = true;
         drift = 0;
     }
 
@@ -656,7 +759,7 @@ static void stream_Synchronize(vlc_aout_stream *stream, vlc_tick_t system_now,
         if (stream_GetDelay(stream, &delay) != 0)
             return; /* nothing can be done if timing is unknown */
 
-        if (stream->sync.discontinuity)
+        if (!stream->sync.played)
         {
             /* Chicken-egg situation for some aout modules that can't be
              * started deferred (like alsa). These modules will start to play
@@ -731,13 +834,16 @@ int vlc_aout_stream_Play(vlc_aout_stream *stream, block_t *block)
     block->i_length = vlc_tick_from_samples( block->i_nb_samples,
                                    stream->input_format.i_rate );
 
+    if (stream->discontinuity.draining)
+        return stream_HandleDiscontinuity(stream, block);
+
+    if (block->i_flags & BLOCK_FLAG_DISCONTINUITY && stream->sync.played)
+        return stream_StartDiscontinuity(stream, block);
+
     int ret = stream_CheckReady (stream);
     if (unlikely(ret == AOUT_DEC_FAILED))
         goto drop; /* Pipeline is unrecoverably broken :-( */
 
-    if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
-        stream_Discontinuity(stream);
-
     if (stream->filters)
     {
         if (atomic_load_explicit(&owner->vp.update, memory_order_relaxed))
@@ -783,14 +889,14 @@ int vlc_aout_stream_Play(vlc_aout_stream *stream, block_t *block)
     vlc_audio_meter_Process(&owner->meter, block, play_date);
 
     /* Output */
-    stream->sync.discontinuity = false;
+    stream->sync.played = true;
     stream->timing.played_samples += block->i_nb_samples;
     aout->play(aout, block, play_date);
 
     atomic_fetch_add_explicit(&stream->buffers_played, 1, memory_order_relaxed);
     return ret;
 drop:
-    stream_Discontinuity(stream);
+    stream_ResetTimings(stream);
     block_Release (block);
     atomic_fetch_add_explicit(&stream->buffers_lost, 1, memory_order_relaxed);
     return ret;
@@ -889,17 +995,11 @@ void vlc_aout_stream_NotifyDrained(vlc_aout_stream *stream)
 
 bool vlc_aout_stream_IsDrained(vlc_aout_stream *stream)
 {
-    audio_output_t *aout = aout_stream_aout(stream);
+    /* The internal draining state should not mess with the public one */
+    if (stream->discontinuity.draining)
+        return false;
 
-    if (aout->drain == NULL)
-    {
-        vlc_tick_t drain_deadline =
-            atomic_load_explicit(&stream->drain_deadline, memory_order_relaxed);
-        return drain_deadline != VLC_TICK_INVALID
-            && vlc_tick_now() >= drain_deadline;
-    }
-    else
-        return atomic_load_explicit(&stream->drained, memory_order_relaxed);
+    return stream_IsDrained(stream);
 }
 
 void vlc_aout_stream_Drain(vlc_aout_stream *stream)
@@ -909,6 +1009,21 @@ void vlc_aout_stream_Drain(vlc_aout_stream *stream)
     if (!stream->mixer_format.i_format)
         return;
 
+    if (unlikely(stream->discontinuity.draining))
+    {
+        if (stream->discontinuity.fifo_first != NULL)
+        {
+            vlc_tick_t length;
+            block_ChainProperties(stream->discontinuity.fifo_first, NULL, NULL,
+                                  &length);
+
+            msg_Err(aout, "draining while handling a discontinuity not handled"
+                    ", losing %"PRId64 " us of audio", length); /* FIXME */
+        }
+        stream_ResetDiscontinuity(stream);
+        return;
+    }
+
     struct vlc_tracer *tracer = aout_stream_tracer(stream);
 
     if (tracer != NULL)



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/781532d8e4757063343ab9fba58ef38cb0c2c848...46a98b84f5754e5602c4735e5dd1e929fcc99964

-- 
This project does not include diff previews in email notifications.
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/781532d8e4757063343ab9fba58ef38cb0c2c848...46a98b84f5754e5602c4735e5dd1e929fcc99964
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list