[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