[vlc-devel] [PATCH 1/3] input/decoder: add decoder_DecodeAgain

Thomas Guillem thomas at gllm.fr
Fri Jan 20 17:06:08 CET 2017


This new function can be used to save an input block when a decoder module is
requesting a restart.

This can solve the issue when the first input block is lost after a hardware
decoder requested a restart while decoding this block.

This can't solve the issue when more than one input blocks are lost after a
hardware decoder requested a restart asynchronously (less common case).
---
 include/vlc_codec.h | 11 ++++++++++-
 src/input/decoder.c | 53 ++++++++++++++++++++++++++++++++++++++++-------------
 src/libvlccore.sym  |  1 +
 3 files changed, 51 insertions(+), 14 deletions(-)

diff --git a/include/vlc_codec.h b/include/vlc_codec.h
index af7b979fe2..b9655d639a 100644
--- a/include/vlc_codec.h
+++ b/include/vlc_codec.h
@@ -346,7 +346,7 @@ VLC_API block_t * decoder_NewAudioBuffer( decoder_t *, int i_size ) VLC_USED;
  */
 VLC_API subpicture_t * decoder_NewSubpicture( decoder_t *, const subpicture_updater_t * ) VLC_USED;
 
-/*
+/**
  * Request that the decoder should be reloaded. The current module will be
  * unloaded. Reloading a module may cause a loss of frames. There is no
  * warranty that pf_decode_* callbacks won't be called again after this call.
@@ -354,6 +354,15 @@ VLC_API subpicture_t * decoder_NewSubpicture( decoder_t *, const subpicture_upda
 VLC_API void decoder_RequestReload( decoder_t * );
 
 /**
+ * Request the DecoderThread to decode a block a second time. This function
+ * must be called from the pf_decode*() callback. This block must be the same
+ * than the one passed by the pf_decode*() callback. This can be used after a
+ * call to decoder_RequestReload() in order to don't loose the current input
+ * block.
+ */
+VLC_API void decoder_DecodeAgain( decoder_t *, block_t *p_block );
+
+/**
  * This function gives all input attachments at once.
  *
  * You MUST release the returned values
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 1e8189af09..36cbb48a6a 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -95,6 +95,8 @@ struct decoder_owner_sys_t
     /* fifo */
     block_fifo_t *p_fifo;
 
+    block_t      *p_fallback_block;
+
     /* Lock for communication with decoder thread */
     vlc_mutex_t lock;
     vlc_cond_t  wait_request;
@@ -144,6 +146,7 @@ struct decoder_owner_sys_t
 
 /* */
 #define DECODER_SPU_VOUT_WAIT_DURATION ((int)(0.200*CLOCK_FREQ))
+#define BLOCK_FLAG_CORE_PRIVATE_PACKETIZED (1 << BLOCK_FLAG_CORE_PRIVATE_SHIFT)
 
 /**
  * Load a decoder module
@@ -626,6 +629,15 @@ void decoder_RequestReload( decoder_t * p_dec )
     atomic_compare_exchange_strong( &p_owner->reload, &expected, RELOAD_DECODER );
 }
 
+void decoder_DecodeAgain( decoder_t *p_dec, block_t *p_block )
+{
+    decoder_owner_sys_t *p_owner = p_dec->p_owner;
+    assert( p_block->p_next == NULL && p_owner->p_fallback_block == NULL );
+    /* This block already went through pf_packetize */
+    p_block->i_flags |= BLOCK_FLAG_CORE_PRIVATE_PACKETIZED;
+    p_owner->p_fallback_block = p_block;
+}
+
 /* decoder_GetInputAttachments:
  */
 int decoder_GetInputAttachments( decoder_t *p_dec,
@@ -1059,7 +1071,8 @@ static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
 
-    if( p_owner->p_packetizer )
+    if( p_owner->p_packetizer
+     && !unlikely( p_block->i_flags & BLOCK_FLAG_CORE_PRIVATE_PACKETIZED ) )
     {
         block_t *p_packetized_block;
         block_t **pp_block = p_block ? &p_block : NULL;
@@ -1253,7 +1266,8 @@ static void DecoderProcessAudio( decoder_t *p_dec, block_t *p_block )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
 
-    if( p_owner->p_packetizer )
+    if( p_owner->p_packetizer
+     && !unlikely( p_block->i_flags & BLOCK_FLAG_CORE_PRIVATE_PACKETIZED ) )
     {
         block_t *p_packetized_block;
         block_t **pp_block = p_block ? &p_block : NULL;
@@ -1571,19 +1585,29 @@ static void *DecoderThread( void *p_data )
         vlc_cond_signal( &p_owner->wait_fifo );
         vlc_testcancel(); /* forced expedited cancellation in case of stop */
 
-        block_t *p_block = vlc_fifo_DequeueUnlocked( p_owner->p_fifo );
-        if( p_block == NULL )
+        block_t *p_block;
+        if( unlikely( p_owner->p_fallback_block != NULL ) )
+        {
+            p_block = p_owner->p_fallback_block;
+            p_owner->p_fallback_block = NULL;
+        }
+        else
         {
-            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;
+            p_block = vlc_fifo_DequeueUnlocked( p_owner->p_fifo );
+
+            if( p_block == NULL )
+            {
+                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
+                 * drain. Pass p_block = NULL to decoder just once. */
+                p_owner->b_draining = false;
             }
-            /* We have emptied the FIFO and there is a pending request to
-             * drain. Pass p_block = NULL to decoder just once. */
-            p_owner->b_draining = false;
         }
 
         vlc_fifo_Unlock( p_owner->p_fifo );
@@ -1680,6 +1704,7 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
         vlc_object_release( p_dec );
         return NULL;
     }
+    p_owner->p_fallback_block = NULL;
 
     vlc_mutex_init( &p_owner->lock );
     vlc_cond_init( &p_owner->wait_request );
@@ -1780,6 +1805,8 @@ static void DeleteDecoder( decoder_t * p_dec )
 
     /* Free all packets still in the decoder fifo. */
     block_FifoRelease( p_owner->p_fifo );
+    if( unlikely( p_owner->p_fallback_block != NULL ) )
+        block_Release( p_owner->p_fallback_block );
 
     /* Cleanup */
     if( p_owner->p_aout )
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 7b9657a4b1..9d14fd2ee2 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -76,6 +76,7 @@ date_Init
 date_Move
 date_Set
 decoder_AbortPictures
+decoder_DecodeAgain
 decoder_GetDisplayDate
 decoder_GetDisplayRate
 decoder_GetInputAttachments
-- 
2.11.0



More information about the vlc-devel mailing list