[vlc-devel] [PATCH 1/4] es_out: fix flapping PREROLL flag on non dated packets

Francois Cartegnie fcvlcdev at free.fr
Wed Sep 30 17:44:04 CEST 2020


Saves pts to perform preroll target comparison against.
refs #25129

In some cases, the packets are sent interleaved with non dated packets
SEND 1
SEND 0
(...) multiple times, simplified to 1 occurence
PCR 1
SEND 719996
SEND 0
PCR 719996
SEND 1439992
SEND 0
PCR 1439992
SEND 2160008
SEND 0
PCR 2160008

Until preroll_end (file caching) is reached, all packets
are flagged as PREROLL.

Entering preroll has effect on audio output by flushing
previous content, and silencing dropped buffers.

Due to non dated interleaving, the stateless es_out keeps
flipping PREROLL packets and triggering the in-stream PREROLL
behaviour (like SET_NEXT_DISPLAY_TIME).
The effect being (here with alsa) to re-enter preroll each
time, extending decoder preroll until pts >= preroll_end
and flushing decoders.

Stream buffering done (1439 ms in 0 ms)
ModuleThread_PlayAudio pts 1 preroll end -9223372036854775808
inserting 3840 zeroes / 80 ms
cannot write samples: Relais brisé (pipe)
ModuleThread_PlayAudio pts 120001 preroll end 9223372036854775807
(...)
ModuleThread_PlayAudio pts 719996 preroll end 719996
end of audio preroll
inserting 34804 zeroes / 725 ms 719996
ModuleThread_PlayAudio pts 839996 preroll end 9223372036854775807
(...)
ModuleThread_PlayAudio pts 1439992 preroll end 1439992
end of audio preroll
inserting 69172 zeroes / 1441 ms 1439992
ModuleThread_PlayAudio pts 1559992 preroll end 9223372036854775807
(...)
ModuleThread_PlayAudio pts 2160008 preroll end 2160008
end of audio preroll
inserting 103601 zeroes / 2158 ms 2160008
ModuleThread_PlayAudio pts 2280008 preroll end -9223372036854775808
(...)
---
 src/input/es_out.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/input/es_out.c b/src/input/es_out.c
index e4b840ed75..a95f804f70 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -79,6 +79,8 @@ typedef struct
     vlc_clock_main_t *p_main_clock;
     vlc_clock_t      *p_master_clock;
 
+    vlc_tick_t i_last_pcr;
+
     vlc_meta_t *p_meta;
     struct vlc_list node;
 } es_out_pgrm_t;
@@ -133,6 +135,7 @@ struct es_out_id_t
     /* Used by vlc_clock_cbs, need to be const during the lifetime of the clock */
     bool master;
 
+    vlc_tick_t i_roll_level;
     vlc_tick_t delay;
 
     /* Fields for Video with CC */
@@ -896,6 +899,7 @@ static void EsOutChangePosition( es_out_t *out, bool b_flush )
     input_SendEventCache( p_sys->p_input, 0.0 );
 
     foreach_es_then_es_slaves(p_es)
+    {
         if( p_es->p_dec != NULL )
         {
             if( b_flush )
@@ -907,12 +911,15 @@ static void EsOutChangePosition( es_out_t *out, bool b_flush )
                     vlc_input_decoder_StartWait( p_es->p_dec_record );
             }
         }
+        p_es->i_roll_level = VLC_TICK_INVALID;
+    }
 
     es_out_pgrm_t *pgrm;
     vlc_list_foreach(pgrm, &p_sys->programs, node)
     {
         input_clock_Reset(pgrm->p_input_clock);
         vlc_clock_main_Reset(pgrm->p_main_clock);
+        pgrm->i_last_pcr = VLC_TICK_INVALID;
     }
 
     p_sys->b_buffering = true;
@@ -1371,6 +1378,7 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, input_source_t *source, in
     p_pgrm->i_es = 0;
     p_pgrm->b_selected = false;
     p_pgrm->b_scrambled = false;
+    p_pgrm->i_last_pcr = VLC_TICK_INVALID;
     p_pgrm->p_meta = NULL;
 
     p_pgrm->p_master_clock = NULL;
@@ -2083,6 +2091,7 @@ static es_out_id_t *EsOutAddLocked( es_out_t *out, input_source_t *source,
     es->p_master = p_master;
     es->mouse_event_cb = NULL;
     es->mouse_event_userdata = NULL;
+    es->i_roll_level = VLC_TICK_INVALID;
     es->delay = INT64_MAX;
 
     vlc_list_append(&es->node, es->p_master ? &p_sys->es_slaves : &p_sys->es);
@@ -2764,8 +2773,23 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
         if( p_block->i_pts == VLC_TICK_INVALID )
             i_date = p_block->i_dts;
 
-        if( i_date + p_block->i_length < p_sys->i_preroll_end )
+        /* In some cases, the demuxer sends non dated packets.
+           We use interpolation, previous, or pcr value to compare with
+           preroll target timestamp */
+        if( i_date == VLC_TICK_INVALID )
+        {
+            if( es->i_roll_level != VLC_TICK_INVALID )
+                i_date = es->i_roll_level;
+            else if( es->p_pgrm->i_last_pcr != VLC_TICK_INVALID )
+                i_date = es->p_pgrm->i_last_pcr;
+        }
+
+        /* If i_date is still invalid (first/all non dated), expect to be in preroll */
+        if( i_date == VLC_TICK_INVALID ||
+            i_date + p_block->i_length < p_sys->i_preroll_end )
             p_block->i_flags |= BLOCK_FLAG_PREROLL;
+
+        es->i_roll_level = i_date + p_block->i_length;
     }
 
     if( !es->p_dec )
@@ -3169,6 +3193,8 @@ static int EsOutVaControlLocked( es_out_t *out, input_source_t *source,
             return VLC_EGENERIC;
         }
 
+        p_pgrm->i_last_pcr = i_pcr;
+
         input_thread_private_t *priv = input_priv(p_sys->p_input);
 
         /* TODO do not use vlc_tick_now() but proper stream acquisition date */
-- 
2.25.4



More information about the vlc-devel mailing list