[vlc-devel] [PATCH 1/3] decoder: unblock input thread when interrupted

Thomas Guillem thomas at gllm.fr
Mon Feb 12 18:13:24 CET 2018


When not paced, input_DecoderDecode() called from
(input_thread_t->demux->es_out) can wait for the DecoderThread to empty its
FIFO. This can take a very long time with inputs that need a big buffering (cf.
ACCESS/DEMUX PTS_DELAY) or if sout inputs are blocked in IO.

I also took the opportunity to unblock input_DecoderWait(), not sure if really
needed. I didn't saw any deadlock in that part but I guess it can happen too.
---
 src/input/decoder.c | 56 ++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 45 insertions(+), 11 deletions(-)

diff --git a/src/input/decoder.c b/src/input/decoder.c
index 98817e6f39..8ec8ee4131 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -129,6 +129,8 @@ struct decoder_owner_sys_t
     atomic_bool drained;
     bool b_idle;
 
+    bool interrupted;
+
     /* CC */
 #define MAX_CC_DECODERS 64 /* The es_out only creates one type of es */
     struct
@@ -1695,6 +1697,7 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
     p_owner->drained = false;
     atomic_init( &p_owner->reload, RELOAD_NO_REQUEST );
     p_owner->b_idle = false;
+    p_owner->interrupted = false;
 
     es_format_Init( &p_owner->fmt, fmt->i_cat, 0 );
 
@@ -2031,6 +2034,19 @@ void input_DecoderDelete( decoder_t *p_dec )
     DeleteDecoder( p_dec );
 }
 
+static void interrupted_cb(void *data)
+{
+    decoder_t *p_dec = data;
+    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+
+    vlc_fifo_Lock( p_owner->p_fifo );
+    p_owner->interrupted = true;
+    vlc_fifo_Unlock( p_owner->p_fifo );
+
+    vlc_cond_signal( &p_owner->wait_fifo );
+    vlc_cond_signal( &p_owner->wait_acknowledge );
+}
+
 /**
  * Put a block_t in the decoder's fifo.
  * Thread-safe w.r.t. the decoder. May be a cancellation point.
@@ -2042,9 +2058,9 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block, bool b_do_pace )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
 
-    vlc_fifo_Lock( p_owner->p_fifo );
     if( !b_do_pace )
     {
+        vlc_fifo_Lock( p_owner->p_fifo );
         /* FIXME: ideally we would check the time amount of data
          * in the FIFO instead of its size. */
         /* 400 MiB, i.e. ~ 50mb/s for 60s */
@@ -2055,18 +2071,31 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block, bool b_do_pace )
             block_ChainRelease( vlc_fifo_DequeueAllUnlocked( p_owner->p_fifo ) );
             p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
         }
+
+        vlc_fifo_QueueUnlocked( p_owner->p_fifo, p_block );
+        vlc_fifo_Unlock( p_owner->p_fifo );
     }
     else
-    if( !p_owner->b_waiting )
-    {   /* The FIFO is not consumed when waiting, so pacing would deadlock VLC.
-         * Locking is not necessary as b_waiting is only read, not written by
-         * the decoder thread. */
-        while( vlc_fifo_GetCount( p_owner->p_fifo ) >= 10 )
-            vlc_fifo_WaitCond( p_owner->p_fifo, &p_owner->wait_fifo );
-    }
+    {
+        vlc_interrupt_register( interrupted_cb, p_dec );
+        vlc_fifo_Lock( p_owner->p_fifo );
 
-    vlc_fifo_QueueUnlocked( p_owner->p_fifo, p_block );
-    vlc_fifo_Unlock( p_owner->p_fifo );
+        if( !p_owner->b_waiting )
+        {   /* The FIFO is not consumed when waiting, so pacing would deadlock VLC.
+             * Locking is not necessary as b_waiting is only read, not written by
+             * the decoder thread. */
+            while( !p_owner->interrupted && vlc_fifo_GetCount( p_owner->p_fifo ) >= 10 )
+                vlc_fifo_WaitCond( p_owner->p_fifo, &p_owner->wait_fifo );
+        }
+
+        if( p_owner->interrupted )
+            block_Release( p_block );
+        else
+            vlc_fifo_QueueUnlocked( p_owner->p_fifo, p_block );
+
+        vlc_fifo_Unlock( p_owner->p_fifo );
+        vlc_interrupt_unregister();
+    }
 }
 
 bool input_DecoderIsEmpty( decoder_t * p_dec )
@@ -2308,6 +2337,8 @@ void input_DecoderWait( decoder_t *p_dec )
 
     assert( p_owner->b_waiting );
 
+    vlc_interrupt_register(interrupted_cb, p_dec);
+
     vlc_mutex_lock( &p_owner->lock );
     while( !p_owner->b_has_data )
     {
@@ -2316,7 +2347,8 @@ void input_DecoderWait( decoder_t *p_dec )
         if( p_owner->paused )
             break;
         vlc_fifo_Lock( p_owner->p_fifo );
-        if( p_owner->b_idle && vlc_fifo_IsEmpty( p_owner->p_fifo ) )
+        if( p_owner->interrupted
+         || ( 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 );
@@ -2326,6 +2358,8 @@ void input_DecoderWait( decoder_t *p_dec )
         vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
     }
     vlc_mutex_unlock( &p_owner->lock );
+
+    vlc_interrupt_unregister();
 }
 
 void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration )
-- 
2.11.0



More information about the vlc-devel mailing list