[vlc-commits] [Git][videolan/vlc][3.0.x] 5 commits: input: add a workaround for next-frame

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Thu Feb 16 13:18:00 UTC 2023



Jean-Baptiste Kempf pushed to branch 3.0.x at VideoLAN / VLC


Commits:
feaa1eea by Thomas Guillem at 2023-02-16T13:06:01+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

(cherry picked from commit ea93b2c847880581b55c433b3aa0f315c6449cf3)
Signed-off-by: Thomas Guillem <thomas at gllm.fr>

- - - - -
87b7b422 by Thomas Guillem at 2023-02-16T13:06:01+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).

(cherry picked from commit ff1316724f3520ae0220fd693b6b589d56240561)
Signed-off-by: Thomas Guillem <thomas at gllm.fr>

- - - - -
cf041857 by Thomas Guillem at 2023-02-16T13:06:01+00:00
es_out: report timing when using next-frame

- - - - -
e9cf9077 by Thomas Guillem at 2023-02-16T13:06:01+00:00
es_out: don't pace when using next-frame

This fixes hiccups after few seconds when hitting next-frame in repeat mode.

- - - - -
8f30d641 by Thomas Guillem at 2023-02-16T13:06:01+00:00
input: seek to the current time when resuming from next-frame

This fixes video glitches. It won't work for all input sources (but it's
not critical).

- - - - -


3 changed files:

- src/input/es_out.c
- src/input/input.c
- src/input/input_internal.h


Changes:

=====================================
src/input/es_out.c
=====================================
@@ -163,6 +163,7 @@ struct es_out_sys_t
 
     /* */
     bool        b_paused;
+    es_out_id_t *p_next_frame_es;
     vlc_tick_t  i_pause_date;
 
     /* Current preroll */
@@ -198,6 +199,7 @@ static void EsDeleteInfo( es_out_t *, es_out_id_t *es );
 static void EsUnselect( 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 );
 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 );
@@ -313,6 +315,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
     p_sys->p_input = p_input;
 
     p_sys->b_active = false;
+    p_sys->p_next_frame_es = NULL;
     p_sys->i_mode   = ES_OUT_MODE_NONE;
 
     TAB_INIT( p_sys->i_pgrm, p_sys->pgrm );
@@ -410,7 +413,8 @@ static vlc_tick_t EsOutGetWakeup( es_out_t *out )
      * to avoid too heavy buffering */
     if( !input_priv(p_input)->b_can_pace_control ||
         input_priv(p_input)->b_out_pace_control ||
-        p_sys->b_buffering )
+        p_sys->b_buffering ||
+        p_sys->p_next_frame_es != NULL )
         return 0;
 
     return input_clock_GetWakeup( p_sys->p_pgrm->p_clock );
@@ -552,6 +556,16 @@ static int EsOutSetRecord(  es_out_t *out, bool b_record )
 
     return VLC_SUCCESS;
 }
+
+static void EsOutStopNextFrame( es_out_t *out )
+{
+    es_out_sys_t *p_sys = out->p_sys;
+    assert( p_sys->p_next_frame_es != NULL );
+    /* Flush every ES except the video one */
+    EsOutChangePosition( out );
+    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 = out->p_sys;
@@ -564,6 +578,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;
@@ -808,71 +825,35 @@ static void EsOutProgramsChangeRate( es_out_t *out )
 static void EsOutFrameNext( es_out_t *out )
 {
     es_out_sys_t *p_sys = out->p_sys;
-    es_out_id_t *p_es_video = NULL;
-
-    if( p_sys->b_buffering )
-    {
-        msg_Warn( p_sys->p_input, "buffering, ignoring 'frame next'" );
-        return;
-    }
 
     assert( p_sys->b_paused );
 
-    for( int i = 0; i < p_sys->i_es; i++ )
+    if( p_sys->p_next_frame_es == NULL )
     {
-        es_out_id_t *p_es = p_sys->es[i];
-
-        if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
+        /* Don't use 'foreach_es_then_es_slaves': next-frame is not implemented
+         * on ES slaves */
+        for( int i = 0; i < p_sys->i_es; i++ )
         {
-            p_es_video = p_es;
-            break;
+            es_out_id_t *p_es = p_sys->es[i];
+
+            if( p_es->p_master == NULL && p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
+            {
+                p_sys->p_next_frame_es = p_es;
+                break;
+            }
         }
-    }
 
-    if( !p_es_video )
-    {
-        msg_Warn( p_sys->p_input, "No video track selected, ignoring 'frame next'" );
-        return;
+        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;
-    input_DecoderFrameNext( p_es_video->p_dec, &i_duration );
+    input_DecoderFrameNext( p_sys->p_next_frame_es->p_dec, &i_duration );
 
     msg_Dbg( out->p_sys->p_input, "EsOutFrameNext consummed %d ms", (int)(i_duration/1000) );
-
-    if( i_duration <= 0 )
-        i_duration = 40*1000;
-
-    /* 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;
-
-        i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock,
-                                      &i_stream_start, &i_system_start,
-                                      &i_stream_duration, &i_system_duration );
-        if( i_ret )
-            return;
-
-        p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->i_pts_delay; /* FIXME < 0 ? */
-        p_sys->i_buffering_extra_system =
-        p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial;
-    }
-
-    const int i_rate = input_clock_GetRate( p_sys->p_pgrm->p_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 ) *
-                                                INPUT_RATE_DEFAULT / i_rate;
-
-    p_sys->i_preroll_end = -1;
-    p_sys->i_prev_stream_level = -1;
 }
 static vlc_tick_t EsOutGetBuffering( es_out_t *out )
 {
@@ -1834,6 +1815,9 @@ static void EsUnselect( 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 )
@@ -2083,6 +2067,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 )
     {
@@ -2538,6 +2530,9 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
         }
         else if( p_pgrm == p_sys->p_pgrm )
         {
+            if( p_sys->p_next_frame_es != NULL )
+                return VLC_SUCCESS;
+
             if( b_late && ( !input_priv(p_sys->p_input)->p_sout ||
                             !input_priv(p_sys->p_input)->b_out_pace_control ) )
             {
@@ -2753,6 +2748,19 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
     {
         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
+                && input_DecoderIsEmpty( p_sys->p_next_frame_es->p_dec );
+        }
+        else
+            *pb = false;
         return VLC_SUCCESS;
     }
 
@@ -2822,13 +2830,17 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
 
         input_SendEventLength( p_sys->p_input, i_length );
 
-        if( !p_sys->b_buffering )
+        if( !p_sys->b_buffering || p_sys->p_next_frame_es != NULL )
         {
+            /* Also report times in next-frame mode without taking into
+             * account the buffering. */
+
             vlc_tick_t i_delay;
 
             /* Fix for buffering delay */
-            if( !input_priv(p_sys->p_input)->p_sout ||
-                !input_priv(p_sys->p_input)->b_out_pace_control )
+            if( p_sys->p_next_frame_es == NULL
+             && (!input_priv(p_sys->p_input)->p_sout ||
+                 !input_priv(p_sys->p_input)->b_out_pace_control ) )
                 i_delay = EsOutGetBuffering( out );
             else
                 i_delay = 0;


=====================================
src/input/input.c
=====================================
@@ -319,6 +319,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     priv->is_running = false;
     priv->is_stopped = false;
     priv->b_recording = false;
+    priv->b_next_frame = false;
     priv->i_rate = INPUT_RATE_DEFAULT;
     memset( &priv->bookmark, 0, sizeof(priv->bookmark) );
     TAB_INIT( priv->i_bookmark, priv->pp_bookmark );
@@ -1803,6 +1804,17 @@ static void ControlUnpause( input_thread_t *p_input, vlc_tick_t i_control_date )
     /* Switch to play */
     input_ChangeState( p_input, PLAYING_S );
     es_out_SetPauseState( input_priv(p_input)->p_es_out, false, false, i_control_date );
+
+    if( input_priv(p_input)->b_next_frame )
+    {
+        input_priv(p_input)->b_next_frame = false;
+        int64_t i_time;
+        if( demux_Control( input_priv(p_input)->master->p_demux, DEMUX_GET_TIME, &i_time ) == 0)
+        {
+            vlc_value_t val = { .i_int = i_time };
+            Control( p_input, INPUT_CONTROL_SET_TIME, val );
+        }
+    }
 }
 
 static void ViewpointApply( input_thread_t *p_input )
@@ -2365,6 +2377,7 @@ static bool Control( input_thread_t *p_input,
         case INPUT_CONTROL_SET_FRAME_NEXT:
             if( input_priv(p_input)->i_state == PAUSE_S )
             {
+                input_priv(p_input)->b_next_frame = true;
                 es_out_SetFrameNext( input_priv(p_input)->p_es_out );
             }
             else if( input_priv(p_input)->i_state == PLAYING_S )


=====================================
src/input/input_internal.h
=====================================
@@ -97,6 +97,7 @@ typedef struct input_thread_private_t
     bool        is_running;
     bool        is_stopped;
     bool        b_recording;
+    bool        b_next_frame;
     int         i_rate;
 
     /* Playtime configuration and state */



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/62ccae7d09fa58cd65c5c2d2cab8f58017157468...8f30d6411fa95b60bf821f5fd02c4d7dcae34286

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/62ccae7d09fa58cd65c5c2d2cab8f58017157468...8f30d6411fa95b60bf821f5fd02c4d7dcae34286
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