[vlc-commits] [Git][videolan/vlc][master] 7 commits: input: add a workaround for next-frame

Steve Lhomme (@robUx4) gitlab at videolan.org
Tue Feb 14 10:42:54 UTC 2023



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
ea93b2c8 by Thomas Guillem at 2023-02-14T09:55:37+00:00
input: add a workaround for next-frame

Don't hack the buffering values, but fake the buffering state: tell the
input_thread to demux() until the vout has a picture.

Fixes #2951

- - - - -
9fe30c65 by Thomas Guillem at 2023-02-14T09:55:37+00:00
vout: remove now unused duration in vout_NextPicture

- - - - -
0306d70a by Thomas Guillem at 2023-02-14T09:55:37+00:00
vout: return an error if there is no new pictures to display next

Instead of reporting an error when the current picture fail to refresh
(unlikely).

- - - - -
e4430667 by Thomas Guillem at 2023-02-14T09:55:37+00:00
vout: add vout_control_ReleaseAndWake

Release and wake the control within the same lock instance.

Will be used by the next commit

- - - - -
c2f303cc by Thomas Guillem at 2023-02-14T09:55:37+00:00
vout: render next frame asynchronously

Smoother next-frame (when repeating next-frame key) and fix the next
frame sometime not being displayed, just after a seek.

Refs #2951

- - - - -
44a4e0b0 by Thomas Guillem at 2023-02-14T09:55:37+00:00
es_out: pause newly created decoders during next-frame

- - - - -
ff131672 by Thomas Guillem at 2023-02-14T09:55:37+00:00
es_out: don't decode paused decoders

This avoid to fill up the decoder FIFO for nothing (ESes will be flushed
on resume).

- - - - -


7 changed files:

- src/input/decoder.c
- src/input/decoder.h
- src/input/es_out.c
- src/video_output/control.c
- src/video_output/control.h
- src/video_output/video_output.c
- src/video_output/vout_internal.h


Changes:

=====================================
src/input/decoder.c
=====================================
@@ -2619,11 +2619,9 @@ void vlc_input_decoder_Wait( vlc_input_decoder_t *p_owner )
     vlc_fifo_Unlock(p_owner->p_fifo);
 }
 
-void vlc_input_decoder_FrameNext( vlc_input_decoder_t *p_owner,
-                                  vlc_tick_t *pi_duration )
+void vlc_input_decoder_FrameNext( vlc_input_decoder_t *p_owner )
 {
     assert( p_owner->paused );
-    *pi_duration = 0;
 
     vlc_fifo_Lock( p_owner->p_fifo );
     p_owner->frames_countdown++;
@@ -2634,7 +2632,7 @@ void vlc_input_decoder_FrameNext( vlc_input_decoder_t *p_owner,
     if( p_owner->dec.fmt_in->i_cat == VIDEO_ES )
     {
         if( p_owner->p_vout )
-            vout_NextPicture( p_owner->p_vout, pi_duration );
+            vout_NextPicture( p_owner->p_vout );
     }
     vlc_fifo_Unlock(p_owner->p_fifo);
 }


=====================================
src/input/decoder.h
=====================================
@@ -119,10 +119,9 @@ int vlc_input_decoder_GetCcState( vlc_input_decoder_t *, vlc_fourcc_t, int i_cha
 void vlc_input_decoder_GetCcDesc( vlc_input_decoder_t *, decoder_cc_desc_t * );
 
 /**
- * This function force the display of the next picture and fills the stream
- * time consumed.
+ * This function forces the display of the next picture
  */
-void vlc_input_decoder_FrameNext( vlc_input_decoder_t *p_dec, vlc_tick_t *pi_duration );
+void vlc_input_decoder_FrameNext( vlc_input_decoder_t *p_dec );
 
 struct vlc_input_decoder_status
 {


=====================================
src/input/es_out.c
=====================================
@@ -213,6 +213,7 @@ typedef struct
 
     /* */
     bool        b_paused;
+    es_out_id_t *p_next_frame_es;
     vlc_tick_t  i_pause_date;
 
     /* Current preroll */
@@ -251,6 +252,7 @@ static void EsOutDeleteInfoEs( es_out_t *, es_out_id_t *es );
 static void EsOutUnselectEs( es_out_t *out, es_out_id_t *es, bool b_update );
 static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es );
 static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date );
+static void EsOutChangePosition( es_out_t *out, bool b_flush, es_out_id_t *p_next_frame_es );
 static void EsOutProgramChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date );
 static void EsOutProgramsChangeRate( es_out_t *out );
 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced );
@@ -547,6 +549,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input, input_source_t *main_source,
     p_sys->main_source = main_source;
 
     p_sys->b_active = false;
+    p_sys->p_next_frame_es = NULL;
     p_sys->i_mode   = ES_OUT_MODE_NONE;
     p_sys->input_type = input_type;
 
@@ -892,6 +895,16 @@ static int EsOutSetRecord(  es_out_t *out, bool b_record, const char *dir_path )
 
     return VLC_SUCCESS;
 }
+
+static void EsOutStopNextFrame( es_out_t *out )
+{
+    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
+    assert( p_sys->p_next_frame_es != NULL );
+    /* Flush every ES except the video one */
+    EsOutChangePosition( out, true, p_sys->p_next_frame_es );
+    p_sys->p_next_frame_es = NULL;
+}
+
 static void EsOutChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date )
 {
     es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
@@ -904,6 +917,9 @@ static void EsOutChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date )
     }
     else
     {
+        if( p_sys->p_next_frame_es != NULL )
+            EsOutStopNextFrame( out );
+
         if( p_sys->i_buffering_extra_initial > 0 )
         {
             vlc_tick_t i_stream_start;
@@ -946,7 +962,8 @@ static void EsOutChangeRate( es_out_t *out, float rate )
             vlc_input_decoder_ChangeRate( es->p_dec, rate );
 }
 
-static void EsOutChangePosition( es_out_t *out, bool b_flush )
+static void EsOutChangePosition( es_out_t *out, bool b_flush,
+                                 es_out_id_t *p_next_frame_es )
 {
     es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
     es_out_id_t *p_es;
@@ -957,7 +974,7 @@ static void EsOutChangePosition( es_out_t *out, bool b_flush )
     {
         if( p_es->p_dec != NULL )
         {
-            if( b_flush )
+            if( b_flush && p_es != p_next_frame_es )
                 vlc_input_decoder_Flush( p_es->p_dec );
             if( !p_sys->b_buffering )
             {
@@ -1177,69 +1194,29 @@ static void EsOutProgramsChangeRate( es_out_t *out )
 static void EsOutFrameNext( es_out_t *out )
 {
     es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
-    es_out_id_t *p_es_video = NULL, *p_es;
-
-    if( p_sys->b_buffering )
-    {
-        msg_Warn( p_sys->p_input, "buffering, ignoring 'frame next'" );
-        return;
-    }
 
     assert( p_sys->b_paused );
 
-    foreach_es_then_es_slaves(p_es)
-        if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec && !p_es_video /* nested loop */ )
-        {
-            p_es_video = p_es;
-            break;
-        }
-
-    if( !p_es_video )
+    if( p_sys->p_next_frame_es == NULL )
     {
-        msg_Warn( p_sys->p_input, "No video track selected, ignoring 'frame next'" );
-        return;
-    }
-
-    vlc_tick_t i_duration;
-    vlc_input_decoder_FrameNext( p_es_video->p_dec, &i_duration );
-
-    msg_Dbg( p_sys->p_input, "EsOutFrameNext consumed %d ms", (int)MS_FROM_VLC_TICK(i_duration) );
-
-    if( i_duration <= 0 )
-        i_duration = VLC_TICK_FROM_MS(40);
-
-    /* FIXME it is not a clean way ? */
-    if( p_sys->i_buffering_extra_initial <= 0 )
-    {
-        vlc_tick_t i_stream_start;
-        vlc_tick_t i_system_start;
-        vlc_tick_t i_stream_duration;
-        vlc_tick_t i_system_duration;
-        int i_ret;
+        /* Don't use 'foreach_es_then_es_slaves': next-frame is not implemented
+         * on ES slaves */
+        es_out_id_t *p_es;
+        vlc_list_foreach( p_es, &p_sys->es, node )
+            if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
+            {
+                p_sys->p_next_frame_es = p_es;
+                break;
+            }
 
-        i_ret = input_clock_GetState( p_sys->p_pgrm->p_input_clock,
-                                      &i_stream_start, &i_system_start,
-                                      &i_stream_duration, &i_system_duration );
-        if( i_ret )
+        if( p_sys->p_next_frame_es == NULL )
+        {
+            msg_Warn( p_sys->p_input, "No video track selected, ignoring 'frame next'" );
             return;
-
-        p_sys->i_buffering_extra_initial = 1 + i_stream_duration
-                                         - p_sys->i_pts_delay
-                                         - p_sys->i_pts_jitter
-                                         - p_sys->i_tracks_pts_delay; /* FIXME < 0 ? */
-        p_sys->i_buffering_extra_system =
-        p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial;
+        }
     }
 
-    const float rate = input_clock_GetRate( p_sys->p_pgrm->p_input_clock );
-
-    p_sys->b_buffering = true;
-    p_sys->i_buffering_extra_system += i_duration;
-    p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial +
-        ( p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial ) * rate;
-
-    p_sys->i_preroll_end = -1;
-    p_sys->i_prev_stream_level = -1;
+    vlc_input_decoder_FrameNext( p_sys->p_next_frame_es->p_dec );
 }
 static vlc_tick_t EsOutGetBuffering( es_out_t *out )
 {
@@ -2366,6 +2343,9 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
     {
         vlc_input_decoder_ChangeRate( dec, p_sys->rate );
 
+        if( unlikely( p_sys->b_paused ) ) /* Could happen during next-frame */
+            vlc_input_decoder_ChangePause( dec, true, p_sys->i_pause_date );
+
         if( p_sys->b_buffering )
             vlc_input_decoder_StartWait( dec );
 
@@ -2383,8 +2363,13 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
             };
             p_es->p_dec_record = vlc_input_decoder_New( VLC_OBJECT(p_input), &rec_cfg );
 
-            if( p_es->p_dec_record && p_sys->b_buffering )
-                vlc_input_decoder_StartWait( p_es->p_dec_record );
+            if( p_es->p_dec_record )
+            {
+                if( p_sys->b_buffering )
+                    vlc_input_decoder_StartWait( p_es->p_dec_record );
+                if( unlikely( p_sys->b_paused ) ) /* Could happen during next-frame */
+                    vlc_input_decoder_ChangePause( p_es->p_dec_record, true, p_sys->i_pause_date );
+            }
         }
 
         if( p_es->mouse_event_cb && p_es->fmt.i_cat == VIDEO_ES )
@@ -2565,6 +2550,9 @@ static void EsOutUnselectEs( es_out_t *out, es_out_id_t *es, bool b_update )
         return;
     }
 
+    if( p_sys->p_next_frame_es == es )
+        EsOutStopNextFrame( out );
+
     if( es->p_master )
     {
         if( es->p_master->p_dec )
@@ -2958,6 +2946,14 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
 
     vlc_mutex_lock( &p_sys->lock );
 
+    /* Drop all ESes except the video one in case of next-frame */
+    if( p_sys->p_next_frame_es != NULL && p_sys->p_next_frame_es != es )
+    {
+        block_Release( p_block );
+        vlc_mutex_unlock( &p_sys->lock );
+        return VLC_SUCCESS;
+    }
+
     /* Mark preroll blocks */
     if( p_sys->i_preroll_end >= 0 )
     {
@@ -3424,6 +3420,9 @@ static int EsOutVaControlLocked( es_out_t *out, input_source_t *source,
         }
         else if( p_pgrm == p_sys->p_pgrm )
         {
+            if( p_sys->p_next_frame_es != NULL )
+                return VLC_SUCCESS;
+
             /* Last pcr/clock update was late. We need to compensate by offsetting
                from the clock the rendering dates */
             if( i_late > 0 && ( !priv->p_sout ||
@@ -3485,7 +3484,7 @@ static int EsOutVaControlLocked( es_out_t *out, input_source_t *source,
 
     case ES_OUT_RESET_PCR:
         msg_Dbg( p_sys->p_input, "ES_OUT_RESET_PCR called" );
-        EsOutChangePosition( out, true );
+        EsOutChangePosition( out, true, NULL );
         return VLC_SUCCESS;
 
     case ES_OUT_SET_GROUP:
@@ -3840,7 +3839,19 @@ static int EsOutVaPrivControlLocked( es_out_t *out, int query, va_list args )
     case ES_OUT_PRIV_GET_BUFFERING:
     {
         bool *pb = va_arg( args, bool* );
-        *pb = p_sys->b_buffering;
+        if( p_sys->b_buffering )
+            *pb = true;
+        else if( p_sys->p_next_frame_es != NULL )
+        {
+            /* The input thread will continue to call demux() if this control
+             * returns true. In case of next-frame, ask the input thread to
+             * continue to demux() until the vout has a picture to display. */
+            assert( p_sys->b_paused );
+            *pb = p_sys->p_next_frame_es->p_dec != NULL
+                && vlc_input_decoder_IsEmpty( p_sys->p_next_frame_es->p_dec );
+        }
+        else
+            *pb = false;
         return VLC_SUCCESS;
     }
     case ES_OUT_PRIV_SET_ES_DELAY:


=====================================
src/video_output/control.c
=====================================
@@ -64,12 +64,26 @@ void vout_control_Hold(vout_control_t *ctrl)
     vlc_mutex_unlock(&ctrl->lock);
 }
 
-void vout_control_Release(vout_control_t *ctrl)
+static void vout_control_ReleaseUnlocked(vout_control_t *ctrl)
 {
-    vlc_mutex_lock(&ctrl->lock);
     assert(ctrl->is_held);
     ctrl->is_held = false;
     vlc_cond_signal(&ctrl->wait_available);
+}
+
+void vout_control_Release(vout_control_t *ctrl)
+{
+    vlc_mutex_lock(&ctrl->lock);
+    vout_control_ReleaseUnlocked(ctrl);
+    vlc_mutex_unlock(&ctrl->lock);
+}
+
+void vout_control_ReleaseAndWake(vout_control_t *ctrl)
+{
+    vlc_mutex_lock(&ctrl->lock);
+    vout_control_ReleaseUnlocked(ctrl);
+    ctrl->forced_awake = true;
+    vlc_cond_signal(&ctrl->wait_request);
     vlc_mutex_unlock(&ctrl->lock);
 }
 


=====================================
src/video_output/control.h
=====================================
@@ -45,6 +45,7 @@ void vout_control_Init(vout_control_t *);
 void vout_control_Wake(vout_control_t *);
 void vout_control_Hold(vout_control_t *);
 void vout_control_Release(vout_control_t *);
+void vout_control_ReleaseAndWake(vout_control_t *);
 
 /* control inside of the vout thread */
 void vout_control_Wait(vout_control_t *, vlc_tick_t deadline);


=====================================
src/video_output/video_output.c
=====================================
@@ -116,11 +116,6 @@ typedef struct vout_thread_sys_t
         picture_t   *current;
     } displayed;
 
-    struct {
-        vlc_tick_t  last;
-        vlc_tick_t  timestamp;
-    } step;
-
     struct {
         bool        is_on;
         vlc_tick_t  date;
@@ -169,6 +164,8 @@ typedef struct vout_thread_sys_t
         vout_chrono_t render;         /**< picture render time estimator */
     } chrono;
 
+    unsigned frame_next_count;
+
     vlc_atomic_rc_t rc;
 
 } vout_thread_sys_t;
@@ -1390,7 +1387,7 @@ static int DisplayNextFrame(vout_thread_sys_t *sys)
         sys->displayed.current = next;
     }
 
-    if (!sys->displayed.current)
+    if (!next)
         return VLC_EGENERIC;
 
     return RenderPicture(sys, true);
@@ -1400,6 +1397,13 @@ static bool UpdateCurrentPicture(vout_thread_sys_t *sys)
 {
     assert(sys->clock);
 
+    if (sys->frame_next_count > 0)
+    {
+        if (DisplayNextFrame(sys) == VLC_SUCCESS)
+            --sys->frame_next_count;
+        return false;
+    }
+
     if (sys->displayed.current == NULL)
     {
         sys->displayed.current = PreparePicture(sys, true, false);
@@ -1503,10 +1507,7 @@ void vout_ChangePause(vout_thread_t *vout, bool is_paused, vlc_tick_t date)
 
     if (sys->pause.is_on)
         FilterFlush(sys, false);
-    else {
-        sys->step.timestamp = VLC_TICK_INVALID;
-        sys->step.last      = VLC_TICK_INVALID;
-    }
+
     sys->pause.is_on = is_paused;
     sys->pause.date  = date;
     vout_control_Release(&sys->control);
@@ -1526,9 +1527,6 @@ static void vout_FlushUnlocked(vout_thread_sys_t *vout, bool below,
 {
     vout_thread_sys_t *sys = vout;
 
-    sys->step.timestamp = VLC_TICK_INVALID;
-    sys->step.last      = VLC_TICK_INVALID;
-
     FilterFlush(vout, false); /* FIXME too much */
 
     picture_t *last = sys->displayed.decoded;
@@ -1574,27 +1572,16 @@ void vout_Flush(vout_thread_t *vout, vlc_tick_t date)
         vlc_tracer_TraceEvent(tracer, "RENDER", sys->str_id, "flushed");
 }
 
-void vout_NextPicture(vout_thread_t *vout, vlc_tick_t *duration)
+void vout_NextPicture(vout_thread_t *vout)
 {
     vout_thread_sys_t *sys = VOUT_THREAD_TO_SYS(vout);
     assert(!sys->dummy);
-    *duration = 0;
 
     vout_control_Hold(&sys->control);
-    if (sys->step.last == VLC_TICK_INVALID)
-        sys->step.last = sys->displayed.timestamp;
 
-    if (DisplayNextFrame(sys) == VLC_SUCCESS) {
-        sys->step.timestamp = sys->displayed.timestamp;
+    sys->frame_next_count++;
 
-        if (sys->step.last != VLC_TICK_INVALID &&
-            sys->step.timestamp > sys->step.last) {
-            *duration = sys->step.timestamp - sys->step.last;
-            sys->step.last = sys->step.timestamp;
-            /* TODO advance subpicture by the duration ... */
-        }
-    }
-    vout_control_Release(&sys->control);
+    vout_control_ReleaseAndWake(&sys->control);
 }
 
 void vout_ChangeDelay(vout_thread_t *vout, vlc_tick_t delay)
@@ -1727,9 +1714,6 @@ static int vout_Start(vout_thread_sys_t *vout, vlc_video_context *vctx, const vo
     sys->displayed.timestamp     = VLC_TICK_INVALID;
     sys->displayed.is_interlaced = false;
 
-    sys->step.last               = VLC_TICK_INVALID;
-    sys->step.timestamp          = VLC_TICK_INVALID;
-
     sys->pause.is_on = false;
     sys->pause.date  = VLC_TICK_INVALID;
 
@@ -2056,6 +2040,7 @@ vout_thread_t *vout_Create(vlc_object_t *object)
     if (sys->splitter_name != NULL)
         var_Destroy(vout, "window");
     sys->window_enabled = false;
+    sys->frame_next_count = 0;
     vlc_mutex_init(&sys->window_lock);
 
     if (var_InheritBool(vout, "video-wallpaper"))


=====================================
src/video_output/vout_internal.h
=====================================
@@ -226,7 +226,7 @@ void vout_GetResetStatistic( vout_thread_t *p_vout, unsigned *pi_displayed,
 /**
  * This function will force to display the next picture while paused
  */
-void vout_NextPicture( vout_thread_t *p_vout, vlc_tick_t *pi_duration );
+void vout_NextPicture( vout_thread_t *p_vout );
 
 /**
  * This function will ask the display of the input title



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/fe1c31bcd2e4988fd7faabad4c0d07f5ce39f621...ff1316724f3520ae0220fd693b6b589d56240561

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