[vlc-commits] [Git][videolan/vlc][master] 3 commits: decoder: handle potential DecoderWaitUnblock return

Thomas Guillem (@tguillem) gitlab at videolan.org
Fri Nov 24 20:00:00 UTC 2023



Thomas Guillem pushed to branch master at VideoLAN / VLC


Commits:
8a967f0d by Thomas Guillem at 2023-11-24T19:27:58+00:00
decoder: handle potential DecoderWaitUnblock return

If a wait failed (in case of flush for example, cf. next commit), the
current frame should not be displayed.

- - - - -
3f1bf4e4 by Thomas Guillem at 2023-11-24T19:27:58+00:00
decoder: cancel DecoderWaitUnblock on Flush()

This fixes clock being updated by a point that was decoded just before a flush.

- - - - -
5e9747b6 by Thomas Guillem at 2023-11-24T19:27:58+00:00
test: player: also test without master source

Add a new test: test_src_player_monotonic_clock, same than
test_src_player but with a monotonic clock.

But with one restriction on "test_timers", cf. comment.

- - - - -


3 changed files:

- src/input/decoder.c
- test/Makefile.am
- test/src/player/player.c


Changes:

=====================================
src/input/decoder.c
=====================================
@@ -1029,7 +1029,7 @@ static void RequestReload( vlc_input_decoder_t *p_owner )
     atomic_compare_exchange_strong( &p_owner->reload, &expected, RELOAD_DECODER );
 }
 
-static void DecoderWaitUnblock( vlc_input_decoder_t *p_owner )
+static int DecoderWaitUnblock( vlc_input_decoder_t *p_owner )
 {
     vlc_fifo_Assert(p_owner->p_fifo);
 
@@ -1039,8 +1039,17 @@ static void DecoderWaitUnblock( vlc_input_decoder_t *p_owner )
         vlc_cond_signal( &p_owner->wait_acknowledge );
     }
 
-    while( p_owner->b_waiting && p_owner->b_has_data )
+    while (p_owner->b_waiting && p_owner->b_has_data && !p_owner->flushing)
         vlc_fifo_WaitCond(p_owner->p_fifo, &p_owner->wait_request);
+
+    if (p_owner->flushing)
+    {
+        p_owner->b_has_data = false;
+        vlc_cond_signal(&p_owner->wait_acknowledge);
+        return VLC_ENOENT;
+    }
+
+    return VLC_SUCCESS;
 }
 
 static inline void DecoderUpdatePreroll( vlc_tick_t *pi_preroll, const vlc_frame_t *p )
@@ -1350,7 +1359,12 @@ static int ModuleThread_PlayVideo( vlc_input_decoder_t *p_owner, picture_t *p_pi
     }
     else
     {
-        DecoderWaitUnblock( p_owner );
+        int ret = DecoderWaitUnblock(p_owner);
+        if (ret != VLC_SUCCESS)
+        {
+            picture_Release(p_picture);
+            return ret;
+        }
     }
 
     if( unlikely(p_owner->paused) && likely(p_owner->frames_countdown > 0) )
@@ -1487,7 +1501,12 @@ static int ModuleThread_PlayAudio( vlc_input_decoder_t *p_owner, vlc_frame_t *p_
         vlc_aout_stream_Flush( p_astream );
     }
 
-    DecoderWaitUnblock( p_owner );
+    int ret = DecoderWaitUnblock(p_owner);
+    if (ret != VLC_SUCCESS)
+    {
+        block_Release(p_audio);
+        return ret;
+    }
 
     int status = vlc_aout_stream_Play( p_astream, p_audio );
     if( status == AOUT_DEC_CHANGED )
@@ -1550,10 +1569,10 @@ static void ModuleThread_PlaySpu( vlc_input_decoder_t *p_owner, subpicture_t *p_
 
     /* */
     vlc_fifo_Lock(p_owner->p_fifo);
-    DecoderWaitUnblock( p_owner );
+    int ret = DecoderWaitUnblock(p_owner);
     vlc_fifo_Unlock(p_owner->p_fifo);
 
-    if( p_subpic->i_start == VLC_TICK_INVALID )
+    if (ret != VLC_SUCCESS || p_subpic->i_start == VLC_TICK_INVALID)
     {
         subpicture_Delete( p_subpic );
         return;
@@ -2538,6 +2557,23 @@ void vlc_input_decoder_Flush( vlc_input_decoder_t *p_owner )
         }
     }
     vlc_fifo_Signal( p_owner->p_fifo );
+
+    if (unlikely(p_owner->b_waiting && p_owner->b_has_data))
+    {
+        /* Signal the output thread to stop waiting from DecoderWaitUnblock()
+         * and to discard the current frame (via 'flushing' = true). */
+        vlc_cond_signal(&p_owner->wait_request);
+
+        /* Flushing is fully asynchronous, but we need to wait for the output
+         * thread to unblock in DecoderWaitUnblock() otherwise there are no
+         * ways to know if the frame referenced when waiting comes from before
+         * or after the flush. Waiting here is almost instantaneous since we
+         * are sure that the output thread is waiting in DecoderWaitUnblock().
+         */
+        while (p_owner->b_has_data)
+            vlc_fifo_WaitCond(p_owner->p_fifo, &p_owner->wait_acknowledge);
+    }
+
     vlc_fifo_Unlock( p_owner->p_fifo );
 
     if (vlc_input_decoder_IsSynchronous(p_owner))


=====================================
test/Makefile.am
=====================================
@@ -32,6 +32,7 @@ check_PROGRAMS = \
 	test_src_input_thumbnail \
 	test_src_input_decoder \
 	test_src_player \
+	test_src_player_monotonic_clock \
 	test_src_interface_dialog \
 	test_src_media_source \
 	test_src_misc_bits \
@@ -179,6 +180,9 @@ test_src_input_thumbnail_SOURCES = src/input/thumbnail.c
 test_src_input_thumbnail_LDADD = $(LIBVLCCORE) $(LIBVLC)
 test_src_player_SOURCES = src/player/player.c
 test_src_player_LDADD = $(LIBVLCCORE) $(LIBVLC) $(LIBM)
+test_src_player_monotonic_clock_SOURCES = src/player/player.c
+test_src_player_monotonic_clock_CFLAGS = $(AM_CFLAGS) -DTEST_CLOCK_MONOTONIC
+test_src_player_monotonic_clock_LDADD = $(LIBVLCCORE) $(LIBVLC) $(LIBM)
 test_src_misc_bits_SOURCES = src/misc/bits.c
 test_src_misc_bits_LDADD = $(LIBVLC)
 test_src_misc_epg_SOURCES = src/misc/epg.c


=====================================
test/src/player/player.c
=====================================
@@ -2186,6 +2186,9 @@ ctx_init(struct ctx *ctx, enum ctx_flags flags)
         (flags & DISABLE_VIDEO) ? "--no-video" : "--video",
         (flags & DISABLE_AUDIO) ? "--no-audio" : "--audio",
         "--text-renderer=tdummy",
+#ifdef TEST_CLOCK_MONOTONIC
+        "--clock-master=monotonic",
+#endif
     };
     libvlc_instance_t *vlc = libvlc_new(ARRAY_SIZE(argv), argv);
     assert(vlc);
@@ -2425,6 +2428,12 @@ test_timers_playback(struct ctx *ctx, struct timer_state timers[],
         }
     }
 
+/* If there is no master source, we can't known which sources (audio or video)
+ * will feed the timer. Indeed the first source that trigger a clock update
+ * will be used as a timer source (and audio/video goes through decoder threads
+ * and output threads, adding more uncertainty). */
+#ifndef TEST_CLOCK_MONOTONIC
+
     /* Assertions for the regular timer that received all update points */
     if (track_count != 0)
     {
@@ -2474,6 +2483,7 @@ test_timers_playback(struct ctx *ctx, struct timer_state timers[],
             }
         }
     }
+#endif
 
     if (track_count > 0)
         test_timers_assert_smpte(&timers[SMPTE_TIMER_IDX], length, fps, false, 3);



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/597400f16506461777ae74173ef208b6d77e614d...5e9747b6db6973ed8af0e20512f547b6ec1900a8

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/597400f16506461777ae74173ef208b6d77e614d...5e9747b6db6973ed8af0e20512f547b6ec1900a8
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