[vlc-devel] [RFC PATCH 03/13] es_out: use new vlc_clock_t
Thomas Guillem
thomas at gllm.fr
Wed Jun 27 14:41:25 CEST 2018
---
src/input/decoder.c | 130 ++++---------------------------
src/input/decoder.h | 2 +-
src/input/es_out.c | 40 ++++++++--
src/input/resource.c | 10 ++-
src/input/resource.h | 3 +-
src/video_output/control.h | 2 +
src/video_output/video_output.c | 89 ++++++++++++++-------
src/video_output/vout_internal.h | 11 +++
8 files changed, 133 insertions(+), 154 deletions(-)
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 988103ea78..062464f8d4 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -46,7 +46,7 @@
#include "audio_output/aout_internal.h"
#include "stream_output/stream_output.h"
#include "input_internal.h"
-#include "../clock/input_clock.h"
+#include "../clock/clock.h"
#include "decoder.h"
#include "event.h"
#include "resource.h"
@@ -68,8 +68,7 @@ struct decoder_owner
decoder_t dec;
input_thread_t *p_input;
input_resource_t*p_resource;
- input_clock_t *p_clock;
- int i_last_rate;
+ vlc_clock_t *p_clock;
int i_spu_channel;
int64_t i_spu_order;
@@ -101,7 +100,6 @@ struct decoder_owner
vlc_cond_t wait_request;
vlc_cond_t wait_acknowledge;
vlc_cond_t wait_fifo; /* TODO: merge with wait_acknowledge */
- vlc_cond_t wait_timed;
/* -- These variables need locking on write(only) -- */
audio_output_t *p_aout;
@@ -292,7 +290,7 @@ static vout_thread_t *aout_request_vout( void *p_private,
struct decoder_owner *p_owner = dec_get_owner( p_dec );
input_thread_t *p_input = p_owner->p_input;
- p_vout = input_resource_RequestVout( p_owner->p_resource, p_vout, p_fmt, 1,
+ p_vout = input_resource_RequestVout( p_owner->p_resource, p_vout, NULL, p_fmt, 1,
b_recyle );
if( p_input != NULL )
input_SendEventVout( p_input );
@@ -520,7 +518,7 @@ static int vout_update_format( decoder_t *p_dec )
break;
}
p_vout = input_resource_RequestVout( p_owner->p_resource,
- p_vout, &fmt,
+ p_vout, p_owner->p_clock, &fmt,
dpb_size +
p_dec->i_extra_picture_buffers + 1,
true );
@@ -635,12 +633,7 @@ static vlc_tick_t DecoderGetDisplayDate( decoder_t *p_dec, vlc_tick_t i_ts )
if( !p_owner->p_clock || i_ts == VLC_TS_INVALID )
return i_ts;
- if( input_clock_ConvertTS( VLC_OBJECT(p_dec), p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) {
- msg_Err(p_dec, "Could not get display date for timestamp %"PRId64"", i_ts);
- return VLC_TS_INVALID;
- }
-
- return i_ts;
+ return vlc_clock_ConvertToSystem( p_owner->p_clock, i_ts );
}
static float DecoderGetDisplayRate( decoder_t *p_dec )
@@ -649,7 +642,7 @@ static float DecoderGetDisplayRate( decoder_t *p_dec )
if( !p_owner->p_clock )
return 1.f;
- return input_clock_GetRate( p_owner->p_clock ) / (float) INPUT_RATE_DEFAULT;
+ return vlc_clock_GetRate( p_owner->p_clock );
}
/*****************************************************************************
@@ -703,24 +696,6 @@ static void DecoderWaitUnblock( decoder_t *p_dec )
}
}
-/* DecoderTimedWait: Interruptible wait
- * Returns VLC_SUCCESS if wait was not interrupted, and VLC_EGENERIC otherwise */
-static int DecoderTimedWait( decoder_t *p_dec, vlc_tick_t deadline )
-{
- struct decoder_owner *p_owner = dec_get_owner( p_dec );
-
- if (deadline - vlc_tick_now() <= 0)
- return VLC_SUCCESS;
-
- vlc_fifo_Lock( p_owner->p_fifo );
- while( !p_owner->flushing
- && vlc_fifo_TimedWaitCond( p_owner->p_fifo, &p_owner->wait_timed,
- deadline ) == 0 );
- int ret = p_owner->flushing ? VLC_EGENERIC : VLC_SUCCESS;
- vlc_fifo_Unlock( p_owner->p_fifo );
- return ret;
-}
-
static inline void DecoderUpdatePreroll( vlc_tick_t *pi_preroll, const block_t *p )
{
if( p->i_flags & BLOCK_FLAG_PREROLL )
@@ -735,56 +710,6 @@ static inline void DecoderUpdatePreroll( vlc_tick_t *pi_preroll, const block_t *
*pi_preroll = __MIN( *pi_preroll, p->i_pts );
}
-static void DecoderFixTs( decoder_t *p_dec, vlc_tick_t *pi_ts0, vlc_tick_t *pi_ts1,
- vlc_tick_t *pi_duration, int *pi_rate, vlc_tick_t i_ts_bound )
-{
- struct decoder_owner *p_owner = dec_get_owner( p_dec );
- input_clock_t *p_clock = p_owner->p_clock;
-
- vlc_assert_locked( &p_owner->lock );
-
- const vlc_tick_t i_es_delay = p_owner->i_ts_delay;
-
- if( !p_clock )
- return;
-
- const bool b_ephemere = pi_ts1 && *pi_ts0 == *pi_ts1;
- int i_rate;
-
- if( *pi_ts0 != VLC_TS_INVALID )
- {
- *pi_ts0 += i_es_delay;
- if( pi_ts1 && *pi_ts1 != VLC_TS_INVALID )
- *pi_ts1 += i_es_delay;
- if( i_ts_bound != INT64_MAX )
- i_ts_bound += i_es_delay;
- if( input_clock_ConvertTS( VLC_OBJECT(p_dec), p_clock, &i_rate, pi_ts0, pi_ts1, i_ts_bound ) ) {
- const char *psz_name = module_get_name( p_dec->p_module, false );
- if( pi_ts1 != NULL )
- msg_Err(p_dec, "Could not convert timestamps %"PRId64
- ", %"PRId64" for %s", *pi_ts0, *pi_ts1, psz_name );
- else
- msg_Err(p_dec, "Could not convert timestamp %"PRId64" for %s", *pi_ts0, psz_name );
- *pi_ts0 = VLC_TS_INVALID;
- }
- }
- else
- {
- i_rate = input_clock_GetRate( p_clock );
- }
-
- /* Do not create ephemere data because of rounding errors */
- if( !b_ephemere && pi_ts1 && *pi_ts1 != VLC_TS_INVALID && *pi_ts0 == *pi_ts1 )
- *pi_ts1 += 1;
-
- if( pi_duration )
- *pi_duration = ( *pi_duration * i_rate + INPUT_RATE_DEFAULT-1 )
- / INPUT_RATE_DEFAULT;
-
- if( pi_rate )
- *pi_rate = i_rate;
-}
-
#ifdef ENABLE_SOUT
static int DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block )
{
@@ -802,8 +727,6 @@ static int DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block )
}
DecoderWaitUnblock( p_dec );
- DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts,
- &p_sout_block->i_length, NULL, INT64_MAX );
vlc_mutex_unlock( &p_owner->lock );
@@ -1007,9 +930,6 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
}
const bool b_dated = p_picture->date != VLC_TS_INVALID;
- int i_rate = INPUT_RATE_DEFAULT;
- DecoderFixTs( p_dec, &p_picture->date, NULL, NULL,
- &i_rate, DECODER_BOGUS_VIDEO_DELAY );
vlc_mutex_unlock( &p_owner->lock );
@@ -1026,15 +946,7 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
if( p_picture->b_force || p_picture->date != VLC_TS_INVALID )
/* FIXME: VLC_TS_INVALID -- verify video_output */
- {
- if( i_rate != p_owner->i_last_rate || b_first_after_wait )
- {
- /* Be sure to not display old picture after our own */
- vout_Flush( p_vout, p_picture->date );
- p_owner->i_last_rate = i_rate;
- }
vout_PutPicture( p_vout, p_picture );
- }
else
{
if( b_dated )
@@ -1138,19 +1050,12 @@ static void DecoderPlayAudio( decoder_t *p_dec, block_t *p_audio,
}
/* */
- int i_rate = INPUT_RATE_DEFAULT;
-
DecoderWaitUnblock( p_dec );
- DecoderFixTs( p_dec, &p_audio->i_pts, NULL, &p_audio->i_length,
- &i_rate, AOUT_MAX_ADVANCE_TIME );
vlc_mutex_unlock( &p_owner->lock );
audio_output_t *p_aout = p_owner->p_aout;
- if( p_aout != NULL && p_audio->i_pts != VLC_TS_INVALID
- && i_rate >= INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE
- && i_rate <= INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE
- && !DecoderTimedWait( p_dec, p_audio->i_pts - AOUT_MAX_PREPARE_TIME ) )
+ if( p_aout != NULL && p_audio->i_pts != VLC_TS_INVALID )
{
int status = aout_DecPlay( p_aout, p_audio );
if( status == AOUT_DEC_CHANGED )
@@ -1239,12 +1144,9 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic )
}
DecoderWaitUnblock( p_dec );
- DecoderFixTs( p_dec, &p_subpic->i_start, &p_subpic->i_stop, NULL,
- NULL, INT64_MAX );
vlc_mutex_unlock( &p_owner->lock );
- if( p_subpic->i_start == VLC_TS_INVALID
- || DecoderTimedWait( p_dec, p_subpic->i_start - SPU_MAX_PREPARE_TIME ) )
+ if( p_subpic->i_start == VLC_TS_INVALID )
{
subpicture_Delete( p_subpic );
return;
@@ -1516,6 +1418,8 @@ static void OutputChangeRate( decoder_t *p_dec, float rate )
switch( p_dec->fmt_out.i_cat )
{
case VIDEO_ES:
+ if( p_owner->p_vout != NULL )
+ vout_ChangeRate( p_owner->p_vout, rate );
break;
case AUDIO_ES:
if( p_owner->p_aout != NULL )
@@ -1702,7 +1606,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
p_dec = &p_owner->dec;
p_owner->i_preroll_end = (vlc_tick_t)INT64_MIN;
- p_owner->i_last_rate = INPUT_RATE_DEFAULT;
p_owner->p_input = p_input;
p_owner->p_resource = p_resource;
p_owner->p_aout = NULL;
@@ -1747,7 +1650,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
vlc_cond_init( &p_owner->wait_request );
vlc_cond_init( &p_owner->wait_acknowledge );
vlc_cond_init( &p_owner->wait_fifo );
- vlc_cond_init( &p_owner->wait_timed );
/* Load a packetizer module if the input is not already packetized */
if( p_sout == NULL && !fmt->b_packetized )
@@ -1870,8 +1772,8 @@ static void DeleteDecoder( decoder_t * p_dec )
* thread */
vout_Cancel( p_owner->p_vout, false );
- input_resource_RequestVout( p_owner->p_resource, p_owner->p_vout, NULL,
- 0, true );
+ input_resource_RequestVout( p_owner->p_resource, p_owner->p_vout,
+ NULL, NULL, 0, true );
if( p_owner->p_input != NULL )
input_SendEventVout( p_owner->p_input );
}
@@ -1905,7 +1807,6 @@ static void DeleteDecoder( decoder_t * p_dec )
vlc_object_release( p_owner->p_packetizer );
}
- vlc_cond_destroy( &p_owner->wait_timed );
vlc_cond_destroy( &p_owner->wait_fifo );
vlc_cond_destroy( &p_owner->wait_acknowledge );
vlc_cond_destroy( &p_owner->wait_request );
@@ -1934,7 +1835,7 @@ static void DecoderUnsupportedCodec( decoder_t *p_dec, const es_format_t *fmt, b
/* TODO: pass p_sout through p_resource? -- Courmisch */
static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
- const es_format_t *fmt, input_clock_t *p_clock,
+ const es_format_t *fmt, vlc_clock_t *p_clock,
input_resource_t *p_resource,
sout_instance_t *p_sout )
{
@@ -2004,7 +1905,7 @@ static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
* \return the spawned decoder object
*/
decoder_t *input_DecoderNew( input_thread_t *p_input,
- es_format_t *fmt, input_clock_t *p_clock,
+ es_format_t *fmt, vlc_clock_t *p_clock,
sout_instance_t *p_sout )
{
return decoder_New( VLC_OBJECT(p_input), p_input, fmt, p_clock,
@@ -2035,9 +1936,7 @@ void input_DecoderDelete( decoder_t *p_dec )
vlc_cancel( p_owner->thread );
vlc_fifo_Lock( p_owner->p_fifo );
- /* Signal DecoderTimedWait */
p_owner->flushing = true;
- vlc_cond_signal( &p_owner->wait_timed );
vlc_fifo_Unlock( p_owner->p_fifo );
/* Make sure we aren't waiting/decoding anymore */
@@ -2185,7 +2084,6 @@ void input_DecoderFlush( decoder_t *p_dec )
p_owner->frames_countdown++;
vlc_fifo_Signal( p_owner->p_fifo );
- vlc_cond_signal( &p_owner->wait_timed );
vlc_fifo_Unlock( p_owner->p_fifo );
}
diff --git a/src/input/decoder.h b/src/input/decoder.h
index 2cfda8cc54..6bf10b8276 100644
--- a/src/input/decoder.h
+++ b/src/input/decoder.h
@@ -28,7 +28,7 @@
#include <vlc_common.h>
#include <vlc_codec.h>
-decoder_t *input_DecoderNew( input_thread_t *, es_format_t *, input_clock_t *,
+decoder_t *input_DecoderNew( input_thread_t *, es_format_t *, vlc_clock_t *,
sout_instance_t * ) VLC_USED;
/**
diff --git a/src/input/es_out.c b/src/input/es_out.c
index d36fd2c4ff..91c4911607 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -43,6 +43,7 @@
#include "input_internal.h"
#include "../clock/input_clock.h"
+#include "../clock/clock.h"
#include "decoder.h"
#include "es_out.h"
#include "event.h"
@@ -70,7 +71,9 @@ typedef struct
bool b_scrambled;
/* Clock for this program */
- input_clock_t *p_input_clock;
+ input_clock_t *p_input_clock;
+ vlc_clock_main_t *p_main_clock;
+ vlc_clock_t *p_master_clock;
vlc_meta_t *p_meta;
struct vlc_list node;
@@ -93,6 +96,7 @@ struct es_out_id_t
decoder_t *p_dec;
decoder_t *p_dec_record;
+ vlc_clock_t *p_clock;
/* Fields for Video with CC */
struct
@@ -368,6 +372,7 @@ static void EsOutTerminate( es_out_t *out )
vlc_list_foreach(p_pgrm, &p_sys->programs, node)
{
input_clock_Delete( p_pgrm->p_input_clock );
+ vlc_clock_main_Delete( p_pgrm->p_main_clock );
if( p_pgrm->p_meta )
vlc_meta_Delete( p_pgrm->p_meta );
@@ -513,7 +518,7 @@ static int EsOutSetRecord( es_out_t *out, bool b_record )
if( !p_es->p_dec || p_es->p_master )
continue;
- p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_input_clock, p_sys->p_sout_record );
+ p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, NULL, p_sys->p_sout_record );
if( p_es->p_dec_record && p_sys->b_buffering )
input_DecoderStartWait( p_es->p_dec_record );
}
@@ -612,7 +617,10 @@ static void EsOutChangePosition( es_out_t *out )
es_out_pgrm_t *pgrm;
vlc_list_foreach(pgrm, &p_sys->programs, node)
+ {
input_clock_Reset(pgrm->p_input_clock);
+ vlc_clock_main_Reset(pgrm->p_main_clock);
+ }
p_sys->b_buffering = true;
p_sys->i_buffering_extra_initial = 0;
@@ -1081,9 +1089,14 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
p_pgrm->b_selected = false;
p_pgrm->b_scrambled = false;
p_pgrm->p_meta = NULL;
+
+ p_pgrm->p_master_clock = NULL;
p_pgrm->p_input_clock = input_clock_New( p_sys->i_rate );
- if( !p_pgrm->p_input_clock )
+ p_pgrm->p_main_clock = vlc_clock_main_New();
+ if( !p_pgrm->p_input_clock || !p_pgrm->p_main_clock )
{
+ if( p_pgrm->p_input_clock )
+ input_clock_Delete( p_pgrm->p_input_clock );
free( p_pgrm );
return NULL;
}
@@ -1137,6 +1150,7 @@ static int EsOutProgramDel( es_out_t *out, int i_group )
p_sys->p_pgrm = NULL;
input_clock_Delete( p_pgrm->p_input_clock );
+ vlc_clock_main_Delete( p_pgrm->p_main_clock );
if( p_pgrm->p_meta )
vlc_meta_Delete( p_pgrm->p_meta );
@@ -1618,6 +1632,7 @@ static es_out_id_t *EsOutAddSlave( es_out_t *out, const es_format_t *fmt, es_out
es->psz_language_code = LanguageGetCode( es->fmt.psz_language );
es->p_dec = NULL;
es->p_dec_record = NULL;
+ es->p_clock = NULL;
es->cc.type = 0;
es->cc.i_bitmap = 0;
es->p_master = p_master;
@@ -1670,7 +1685,15 @@ static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es )
input_thread_t *p_input = p_sys->p_input;
decoder_t *dec;
- dec = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_input_clock,
+ if( p_es->fmt.i_cat == AUDIO_ES && p_es->p_pgrm->p_master_clock == NULL )
+ p_es->p_pgrm->p_master_clock = p_es->p_clock =
+ vlc_clock_NewMaster( p_es->p_pgrm->p_main_clock );
+ else
+ p_es->p_clock = vlc_clock_NewSlave( p_es->p_pgrm->p_main_clock );
+ if( !p_es->p_clock )
+ return;
+
+ dec = input_DecoderNew( p_input, &p_es->fmt, p_es->p_clock,
input_priv(p_input)->p_sout );
if( dec != NULL )
{
@@ -1683,7 +1706,7 @@ static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es )
if( !p_es->p_master && p_sys->p_sout_record )
{
- p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_input_clock, p_sys->p_sout_record );
+ p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, NULL, p_sys->p_sout_record );
if( p_es->p_dec_record && p_sys->b_buffering )
input_DecoderStartWait( p_es->p_dec_record );
}
@@ -1701,6 +1724,10 @@ static void EsDestroyDecoder( es_out_t *out, es_out_id_t *p_es )
input_DecoderDelete( p_es->p_dec );
p_es->p_dec = NULL;
+ if( p_es->p_pgrm->p_master_clock == p_es->p_clock )
+ p_es->p_pgrm->p_master_clock = NULL;
+ vlc_clock_Delete( p_es->p_clock );
+ p_es->p_clock = NULL;
if( p_es->p_dec_record )
{
@@ -2514,7 +2541,10 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
/* reset clock */
vlc_list_foreach(pgrm, &p_sys->programs, node)
+ {
input_clock_Reset(pgrm->p_input_clock);
+ vlc_clock_main_Reset(p_pgrm->p_main_clock);
+ }
}
else
{
diff --git a/src/input/resource.c b/src/input/resource.c
index f806cfeb2c..d6e07baaeb 100644
--- a/src/input/resource.c
+++ b/src/input/resource.c
@@ -194,7 +194,7 @@ static void DisplayVoutTitle( input_resource_t *p_resource,
free( psz_nowplaying );
}
static vout_thread_t *RequestVout( input_resource_t *p_resource,
- vout_thread_t *p_vout,
+ vout_thread_t *p_vout, vlc_clock_t *p_clock,
const video_format_t *p_fmt, unsigned dpb_size,
bool b_recycle )
{
@@ -233,6 +233,7 @@ static vout_thread_t *RequestVout( input_resource_t *p_resource,
/* */
vout_configuration_t cfg = {
.vout = p_vout,
+ .clock = p_clock,
.input = VLC_OBJECT(p_resource->p_input),
.change_fmt = true,
.fmt = p_fmt,
@@ -278,6 +279,7 @@ static vout_thread_t *RequestVout( input_resource_t *p_resource,
vout_configuration_t cfg = {
.vout = p_vout,
+ .clock = NULL,
.input = NULL,
.change_fmt = false,
.fmt = NULL,
@@ -464,12 +466,12 @@ void input_resource_SetInput( input_resource_t *p_resource, input_thread_t *p_in
}
vout_thread_t *input_resource_RequestVout( input_resource_t *p_resource,
- vout_thread_t *p_vout,
+ vout_thread_t *p_vout, vlc_clock_t *p_clock,
const video_format_t *p_fmt, unsigned dpb_size,
bool b_recycle )
{
vlc_mutex_lock( &p_resource->lock );
- vout_thread_t *p_ret = RequestVout( p_resource, p_vout, p_fmt, dpb_size, b_recycle );
+ vout_thread_t *p_ret = RequestVout( p_resource, p_vout, p_clock, p_fmt, dpb_size, b_recycle );
vlc_mutex_unlock( &p_resource->lock );
return p_ret;
@@ -487,7 +489,7 @@ void input_resource_HoldVouts( input_resource_t *p_resource, vout_thread_t ***pp
void input_resource_TerminateVout( input_resource_t *p_resource )
{
- input_resource_RequestVout( p_resource, NULL, NULL, 0, false );
+ input_resource_RequestVout( p_resource, NULL, NULL, NULL, 0, false );
}
bool input_resource_HasVout( input_resource_t *p_resource )
{
diff --git a/src/input/resource.h b/src/input/resource.h
index 8f83eb3183..10ca61f320 100644
--- a/src/input/resource.h
+++ b/src/input/resource.h
@@ -25,6 +25,7 @@
#define LIBVLC_INPUT_RESOURCE_H 1
#include <vlc_common.h>
+#include "../clock/clock.h"
/**
* This function set the associated input.
@@ -39,7 +40,7 @@ sout_instance_t *input_resource_RequestSout( input_resource_t *, sout_instance_t
/**
* This function handles vout request.
*/
-vout_thread_t *input_resource_RequestVout( input_resource_t *, vout_thread_t *,
+vout_thread_t *input_resource_RequestVout( input_resource_t *, vout_thread_t *, vlc_clock_t *clock,
const video_format_t *, unsigned dpb_size, bool b_recycle );
/**
diff --git a/src/video_output/control.h b/src/video_output/control.h
index 181e02082d..ad04dff963 100644
--- a/src/video_output/control.h
+++ b/src/video_output/control.h
@@ -48,6 +48,7 @@ enum {
VOUT_CONTROL_CHANGE_SUB_MARGIN, /* integer */
VOUT_CONTROL_PAUSE,
+ VOUT_CONTROL_CHANGE_RATE, /* float */
VOUT_CONTROL_FLUSH, /* time */
VOUT_CONTROL_STEP, /* time_ptr */
@@ -83,6 +84,7 @@ typedef struct {
bool is_on;
vlc_tick_t date;
} pause;
+ float rate;
struct {
int channel;
char *string;
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index d9855a868d..545aaff94c 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -54,6 +54,7 @@
#include "display.h"
#include "window.h"
#include "../misc/variables.h"
+#include "../clock/clock.h"
/*****************************************************************************
* Local prototypes
@@ -132,6 +133,8 @@ static vout_thread_t *VoutCreate(vlc_object_t *object,
/* */
vout->p = (vout_thread_sys_t*)&vout[1];
+ vout->p->rate = 1;
+ vout->p->clock = cfg->clock;
vout->p->original = original;
vout->p->dpb_size = cfg->dpb_size;
@@ -242,15 +245,14 @@ vout_thread_t *vout_Request(vlc_object_t *object,
spu_Attach(vout->p->spu, vout->p->input, true);
}
- if (cfg->change_fmt) {
- vout_control_cmd_t cmd;
- vout_control_cmd_Init(&cmd, VOUT_CONTROL_REINIT);
- cmd.cfg = cfg;
+ vout_control_cmd_t cmd;
+ vout_control_cmd_Init(&cmd, VOUT_CONTROL_REINIT);
+ cmd.cfg = cfg;
- vout_control_Push(&vout->p->control, &cmd);
- vout_control_WaitEmpty(&vout->p->control);
+ vout_control_Push(&vout->p->control, &cmd);
+ vout_control_WaitEmpty(&vout->p->control);
+ if (cfg->change_fmt)
vout_IntfReinit(vout);
- }
if (!vout->p->dead) {
msg_Dbg(object, "reusing provided vout");
@@ -326,6 +328,16 @@ void vout_ChangePause(vout_thread_t *vout, bool is_paused, vlc_tick_t date)
vout_control_WaitEmpty(&vout->p->control);
}
+void vout_ChangeRate(vout_thread_t *vout, float rate)
+{
+ vout_control_cmd_t cmd;
+ vout_control_cmd_Init(&cmd, VOUT_CONTROL_CHANGE_RATE);
+ cmd.rate = rate;
+ vout_control_Push(&vout->p->control, &cmd);
+
+ vout_control_WaitEmpty(&vout->p->control);
+}
+
void vout_GetResetStatistic(vout_thread_t *vout, unsigned *restrict displayed,
unsigned *restrict lost)
{
@@ -845,15 +857,18 @@ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool fra
decoded = picture_Hold(vout->p->displayed.decoded);
} else {
decoded = picture_fifo_Pop(vout->p->decoder_fifo);
+
if (decoded) {
if (is_late_dropped && !decoded->b_force) {
+ const vlc_tick_t date = vlc_tick_now();
+ const vlc_tick_t system_pts =
+ vlc_clock_ConvertToSystem(vout->p->clock, decoded->date);
+ const vlc_tick_t late = date - system_pts;
vlc_tick_t late_threshold;
if (decoded->format.i_frame_rate && decoded->format.i_frame_rate_base)
late_threshold = ((CLOCK_FREQ/2) * decoded->format.i_frame_rate_base) / decoded->format.i_frame_rate;
else
late_threshold = VOUT_DISPLAY_LATE_THRESHOLD;
- const vlc_tick_t predicted = vlc_tick_now() + 0; /* TODO improve */
- const vlc_tick_t late = predicted - decoded->date;
if (late > late_threshold) {
msg_Warn(vout, "picture is too late to be displayed (missing %"PRId64" ms)", late/1000);
picture_Release(decoded);
@@ -1126,13 +1141,15 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
return VLC_EGENERIC;
}
+ vlc_tick_t system_pts = vlc_clock_ConvertToSystem(vout->p->clock, todisplay->date);
+
if (sys->display.use_dr) {
- vout_display_Prepare(vd, todisplay, subpic, todisplay->date);
+ vout_display_Prepare(vd, todisplay, subpic, system_pts);
} else {
if (!do_dr_spu && !do_early_spu && vout->p->spu_blend && subpic)
picture_BlendSubpicture(todisplay, vout->p->spu_blend, subpic);
vout_display_Prepare(vd, todisplay, do_dr_spu ? subpic : NULL,
- todisplay->date);
+ system_pts);
if (!do_dr_spu && subpic)
{
@@ -1158,12 +1175,16 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
msg_Warn(vout, "picture is late (%lld ms)", delay / 1000);
#endif
if (!is_forced)
- vlc_tick_wait(todisplay->date);
+ vlc_clock_Wait(vout->p->clock, todisplay->date, VOUT_REDISPLAY_DELAY);
/* Display the direct buffer returned by vout_RenderPicture */
- vout->p->displayed.date = vlc_tick_now();
vout_display_Display(vd, todisplay, subpic);
+ const vlc_tick_t now = vlc_tick_now();
+ const vlc_tick_t drift = vlc_clock_Update(vout->p->clock, todisplay->date, now,
+ vout->p->rate);
+ vout->p->displayed.date = now + (drift != VLC_TS_INVALID ? drift : 0);
+
vout_statistic_AddDisplayed(&vout->p->statistic, 1);
return VLC_SUCCESS;
@@ -1171,6 +1192,9 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
static int ThreadDisplayPicture(vout_thread_t *vout, vlc_tick_t *deadline)
{
+ if (unlikely(!vout->p->clock))
+ return VLC_EGENERIC;
+
bool frame_by_frame = !deadline;
bool paused = vout->p->pause.is_on;
bool first = !vout->p->displayed.current;
@@ -1188,9 +1212,13 @@ static int ThreadDisplayPicture(vout_thread_t *vout, vlc_tick_t *deadline)
bool drop_next_frame = frame_by_frame;
vlc_tick_t date_next = VLC_TS_INVALID;
+
if (!paused && vout->p->displayed.next) {
- date_next = vout->p->displayed.next->date - render_delay;
- if (date_next /* + 0 FIXME */ <= date)
+ const vlc_tick_t next_system_pts =
+ vlc_clock_ConvertToSystem(vout->p->clock, vout->p->displayed.next->date);
+
+ date_next = next_system_pts - render_delay;
+ if (date_next <= date)
drop_next_frame = true;
}
@@ -1208,7 +1236,7 @@ static int ThreadDisplayPicture(vout_thread_t *vout, vlc_tick_t *deadline)
vlc_tick_t date_refresh = VLC_TS_INVALID;
if (vout->p->displayed.date != VLC_TS_INVALID) {
date_refresh = vout->p->displayed.date + VOUT_REDISPLAY_DELAY - render_delay;
- refresh = date_refresh <= date;
+ refresh = date_refresh <= vlc_tick_now();
}
bool force_refresh = !drop_next_frame && refresh;
@@ -1278,17 +1306,6 @@ static void ThreadChangePause(vout_thread_t *vout, bool is_paused, vlc_tick_t da
assert(!vout->p->pause.is_on || !is_paused);
if (vout->p->pause.is_on) {
- const vlc_tick_t duration = date - vout->p->pause.date;
-
- if (vout->p->step.timestamp != VLC_TS_INVALID)
- vout->p->step.timestamp += duration;
- if (vout->p->step.last != VLC_TS_INVALID)
- vout->p->step.last += duration;
- picture_fifo_OffsetDate(vout->p->decoder_fifo, duration);
- if (vout->p->displayed.decoded)
- vout->p->displayed.decoded->date += duration;
- spu_OffsetSubtitleDate(vout->p->spu, duration);
-
ThreadFilterFlush(vout, false);
} else {
vout->p->step.timestamp = VLC_TS_INVALID;
@@ -1300,6 +1317,14 @@ static void ThreadChangePause(vout_thread_t *vout, bool is_paused, vlc_tick_t da
vout_window_t *window = vout->p->window;
if (window != NULL)
vout_window_SetInhibition(window, !is_paused);
+
+ if (vout->p->clock)
+ vlc_clock_ChangePause(vout->p->clock, is_paused, date);
+}
+
+static void ThreadChangeRate(vout_thread_t *vout, float rate)
+{
+ vout->p->rate = rate;
}
static void ThreadFlush(vout_thread_t *vout, bool below, vlc_tick_t date)
@@ -1323,6 +1348,8 @@ static void ThreadFlush(vout_thread_t *vout, bool below, vlc_tick_t date)
picture_fifo_Flush(vout->p->decoder_fifo, date, below);
vout_FilterFlush(vout->p->display.vd);
+ if (vout->p->clock)
+ vlc_clock_Reset(vout->p->clock);
}
static void ThreadStep(vout_thread_t *vout, vlc_tick_t *duration)
@@ -1591,6 +1618,11 @@ static void ThreadClean(vout_thread_t *vout)
static int ThreadReinit(vout_thread_t *vout,
const vout_configuration_t *cfg)
{
+ vout->p->clock = cfg->clock;
+
+ if (!cfg->change_fmt)
+ return VLC_SUCCESS;
+
video_format_t original;
vout->p->pause.is_on = false;
@@ -1711,6 +1743,9 @@ static int ThreadControl(vout_thread_t *vout, vout_control_cmd_t cmd)
case VOUT_CONTROL_PAUSE:
ThreadChangePause(vout, cmd.pause.is_on, cmd.pause.date);
break;
+ case VOUT_CONTROL_CHANGE_RATE:
+ ThreadChangeRate(vout, cmd.rate);
+ break;
case VOUT_CONTROL_FLUSH:
ThreadFlush(vout, false, cmd.time);
break;
diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h
index feacb10a61..6cafe05667 100644
--- a/src/video_output/vout_internal.h
+++ b/src/video_output/vout_internal.h
@@ -32,6 +32,7 @@
#include "snapshot.h"
#include "statistic.h"
#include "chrono.h"
+#include "../clock/clock.h"
/* It should be high enough to absorbe jitter due to difficult picture(s)
* to decode but not too high as memory is not that cheap.
@@ -46,6 +47,7 @@
*/
typedef struct {
vout_thread_t *vout;
+ vlc_clock_t *clock;
vlc_object_t *input;
bool change_fmt;
const video_format_t *fmt;
@@ -59,6 +61,9 @@ struct vout_thread_sys_t
/* Splitter module if used */
char *splitter_name;
+ vlc_clock_t *clock;
+ float rate;
+
/* Input thread for dvd menu interactions */
vlc_object_t *input;
@@ -226,6 +231,12 @@ void spu_ChangeMargin(spu_t *, int);
*/
void vout_ChangePause( vout_thread_t *, bool b_paused, vlc_tick_t i_date );
+/**
+ * This function will change the rate of the vout
+ * It is thread safe
+ */
+void vout_ChangeRate( vout_thread_t *, float rate );
+
/**
* Updates the pointing device state.
*/
--
2.18.0
More information about the vlc-devel
mailing list