[vlc-commits] [Git][videolan/vlc][master] 4 commits: decoder: add vlc_input_decoder_IsDrained()

Steve Lhomme (@robUx4) gitlab at videolan.org
Thu Nov 27 08:46:44 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
ef85344c by Thomas Guillem at 2025-11-27T07:52:11+00:00
decoder: add vlc_input_decoder_IsDrained()

Polling is still ugly, but I don't think it's wise to change this
behavior in vout and aout for now.

- - - - -
5eb0c9c4 by Thomas Guillem at 2025-11-27T07:52:11+00:00
decoder: move draining check

No functional changes as IsDrained() is only used by IsEmpty()
internally.

- - - - -
bd68f989 by Thomas Guillem at 2025-11-27T07:52:11+00:00
es_out: use vlc_input_decoder_IsDrained() when applicable

- - - - -
82db8c43 by Thomas Guillem at 2025-11-27T07:52:11+00:00
es_out: don't flush decoders if drained

As the doc says:

"The instance must have been drained using vlc_input_decoder_Drain() or
flushed using vlc_input_decoder_Flush() after any previous call to
vlc_input_decoder_Decode() before calling the destructor."

This will allow not flushing outputs when doing gapless transition.

Fixes #28463

- - - - -


5 changed files:

- include/vlc_decoder.h
- src/input/decoder.c
- src/input/es_out.c
- src/input/test/es_out.c
- src/libvlccore.sym


Changes:

=====================================
include/vlc_decoder.h
=====================================
@@ -85,6 +85,15 @@ VLC_API void vlc_input_decoder_Decode( vlc_input_decoder_t *p_dec, struct vlc_fr
  */
 VLC_API void vlc_input_decoder_Drain( vlc_input_decoder_t * );
 
+/**
+ * Returns the drained state
+ *
+ * @warning This function need to be polled (every few ms) to know when the
+ * decoder is drained
+ * @return true if drained (after a call to vlc_input_decoder_Drain())
+ */
+ VLC_API bool vlc_input_decoder_IsDrained( vlc_input_decoder_t * );
+
 /**
  * Requests that the decoder immediately discard all pending buffers.
  * This is useful when seeking or when deselecting a stream.


=====================================
src/input/decoder.c
=====================================
@@ -2486,27 +2486,41 @@ void vlc_input_decoder_Decode(vlc_input_decoder_t *p_owner, vlc_frame_t *frame,
     vlc_input_decoder_DecodeWithStatus(p_owner, frame, b_do_pace, NULL);
 }
 
+static bool vlc_input_decoder_IsDrainedLocked(vlc_input_decoder_t *owner)
+{
+    vlc_fifo_Assert(owner->p_fifo);
+
+    if (owner->p_sout_input != NULL)
+        return true;
+    else if (owner->fmt.i_cat == VIDEO_ES && owner->video.vout != NULL)
+        return vout_IsEmpty(owner->video.vout);
+    else if(owner->fmt.i_cat == AUDIO_ES && owner->audio.stream != NULL)
+        return vlc_aout_stream_IsDrained( owner->audio.stream);
+    else
+        return true; /* TODO subtitles support */
+}
+
+bool vlc_input_decoder_IsDrained(vlc_input_decoder_t *owner)
+{
+    vlc_fifo_Lock(owner->p_fifo);
+    bool drained = !owner->b_draining && vlc_input_decoder_IsDrainedLocked(owner);
+    vlc_fifo_Unlock(owner->p_fifo);
+    return drained;
+}
+
 bool vlc_input_decoder_IsEmpty( vlc_input_decoder_t * p_owner )
 {
     assert( !p_owner->b_waiting );
 
     vlc_fifo_Lock( p_owner->p_fifo );
-    if( !vlc_fifo_IsEmpty( p_owner->p_fifo ) || p_owner->b_draining )
+    if( !vlc_fifo_IsEmpty( p_owner->p_fifo ) )
     {
         vlc_fifo_Unlock( p_owner->p_fifo );
         return false;
     }
 
-    bool b_empty;
+    bool b_empty = vlc_input_decoder_IsDrainedLocked( p_owner );
 
-    if( p_owner->p_sout_input != NULL )
-        b_empty = true;
-    else if( p_owner->fmt.i_cat == VIDEO_ES && p_owner->video.vout != NULL )
-        b_empty = vout_IsEmpty( p_owner->video.vout );
-    else if( p_owner->fmt.i_cat == AUDIO_ES && p_owner->audio.stream != NULL )
-        b_empty = vlc_aout_stream_IsDrained( p_owner->audio.stream );
-    else
-        b_empty = true; /* TODO subtitles support */
     vlc_fifo_Unlock( p_owner->p_fifo );
 
     return b_empty;


=====================================
src/input/es_out.c
=====================================
@@ -663,7 +663,8 @@ static void EsOutTerminate(es_out_sys_t *p_sys)
     {
         if (es->p_dec != NULL)
         {
-            vlc_input_decoder_Flush(es->p_dec);
+            if (!vlc_input_decoder_IsDrained(es->p_dec))
+                vlc_input_decoder_Flush(es->p_dec);
             vlc_input_decoder_Delete(es->p_dec);
         }
 
@@ -2455,7 +2456,8 @@ static void EsOutDestroyDecoder(es_out_sys_t *sys,
 
     EsOutDeleteSubESes(sys, p_es);
 
-    vlc_input_decoder_Flush(p_es->p_dec);
+    if (!vlc_input_decoder_IsDrained(p_es->p_dec))
+        vlc_input_decoder_Flush(p_es->p_dec);
     vlc_input_decoder_Delete( p_es->p_dec );
     p_es->p_dec = NULL;
     if( p_es->p_pgrm->p_master_es_clock == p_es->p_clock )
@@ -2468,7 +2470,8 @@ static void EsOutDestroyDecoder(es_out_sys_t *sys,
 
     if( p_es->p_dec_record )
     {
-        vlc_input_decoder_Flush(p_es->p_dec_record);
+        if (!vlc_input_decoder_IsDrained(p_es->p_dec_record))
+            vlc_input_decoder_Flush(p_es->p_dec_record);
         vlc_input_decoder_Delete( p_es->p_dec_record );
         p_es->p_dec_record = NULL;
     }
@@ -3090,8 +3093,8 @@ EsOutDrainDecoder(es_out_sys_t *p_sys, es_out_id_t *es, bool wait)
      * bit too long if the ES is deleted in the middle of a stream. */
     while( !input_Stopped(p_sys->p_input) && !p_sys->b_buffering )
     {
-        if( vlc_input_decoder_IsEmpty( es->p_dec ) &&
-            ( !es->p_dec_record || vlc_input_decoder_IsEmpty( es->p_dec_record ) ))
+        if( vlc_input_decoder_IsDrained( es->p_dec ) &&
+            ( !es->p_dec_record || vlc_input_decoder_IsDrained( es->p_dec_record ) ))
             break;
         /* FIXME there should be a way to have auto deleted es, but there will be
          * a problem when another codec of the same type is created (mainly video) */


=====================================
src/input/test/es_out.c
=====================================
@@ -138,12 +138,17 @@ void vlc_input_decoder_StopWait(vlc_input_decoder_t *owner)
     owner->started = true;
 }
 
-bool vlc_input_decoder_IsEmpty(vlc_input_decoder_t *owner)
+bool vlc_input_decoder_IsDrained(vlc_input_decoder_t *owner)
 {
     (void)owner;
     return owner->drained;
 }
 
+bool vlc_input_decoder_IsEmpty(vlc_input_decoder_t *owner)
+{
+    return vlc_input_decoder_IsDrained(owner);
+}
+
 void vlc_input_decoder_DecodeWithStatus(
     vlc_input_decoder_t *owner,
     vlc_frame_t *frame,


=====================================
src/libvlccore.sym
=====================================
@@ -188,6 +188,7 @@ vlc_input_decoder_Create
 vlc_input_decoder_Delete
 vlc_input_decoder_Decode
 vlc_input_decoder_Drain
+vlc_input_decoder_IsDrained
 vlc_input_decoder_Flush
 vlc_input_decoder_SetSpuHighlight
 vlc_input_decoder_ChangeDelay



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fd3b0b3ec5e7c4472c7894ea64a9cdfa0676bab6...82db8c43c1433ef26e1f27cd85cb54d4285135db

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fd3b0b3ec5e7c4472c7894ea64a9cdfa0676bab6...82db8c43c1433ef26e1f27cd85cb54d4285135db
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