[vlc-devel] [RFC PATCH] decoder: remove input_DecoderWait

Thomas Guillem thomas at gllm.fr
Wed Dec 16 17:39:46 CET 2015


The big issue when removing input_DecoderWait is that
input_clock_ChangeSystemOrigin is called right after the buffering stops
without waiting for all decoders. This leads to a desync between all decoders.
So, input_clock_ChangeSystemOrigin has to be called when all decoders are ready
to output something. The other big issue is that I don't really understand VLC
clocks functions.

My (crazy?) solution: instead of having the input thread waiting for all
decoders when pf_demux send a ES_OUT_SET_PCR control. The input thread will
test (in a non blocking way) if all decoders are ready. If they are not, the
input thread will continue (and pf_demux will be called again). If they are
ready, the input thread will call input_clock_ChangeSystemOrigin, and signal
all decoders to stop waiting.

Improvements:
 - No more deadlocks (?)
 - VLC now quits instantaneously when seeking

Regressions:
 - This don't behave very well when the input is paused (but it's WIP).
 - MKVs take more time to seek (input thread is waiting in ControlPop).
 - /!\ record and timeshifting not tested
---
 src/input/decoder.c | 146 +++++++++++++++++++++++-----------------------------
 src/input/decoder.h |  10 ++--
 src/input/es_out.c  | 106 ++++++++++++++++++++++++++++----------
 3 files changed, 150 insertions(+), 112 deletions(-)

diff --git a/src/input/decoder.c b/src/input/decoder.c
index e054b16..23d3555 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -87,8 +87,7 @@ struct decoder_owner_sys_t
     /* Lock for communication with decoder thread */
     vlc_mutex_t lock;
     vlc_cond_t  wait_request;
-    vlc_cond_t  wait_acknowledge;
-    vlc_cond_t  wait_fifo; /* TODO: merge with wait_acknowledge */
+    vlc_cond_t  wait_fifo;
     vlc_cond_t  wait_timed;
 
     /* -- These variables need locking on write(only) -- */
@@ -106,14 +105,13 @@ struct decoder_owner_sys_t
 
     /* Waiting */
     bool b_waiting;
-    bool b_first;
-    bool b_has_data;
+    bool b_ready;
+    bool b_has_input;
 
     /* Flushing */
     bool flushing;
     bool b_draining;
     atomic_bool drained;
-    bool b_idle;
 
     /* CC */
     struct
@@ -603,18 +601,29 @@ void decoder_AbortPictures( decoder_t *p_dec, bool b_abort )
     vlc_mutex_unlock( &p_owner->lock );
 }
 
-static void DecoderWaitUnblock( decoder_t *p_dec )
+/* DecoderWaitUnblock: Wait for input_DecoderStopWait
+ * Returns VLC_SUCCESS if wait was not interrupted, and VLC_EGENERIC otherwise */
+static int DecoderWaitUnblock( decoder_t *p_dec )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
 
     vlc_assert_locked( &p_owner->lock );
 
-    for( ;; )
+    if( !p_owner->b_has_input )
     {
-        if( !p_owner->b_waiting || !p_owner->b_has_data )
-            break;
-        vlc_cond_wait( &p_owner->wait_request, &p_owner->lock );
+        /* b_has_input is false. Therefore, the processed output is old
+         * corresponds to an input that was sent to the decoder before
+         * input_DecoderStartWait. The output should be discarded. */
+        return VLC_EGENERIC;
     }
+
+    /* Signal that the Decoder is ready */
+    p_owner->b_ready = true;
+
+    while( p_owner->b_waiting && p_owner->b_ready )
+        vlc_cond_wait( &p_owner->wait_request, &p_owner->lock );
+
+    return p_owner->b_ready && p_owner->b_has_input ? VLC_SUCCESS : VLC_EGENERIC;
 }
 
 /* DecoderTimedWait: Interruptible wait
@@ -704,12 +713,6 @@ static int DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block )
 
     vlc_mutex_lock( &p_owner->lock );
 
-    if( p_owner->b_waiting )
-    {
-        p_owner->b_has_data = true;
-        vlc_cond_signal( &p_owner->wait_acknowledge );
-    }
-
     DecoderWaitUnblock( p_dec );
     DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts,
                   &p_sout_block->i_length, NULL, INT64_MAX );
@@ -844,21 +847,14 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
     /* */
     vlc_mutex_lock( &p_owner->lock );
 
-    if( p_owner->b_waiting && !p_owner->b_first )
-    {
-        p_owner->b_has_data = true;
-        vlc_cond_signal( &p_owner->wait_acknowledge );
-    }
-    bool b_first_after_wait = p_owner->b_waiting && p_owner->b_has_data;
-
-    DecoderWaitUnblock( p_dec );
+    bool b_was_first = !p_owner->b_ready;
 
-    if( p_owner->b_waiting )
+    if( DecoderWaitUnblock( p_dec ) )
     {
-        assert( p_owner->b_first );
-        msg_Dbg( p_dec, "Received first picture" );
-        p_owner->b_first = false;
-        p_picture->b_force = true;
+        *pi_lost_sum += 1;
+        picture_Release( p_picture );
+        vlc_mutex_unlock( &p_owner->lock );
+        return;
     }
 
     const bool b_dated = p_picture->date > VLC_TS_INVALID;
@@ -866,6 +862,12 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
     DecoderFixTs( p_dec, &p_picture->date, NULL, NULL,
                   &i_rate, DECODER_BOGUS_VIDEO_DELAY );
 
+    if( b_was_first )
+    {
+        msg_Dbg( p_dec, "Received first picture" );
+        p_picture->b_force = true;
+    }
+
     vlc_mutex_unlock( &p_owner->lock );
 
     /* FIXME: The *input* FIFO should not be locked here. This will not work
@@ -879,7 +881,7 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
     if( p_picture->b_force || p_picture->date > VLC_TS_INVALID )
         /* FIXME: VLC_TS_INVALID -- verify video_output */
     {
-        if( i_rate != p_owner->i_last_rate || b_first_after_wait )
+        if( i_rate != p_owner->i_last_rate || b_was_first )
         {
             /* Be sure to not display old picture after our own */
             vout_Flush( p_vout, p_picture->date );
@@ -1061,18 +1063,20 @@ static void DecoderPlayAudio( decoder_t *p_dec, block_t *p_audio,
 
     /* */
     vlc_mutex_lock( &p_owner->lock );
-    if( p_owner->b_waiting )
-    {
-        p_owner->b_has_data = true;
-        vlc_cond_signal( &p_owner->wait_acknowledge );
-    }
 
     /* */
     int i_rate = INPUT_RATE_DEFAULT;
 
-    DecoderWaitUnblock( p_dec );
+    if( DecoderWaitUnblock( p_dec ) )
+    {
+        *pi_lost_sum += 1;
+        block_Release( p_audio );
+        vlc_mutex_unlock( &p_owner->lock );
+        return;
+    }
     DecoderFixTs( p_dec, &p_audio->i_pts, NULL, &p_audio->i_length,
                   &i_rate, AOUT_MAX_ADVANCE_TIME );
+
     vlc_mutex_unlock( &p_owner->lock );
 
     audio_output_t *p_aout = p_owner->p_aout;
@@ -1242,13 +1246,12 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic )
     /* */
     vlc_mutex_lock( &p_owner->lock );
 
-    if( p_owner->b_waiting )
+    if( DecoderWaitUnblock( p_dec ) )
     {
-        p_owner->b_has_data = true;
-        vlc_cond_signal( &p_owner->wait_acknowledge );
+        subpicture_Delete( p_subpic );
+        vlc_mutex_unlock( &p_owner->lock );
+        return;
     }
-
-    DecoderWaitUnblock( p_dec );
     DecoderFixTs( p_dec, &p_subpic->i_start, &p_subpic->i_stop, NULL,
                   NULL, INT64_MAX );
     vlc_mutex_unlock( &p_owner->lock );
@@ -1331,6 +1334,11 @@ static void DecoderProcess( decoder_t *p_dec, block_t *p_block )
     {
         if( p_block )
             block_Release( p_block );
+
+        /* In case of error, signal to the owner to don't wait for us */
+        vlc_mutex_lock( &p_owner->lock );
+        p_owner->b_ready = true;
+        vlc_mutex_unlock( &p_owner->lock );
         return;
     }
 
@@ -1343,6 +1351,7 @@ static void DecoderProcess( decoder_t *p_dec, block_t *p_block )
     if( p_block )
     {
         vlc_mutex_lock( &p_owner->lock );
+        p_owner->b_has_input = true;
         DecoderUpdatePreroll( &p_owner->i_preroll_end, p_block );
         vlc_mutex_unlock( &p_owner->lock );
     }
@@ -1478,9 +1487,7 @@ static void *DecoderThread( void *p_data )
 
         if( p_owner->paused && p_owner->frames_countdown == 0 )
         {   /* Wait for resumption from pause */
-            p_owner->b_idle = true;
             vlc_fifo_Wait( p_owner->p_fifo );
-            p_owner->b_idle = false;
             continue;
         }
 
@@ -1492,9 +1499,7 @@ static void *DecoderThread( void *p_data )
         {
             if( likely(!p_owner->b_draining) )
             {   /* Wait for a block to decode (or a request to drain) */
-                p_owner->b_idle = true;
                 vlc_fifo_Wait( p_owner->p_fifo );
-                p_owner->b_idle = false;
                 continue;
             }
             /* We have emptied the FIFO and there is a pending request to
@@ -1519,10 +1524,7 @@ static void *DecoderThread( void *p_data )
          * sufficient. TODO? Wait for draining instead of polling. */
         atomic_store( &p_owner->drained, (p_block == NULL) );
 
-        vlc_mutex_lock( &p_owner->lock );
         vlc_fifo_Lock( p_owner->p_fifo );
-        vlc_cond_signal( &p_owner->wait_acknowledge );
-        vlc_mutex_unlock( &p_owner->lock );
     }
     vlc_cleanup_pop();
     vlc_assert_unreachable();
@@ -1577,13 +1579,12 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     p_owner->frames_countdown = 0;
 
     p_owner->b_waiting = false;
-    p_owner->b_first = true;
-    p_owner->b_has_data = false;
+    p_owner->b_ready = false;
+    p_owner->b_has_input = false;
 
     p_owner->flushing = false;
     p_owner->b_draining = false;
     atomic_init( &p_owner->drained, false );
-    p_owner->b_idle = false;
 
     es_format_Init( &p_owner->fmt, UNKNOWN_ES, 0 );
 
@@ -1598,7 +1599,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
 
     vlc_mutex_init( &p_owner->lock );
     vlc_cond_init( &p_owner->wait_request );
-    vlc_cond_init( &p_owner->wait_acknowledge );
     vlc_cond_init( &p_owner->wait_fifo );
     vlc_cond_init( &p_owner->wait_timed );
 
@@ -1749,7 +1749,6 @@ static void DeleteDecoder( decoder_t * p_dec )
 
     vlc_cond_destroy( &p_owner->wait_timed );
     vlc_cond_destroy( &p_owner->wait_fifo );
-    vlc_cond_destroy( &p_owner->wait_acknowledge );
     vlc_cond_destroy( &p_owner->wait_request );
     vlc_mutex_destroy( &p_owner->lock );
 
@@ -1959,6 +1958,17 @@ bool input_DecoderIsEmpty( decoder_t * p_dec )
     return b_empty;
 }
 
+bool input_DecoderIsReady( decoder_t * p_dec )
+{
+    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+
+    vlc_mutex_lock( &p_owner->lock );
+    bool b_ready = p_owner->b_ready;
+    vlc_mutex_unlock( &p_owner->lock );
+
+    return b_ready;
+}
+
 /**
  * Signals that there are no further blocks to decode, and requests that the
  * decoder drain all pending buffers. This is used to ensure that all
@@ -2121,8 +2131,8 @@ void input_DecoderStartWait( decoder_t *p_dec )
     assert( !p_owner->b_waiting );
 
     vlc_mutex_lock( &p_owner->lock );
-    p_owner->b_first = true;
-    p_owner->b_has_data = false;
+    p_owner->b_has_input = false;
+    p_owner->b_ready = false;
     p_owner->b_waiting = true;
     vlc_cond_signal( &p_owner->wait_request );
     vlc_mutex_unlock( &p_owner->lock );
@@ -2140,32 +2150,6 @@ void input_DecoderStopWait( decoder_t *p_dec )
     vlc_mutex_unlock( &p_owner->lock );
 }
 
-void input_DecoderWait( decoder_t *p_dec )
-{
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
-    assert( p_owner->b_waiting );
-
-    vlc_mutex_lock( &p_owner->lock );
-    while( !p_owner->b_has_data )
-    {
-        /* Don't need to lock p_owner->paused since it's only modified by the
-         * owner */
-        if( p_owner->paused )
-            break;
-        vlc_fifo_Lock( p_owner->p_fifo );
-        if( p_owner->b_idle && vlc_fifo_IsEmpty( p_owner->p_fifo ) )
-        {
-            msg_Err( p_dec, "buffer deadlock prevented" );
-            vlc_fifo_Unlock( p_owner->p_fifo );
-            break;
-        }
-        vlc_fifo_Unlock( p_owner->p_fifo );
-        vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
-    }
-    vlc_mutex_unlock( &p_owner->lock );
-}
-
 void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
diff --git a/src/input/decoder.h b/src/input/decoder.h
index f773eb7..3c2af36 100644
--- a/src/input/decoder.h
+++ b/src/input/decoder.h
@@ -49,11 +49,6 @@ void input_DecoderChangeDelay( decoder_t *, mtime_t i_delay );
 void input_DecoderStartWait( decoder_t * );
 
 /**
- * This function waits for the decoder to actually receive data.
- */
-void input_DecoderWait( decoder_t * );
-
-/**
  * This function exits the waiting mode of the decoder.
  */
 void input_DecoderStopWait( decoder_t * );
@@ -64,6 +59,11 @@ void input_DecoderStopWait( decoder_t * );
 bool input_DecoderIsEmpty( decoder_t * );
 
 /**
+ * This function returns true if the decoder is ready to output something.
+ */
+bool input_DecoderIsReady( decoder_t * );
+
+/**
  * This function activates the request closed caption channel.
  */
 int input_DecoderSetCcState( decoder_t *, bool b_decode, int i_channel );
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 72dbbde..dbd1e86 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -92,6 +92,7 @@ struct es_out_id_t
 
     decoder_t   *p_dec;
     decoder_t   *p_dec_record;
+    bool         b_has_data;
 
     /* Fields for Video with CC */
     bool  pb_cc_present[4];
@@ -162,9 +163,11 @@ struct es_out_sys_t
 
     /* Used for buffering */
     bool        b_buffering;
+    bool        b_decoders_waiting;
     mtime_t     i_buffering_extra_initial;
     mtime_t     i_buffering_extra_stream;
     mtime_t     i_buffering_extra_system;
+    mtime_t     i_buffering_duration;
 
     /* Record */
     sout_instance_t *p_sout_record;
@@ -192,6 +195,7 @@ static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_da
 static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date );
 static void EsOutProgramsChangeRate( es_out_t *out );
 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced );
+static void EsOutDecodersWaitBuffering( es_out_t *out );
 
 static char *LanguageGetName( const char *psz_code );
 static char *LanguageGetCode( const char *psz_lang );
@@ -296,9 +300,12 @@ es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
     p_sys->i_rate = i_rate;
 
     p_sys->b_buffering = true;
+    p_sys->b_decoders_waiting = true;
     p_sys->i_preroll_end = -1;
     p_sys->i_prev_stream_level = -1;
 
+    p_sys->i_buffering_duration = 0;
+
     return out;
 }
 
@@ -368,6 +375,12 @@ static void EsOutTerminate( es_out_t *out )
     input_SendEventMetaEpg( p_sys->p_input );
 }
 
+static bool EsOutBuffering( es_out_t *out )
+{
+    es_out_sys_t *p_sys = out->p_sys;
+    return p_sys->b_buffering || p_sys->b_decoders_waiting;
+}
+
 static mtime_t EsOutGetWakeup( es_out_t *out )
 {
     es_out_sys_t   *p_sys = out->p_sys;
@@ -416,6 +429,22 @@ static bool EsOutDecodersIsEmpty( es_out_t *out )
             return true;
     }
 
+    if( p_sys->b_decoders_waiting )
+    {
+        for( int i = 0; i < p_sys->i_es; i++ )
+        {
+            es_out_id_t *p_es = p_sys->es[i];
+
+            if( !p_es->p_dec )
+                continue;
+
+            input_DecoderStopWait( p_es->p_dec );
+            if( p_es->p_dec_record )
+                input_DecoderStopWait( p_es->p_dec_record );
+        }
+        p_sys->b_decoders_waiting = false;
+    }
+
     for( int i = 0; i < p_sys->i_es; i++ )
     {
         es_out_id_t *es = p_sys->es[i];
@@ -572,6 +601,7 @@ static void EsOutChangePosition( es_out_t *out )
     es_out_sys_t      *p_sys = out->p_sys;
 
     input_SendEventCache( p_sys->p_input, 0.0 );
+    p_sys->i_buffering_duration = 0;
 
     for( int i = 0; i < p_sys->i_es; i++ )
     {
@@ -579,13 +609,20 @@ static void EsOutChangePosition( es_out_t *out )
 
         if( p_es->p_dec != NULL )
         {
-            input_DecoderFlush( p_es->p_dec );
-            if( !p_sys->b_buffering )
+            /* Stop waiting before flush to unblock decoders that are waiting */
+            if( p_sys->b_decoders_waiting )
             {
-                input_DecoderStartWait( p_es->p_dec );
+                input_DecoderStopWait( p_es->p_dec );
                 if( p_es->p_dec_record != NULL )
-                    input_DecoderStartWait( p_es->p_dec_record );
+                    input_DecoderStopWait( p_es->p_dec_record );
             }
+
+            input_DecoderFlush( p_es->p_dec );
+            p_es->b_has_data = false;
+
+            input_DecoderStartWait( p_es->p_dec );
+            if( p_es->p_dec_record != NULL )
+                input_DecoderStartWait( p_es->p_dec_record );
         }
     }
 
@@ -593,6 +630,7 @@ static void EsOutChangePosition( es_out_t *out )
         input_clock_Reset( p_sys->pgrm[i]->p_clock );
 
     p_sys->b_buffering = true;
+    p_sys->b_decoders_waiting = true;
     p_sys->i_buffering_extra_initial = 0;
     p_sys->i_buffering_extra_stream = 0;
     p_sys->i_buffering_extra_system = 0;
@@ -600,8 +638,6 @@ static void EsOutChangePosition( es_out_t *out )
     p_sys->i_prev_stream_level = -1;
 }
 
-
-
 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
 {
     es_out_sys_t *p_sys = out->p_sys;
@@ -648,6 +684,15 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
     p_sys->b_buffering = false;
     p_sys->i_preroll_end = -1;
     p_sys->i_prev_stream_level = -1;
+    p_sys->i_buffering_duration = i_buffering_duration;
+}
+
+/* EsOutDecodersWaitBuffering: Non blocking function that will signal all
+ * decoders to stop waiting when they are all ready to output.
+ */
+static void EsOutDecodersWaitBuffering( es_out_t *out )
+{
+    es_out_sys_t *p_sys = out->p_sys;
 
     if( p_sys->i_buffering_extra_initial > 0 )
     {
@@ -655,20 +700,18 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
         return;
     }
 
-    const mtime_t i_decoder_buffering_start = mdate();
-    for( int i = 0; i < p_sys->i_es; i++ )
+    /* Return if decoders are not ready */
+    if( !p_sys->b_paused )
     {
-        es_out_id_t *p_es = p_sys->es[i];
-
-        if( !p_es->p_dec || p_es->fmt.i_cat == SPU_ES )
-            continue;
-        input_DecoderWait( p_es->p_dec );
-        if( p_es->p_dec_record )
-            input_DecoderWait( p_es->p_dec_record );
+        for( int i = 0; i < p_sys->i_es; i++ )
+        {
+            es_out_id_t *id = p_sys->es[i];
+            if( id->p_dec != NULL && id->b_has_data && !input_DecoderIsReady( id->p_dec ) )
+                return;
+        }
     }
 
-    msg_Dbg( p_sys->p_input, "Decoder wait done in %d ms",
-              (int)(mdate() - i_decoder_buffering_start)/1000 );
+    msg_Dbg( p_sys->p_input, "Decoder wait done" );
 
     /* Here is a good place to destroy unused vout with every demuxer */
     input_resource_TerminateVout( p_sys->p_input->p->p_resource );
@@ -678,7 +721,7 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
     const mtime_t i_current_date = p_sys->b_paused ? p_sys->i_pause_date : mdate();
 
     input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_clock, true,
-                                    i_current_date + i_wakeup_delay - i_buffering_duration );
+                                    i_current_date + i_wakeup_delay - p_sys->i_buffering_duration );
 
     for( int i = 0; i < p_sys->i_es; i++ )
     {
@@ -691,7 +734,9 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
         if( p_es->p_dec_record )
             input_DecoderStopWait( p_es->p_dec_record );
     }
+    p_sys->b_decoders_waiting = false;
 }
+
 static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
 {
     es_out_sys_t *p_sys = out->p_sys;
@@ -773,7 +818,7 @@ static void EsOutFrameNext( es_out_t *out )
     es_out_sys_t *p_sys = out->p_sys;
     es_out_id_t *p_es_video = NULL;
 
-    if( p_sys->b_buffering )
+    if( EsOutBuffering( out ) )
     {
         msg_Warn( p_sys->p_input, "buffering, ignoring 'frame next'" );
         return;
@@ -856,7 +901,7 @@ static mtime_t EsOutGetBuffering( es_out_t *out )
 
     mtime_t i_delay;
 
-    if( p_sys->b_buffering && p_sys->i_buffering_extra_initial <= 0 )
+    if( EsOutBuffering( out ) && p_sys->i_buffering_extra_initial <= 0 )
     {
         i_delay = i_stream_duration;
     }
@@ -1503,6 +1548,7 @@ static es_out_id_t *EsOutAdd( es_out_t *out, const es_format_t *fmt )
     es->psz_language = LanguageGetName( es->fmt.psz_language ); /* remember so we only need to do it once */
     es->psz_language_code = LanguageGetCode( es->fmt.psz_language );
     es->p_dec = NULL;
+    es->b_has_data = false;
     es->p_dec_record = NULL;
     for( i = 0; i < 4; i++ )
         es->pb_cc_present[i] = false;
@@ -1558,6 +1604,7 @@ static bool EsIsSelected( es_out_id_t *es )
         return es->p_dec != NULL;
     }
 }
+
 static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es )
 {
     es_out_sys_t   *p_sys = out->p_sys;
@@ -1988,6 +2035,8 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
     }
 
     /* Decode */
+    if( !( p_block->i_flags & BLOCK_FLAG_PREROLL ))
+        es->b_has_data = true;
     if( es->p_dec_record )
     {
         block_t *p_dup = block_Duplicate( p_block );
@@ -2341,7 +2390,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
         bool b_late;
         input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input),
                             &b_late,
-                            p_sys->p_input->p->b_can_pace_control || p_sys->b_buffering,
+                            p_sys->p_input->p->b_can_pace_control || EsOutBuffering( out ),
                             EsOutIsExtraBufferingAllowed( out ),
                             i_pcr, mdate() );
 
@@ -2353,7 +2402,12 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
             /* Check buffering state on master clock update */
             EsOutDecodersStopBuffering( out, false );
         }
-        else if( p_pgrm == p_sys->p_pgrm )
+        if( !p_sys->b_buffering && p_sys->b_decoders_waiting )
+        {
+            EsOutDecodersWaitBuffering( out );
+        }
+        if( !p_sys->b_buffering && !p_sys->b_decoders_waiting
+          && p_pgrm == p_sys->p_pgrm )
         {
             if( b_late && ( !p_sys->p_input->p->p_sout ||
                                  !p_sys->p_input->p->b_out_pace_control ) )
@@ -2554,7 +2608,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
     case ES_OUT_GET_BUFFERING:
     {
         bool *pb = va_arg( args, bool* );
-        *pb = p_sys->b_buffering;
+        *pb = EsOutBuffering( out );
         return VLC_SUCCESS;
     }
 
@@ -2624,7 +2678,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
 
         input_SendEventLength( p_sys->p_input, i_length );
 
-        if( !p_sys->b_buffering )
+        if( !EsOutBuffering( out ) )
         {
             mtime_t i_delay;
 
@@ -2671,7 +2725,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
 
     case ES_OUT_GET_PCR_SYSTEM:
     {
-        if( p_sys->b_buffering )
+        if( EsOutBuffering( out ) )
             return VLC_EGENERIC;
 
         es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
@@ -2686,7 +2740,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
 
     case ES_OUT_MODIFY_PCR_SYSTEM:
     {
-        if( p_sys->b_buffering )
+        if( EsOutBuffering( out ) )
             return VLC_EGENERIC;
 
         es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
-- 
2.1.4



More information about the vlc-devel mailing list