[vlc-commits] qt: use the new player timer

Thomas Guillem git at videolan.org
Mon Sep 23 13:36:32 CEST 2019


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Wed Aug  7 15:10:29 2019 +0200| [6b638f31f82a0889950361d792ea1130109e4e00] | committer: Thomas Guillem

qt: use the new player timer

Qt setup a vlc_player_timer with a minimal period of 500ms. To propagate these
point to the UI, 2 QTimer are used.

 - A time QTimer: it will ask the player when the next second of the media will
   be reached in order to wait accordinly and update the time at the right
   time.

 - A position QTimer: it will update regularly the position, depending on the
   length and rate of the media. Maybe it should also do it according to the
   slider width too.

Before that, the input time was used, it could be delayed by 300ms to 2seconds
depending on your output buffer size (generally, led by audio module buffer
size). Furthermore, the input time was only updated every 250ms. This could
lead to a delay of (250 - 1) ms before updating the right second (and not
taking the output delay into account).

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=6b638f31f82a0889950361d792ea1130109e4e00
---

 modules/gui/qt/components/player_controller.cpp   | 219 +++++++++++++++++-----
 modules/gui/qt/components/player_controller.hpp   |   4 +
 modules/gui/qt/components/player_controller_p.hpp |  10 +
 3 files changed, 181 insertions(+), 52 deletions(-)

diff --git a/modules/gui/qt/components/player_controller.cpp b/modules/gui/qt/components/player_controller.cpp
index 987ab08c6e..b4432ccdaa 100644
--- a/modules/gui/qt/components/player_controller.cpp
+++ b/modules/gui/qt/components/player_controller.cpp
@@ -40,6 +40,8 @@
 
 #include <assert.h>
 
+#define POSITION_MIN_UPDATE_INTERVAL VLC_TICK_FROM_MS(15)
+
 //PlayerController private implementation
 
 using InputItemPtr = vlc_shared_data_ptr_type(input_item_t,
@@ -60,6 +62,7 @@ PlayerControllerPrivate::~PlayerControllerPrivate()
     vlc_player_vout_RemoveListener( m_player, m_player_vout_listener );
     vlc_player_aout_RemoveListener( m_player, m_player_aout_listener );
     vlc_player_RemoveListener( m_player, m_player_listener );
+    vlc_player_RemoveTimer( m_player, m_player_timer );
 }
 
 void PlayerControllerPrivate::UpdateName(input_item_t* media)
@@ -213,6 +216,18 @@ void PlayerControllerPrivate::UpdateSpuOrder(vlc_es_id_t *es_id, enum vlc_vout_o
     }
 }
 
+int PlayerControllerPrivate::interpolateTime(vlc_tick_t system_now)
+{
+    vlc_tick_t new_time;
+    if (vlc_player_timer_point_Interpolate(&m_player_time, system_now,
+                                           &new_time, &m_position) == VLC_SUCCESS)
+    {
+        m_time = new_time != VLC_TICK_INVALID ? new_time - VLC_TICK_0 : 0;
+        return VLC_SUCCESS;
+    }
+    return VLC_EGENERIC;
+}
+
 extern "C" {
 
 //player callbacks
@@ -345,16 +360,6 @@ static void on_player_buffering(vlc_player_t *, float new_buffering, void *data)
     });
 }
 
-static void on_player_rate_changed(vlc_player_t *, float new_rate, void *data)
-{
-    PlayerControllerPrivate* that = static_cast<PlayerControllerPrivate*>(data);
-    msg_Dbg( that->p_intf, "on_player_rate_changed %f", new_rate);
-    that->callAsync([that,new_rate](){
-        that->m_rate = new_rate;
-        emit that->q_func()->rateChanged( new_rate );
-    });
-}
-
 static void on_player_capabilities_changed(vlc_player_t *, int old_caps, int new_caps, void *data)
 {
     PlayerControllerPrivate* that = static_cast<PlayerControllerPrivate*>(data);
@@ -387,45 +392,6 @@ static void on_player_capabilities_changed(vlc_player_t *, int old_caps, int new
     //FIXME other events?
 }
 
-static void on_player_position_changed(vlc_player_t *player, vlc_tick_t time, float pos, void *data)
-{
-    PlayerControllerPrivate* that = static_cast<PlayerControllerPrivate*>(data);
-    vlc_tick_t length =  vlc_player_GetLength( player );
-    that->callAsync([that,time,pos,length] () {
-        PlayerController* q = that->q_func();
-        that->m_position = pos;
-        emit q->positionChanged(pos);
-        that->m_time = time;
-        emit q->timeChanged(time);
-        if ( time != VLC_TICK_INVALID && length != VLC_TICK_INVALID )
-            that->m_remainingTime = length - time;
-        else
-            that->m_remainingTime = VLC_TICK_INVALID;
-        emit q->remainingTimeChanged(that->m_remainingTime);
-        emit that->q_func()->positionUpdated(pos, time, SEC_FROM_VLC_TICK(length) );
-    });
-}
-
-static void on_player_length_changed(vlc_player_t *player, vlc_tick_t new_length, void *data)
-{
-    PlayerControllerPrivate* that = static_cast<PlayerControllerPrivate*>(data);
-    vlc_tick_t time = vlc_player_GetTime( player );
-    float pos = vlc_player_GetPosition( player );
-    that->callAsync([that,new_length,time,pos] () {
-        PlayerController* q = that->q_func();
-        that->m_length = new_length;
-        emit q->lengthChanged(new_length);
-
-        if ( time != VLC_TICK_INVALID && new_length != VLC_TICK_INVALID )
-            that->m_remainingTime = new_length - time;
-        else
-            that->m_remainingTime = VLC_TICK_INVALID;
-        emit q->remainingTimeChanged(that->m_remainingTime);
-        emit that->q_func()->positionUpdated( pos, time, SEC_FROM_VLC_TICK(new_length) );
-    });
-
-}
-
 static void on_player_track_list_changed(vlc_player_t *, enum vlc_player_list_action action, const struct vlc_player_track *track, void *data)
 {
     PlayerControllerPrivate* that = static_cast<PlayerControllerPrivate*>(data);
@@ -865,6 +831,80 @@ static void on_player_corks_changed(vlc_player_t *, unsigned, void *data)
     msg_Dbg( that->p_intf, "on_player_corks_changed");
 }
 
+static void on_player_timer_update(const struct vlc_player_timer_point *point,
+                                   void *data)
+{
+    PlayerControllerPrivate* that = static_cast<PlayerControllerPrivate*>(data);
+    that->callAsync([that,point_copy = *point](){
+        PlayerController* q = that->q_func();
+
+        that->m_player_time = point_copy;
+        bool lengthOrRateChanged = false;
+
+        if (that->m_length != that->m_player_time.length)
+        {
+            that->m_length = that->m_player_time.length;
+            emit q->lengthChanged(that->m_length);
+
+            lengthOrRateChanged = true;
+        }
+        if (that->m_rate != that->m_player_time.rate)
+        {
+            that->m_rate = that->m_player_time.rate;
+            emit q->rateChanged(that->m_rate);
+
+            lengthOrRateChanged = true;
+        }
+
+        vlc_tick_t system_now = vlc_tick_now();
+        if (that->interpolateTime(system_now) == VLC_SUCCESS)
+        {
+            if (lengthOrRateChanged || !that->m_position_timer.isActive())
+            {
+                q->updatePosition();
+
+                if (that->m_player_time.system_date != INT64_MAX)
+                {
+                    // Setup the position update interval, depending on media
+                    // length and rate.  XXX: VLC_TICK_FROM_MS(1) is an educated
+                    // guess, it should be also calculated according to the slider
+                    // size.
+
+                    vlc_tick_t interval =
+                        that->m_length / that->m_player_time.rate / VLC_TICK_FROM_MS(1);
+                    if (interval < POSITION_MIN_UPDATE_INTERVAL)
+                        interval = POSITION_MIN_UPDATE_INTERVAL;
+
+                    that->m_position_timer.start(MS_FROM_VLC_TICK(interval));
+                }
+            }
+            q->updateTime(system_now, lengthOrRateChanged);
+        }
+
+    });
+}
+
+static void on_player_timer_discontinuity(vlc_tick_t system_date, void *data)
+{
+    PlayerControllerPrivate* that = static_cast<PlayerControllerPrivate*>(data);
+    that->callAsync([that,system_date](){
+        PlayerController* q = that->q_func();
+
+        if (system_date != VLC_TICK_INVALID
+         && that->interpolateTime(system_date) == VLC_SUCCESS)
+        {
+            // The discontinuity event got a valid system date, update the time
+            // properties.
+            q->updatePosition();
+            q->updateTime(system_date, false);
+        }
+
+        // And stop the timers.
+        that->m_position_timer.stop();
+        that->m_time_timer.stop();
+    });
+}
+
 } //extern "C"
 
 static const struct vlc_player_cbs player_cbs = {
@@ -872,10 +912,10 @@ static const struct vlc_player_cbs player_cbs = {
     on_player_state_changed,
     on_player_error_changed,
     on_player_buffering,
-    on_player_rate_changed,
+    nullptr, // on_player_rate_changed: handled by on_player_timer_update
     on_player_capabilities_changed,
-    on_player_position_changed,
-    on_player_length_changed,
+    nullptr, // on_player_position_changed: handled by on_player_timer_update
+    nullptr, // on_player_length_changed: handled by on_player_timer_update
     on_player_track_list_changed,
     on_player_track_selection_changed,
     on_player_track_delay_changed,
@@ -914,6 +954,11 @@ static const struct vlc_player_aout_cbs player_aout_cbs = {
     nullptr
 };
 
+static const struct vlc_player_timer_cbs player_timer_cbs = {
+    on_player_timer_update,
+    on_player_timer_discontinuity,
+};
+
 PlayerControllerPrivate::PlayerControllerPrivate(PlayerController *playercontroller, intf_thread_t *p_intf)
     : q_ptr(playercontroller)
     , p_intf(p_intf)
@@ -939,10 +984,14 @@ PlayerControllerPrivate::PlayerControllerPrivate(PlayerController *playercontrol
         m_player_listener = vlc_player_AddListener( m_player, &player_cbs, this );
         m_player_aout_listener = vlc_player_aout_AddListener( m_player, &player_aout_cbs, this );
         m_player_vout_listener = vlc_player_vout_AddListener( m_player, &player_vout_cbs, this );
+        m_player_timer = vlc_player_AddTimer( m_player, VLC_TICK_FROM_MS(500), &player_timer_cbs, this );
     }
 
     QObject::connect( &m_autoscale, &QVLCBool::valueChanged, q_ptr, &PlayerController::autoscaleChanged );
     QObject::connect( &m_audioVisualization, &VLCVarChoiceModel::hasCurrentChanged, q_ptr, &PlayerController::hasAudioVisualizationChanged );
+
+    m_time_timer.setSingleShot( true );
+    m_time_timer.setTimerType( Qt::PreciseTimer );
 }
 
 PlayerController::PlayerController( intf_thread_t *_p_intf )
@@ -952,6 +1001,8 @@ PlayerController::PlayerController( intf_thread_t *_p_intf )
     /* Audio Menu */
     menusAudioMapper = new QSignalMapper(this);
     CONNECT( menusAudioMapper, mapped(const QString&), this, menusUpdateAudio(const QString&) );
+    CONNECT( &d_ptr->m_position_timer, timeout(), this, updatePositionFromTimer() );
+    CONNECT( &d_ptr->m_time_timer, timeout(), this, updateTimeFromTimer() );
 
     input_fetcher_cbs.on_art_fetch_ended = onArtFetchEnded_callback;
 }
@@ -1374,6 +1425,70 @@ void PlayerController::menusUpdateAudio( const QString& data )
         aout_DeviceSet( aout.get(), qtu(data) );
 }
 
+void PlayerController::updatePosition()
+{
+    Q_D(PlayerController);
+
+    // Update position properties
+    emit positionChanged(d->m_position);
+    emit positionUpdated(d->m_position, d->m_time,
+                         SEC_FROM_VLC_TICK(d->m_length));
+}
+
+void PlayerController::updatePositionFromTimer()
+{
+    Q_D(PlayerController);
+
+    vlc_tick_t system_now = vlc_tick_now();
+    if (d->interpolateTime(system_now) == VLC_SUCCESS)
+        updatePosition();
+}
+
+void PlayerController::updateTime(vlc_tick_t system_now, bool forceUpdate)
+{
+    Q_D(PlayerController);
+
+    // Update time properties
+    emit timeChanged(d->m_time);
+    if (d->m_time != VLC_TICK_INVALID && d->m_length != VLC_TICK_INVALID)
+        d->m_remainingTime = d->m_length - d->m_time;
+    else
+        d->m_remainingTime = VLC_TICK_INVALID;
+    emit remainingTimeChanged(d->m_remainingTime);
+
+    if (d->m_player_time.system_date != INT64_MAX
+     && (forceUpdate || !d->m_time_timer.isActive()))
+    {
+        // Tell the timer to wait until the next second is reached.
+        vlc_tick_t next_update_date =
+            vlc_player_timer_point_GetNextIntervalDate(&d->m_player_time, system_now,
+                                                       d->m_time, VLC_TICK_FROM_SEC(1));
+
+        vlc_tick_t next_update_interval = next_update_date - system_now;
+
+        if (next_update_interval > 0)
+        {
+            // The timer can be triggered a little before. In that case, it's
+            // likely that we didn't reach the next next second. It's better to
+            // add a very small delay in order to be triggered after the next
+            // seconds.
+            static const unsigned imprecision_delay_ms = 30;
+
+            d->m_time_timer.start(MS_FROM_VLC_TICK(next_update_interval)
+                                  + imprecision_delay_ms);
+        }
+    }
+}
+
+void PlayerController::updateTimeFromTimer()
+{
+    Q_D(PlayerController);
+
+    vlc_tick_t system_now = vlc_tick_now();
+    if (d->interpolateTime(system_now) == VLC_SUCCESS)
+        updateTime(system_now, false);
+}
+
 //MISC
 
 void PlayerController::setABloopState(ABLoopState state)
diff --git a/modules/gui/qt/components/player_controller.hpp b/modules/gui/qt/components/player_controller.hpp
index 7fb4384886..66a474e056 100644
--- a/modules/gui/qt/components/player_controller.hpp
+++ b/modules/gui/qt/components/player_controller.hpp
@@ -247,6 +247,8 @@ public:
     void requestArtUpdate( input_item_t *p_item, bool b_forced );
     void setArt( input_item_t *p_item, QString fileUrl );
     static const QString decodeArtURL( input_item_t *p_item );
+    void updatePosition();
+    void updateTime(vlc_tick_t system_now, bool forceTimer);
 
     //getter/setters binded to a Q_PROPERTY
 public slots:
@@ -269,6 +271,8 @@ public slots:
     bool isRewindable() const;
     bool isPausable() const;
     bool isRateChangable() const;
+    void updatePositionFromTimer();
+    void updateTimeFromTimer();
 
     //tracks
     TrackListModel* getVideoTracks();
diff --git a/modules/gui/qt/components/player_controller_p.hpp b/modules/gui/qt/components/player_controller_p.hpp
index dcc28c929f..df167228b1 100644
--- a/modules/gui/qt/components/player_controller_p.hpp
+++ b/modules/gui/qt/components/player_controller_p.hpp
@@ -24,6 +24,8 @@
 #include "util/input_models.hpp"
 #include "adapters/var_choice_model.hpp"
 
+#include <QTimer>
+
 class PlayerControllerPrivate {
     Q_DISABLE_COPY(PlayerControllerPrivate)
 public:
@@ -44,6 +46,7 @@ public:
     void UpdateVouts(vout_thread_t **vouts, size_t i_vouts);
     void UpdateTrackSelection(vlc_es_id_t *trackid, bool selected);
     void UpdateSpuOrder(vlc_es_id_t *es_id, enum vlc_vout_order spu_order);
+    int interpolateTime(vlc_tick_t system_now);
 
     ///call function @a fun on object thread
     template <typename Fun>
@@ -93,6 +96,13 @@ public:
     VLCTick      m_secondarySubtitleDelay = 0;
     float        m_subtitleFPS = 1.0;
 
+    //timer
+    vlc_player_timer_id* m_player_timer = nullptr;
+    vlc_player_timer_id* m_player_timer_smpte = nullptr;
+    struct vlc_player_timer_point m_player_time;
+    QTimer m_position_timer;
+    QTimer m_time_timer;
+
     //title/chapters/menu
     TitleListModel m_titleList;
     ChapterListModel m_chapterList;



More information about the vlc-commits mailing list