[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