[vlc-devel] [PATCH 04/10] chromecast: use the demux-filter to display the correct playback time

Steve Lhomme robux4 at videolabs.io
Tue May 3 16:01:40 CEST 2016


The device buffers about 8s before starting playing so we wait until the
Chromecast starts playing to start a monotone clock in the demux filter.
---
 modules/stream_out/chromecast/chromecast.h         | 37 ++++++++++++++++++
 modules/stream_out/chromecast/chromecast_common.h  |  3 ++
 modules/stream_out/chromecast/chromecast_ctrl.cpp  | 45 +++++++++++++++++++++-
 modules/stream_out/chromecast/chromecast_demux.cpp | 45 ++++++++++++++++++++++
 4 files changed, 129 insertions(+), 1 deletion(-)

diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h
index c37728d..2073656 100644
--- a/modules/stream_out/chromecast/chromecast.h
+++ b/modules/stream_out/chromecast/chromecast.h
@@ -180,8 +180,45 @@ private:
     bool           has_input;
     static void* ChromecastThread(void* p_data);
 
+    mtime_t getPlaybackTimestamp() const
+    {
+        switch( receiverState )
+        {
+        case RECEIVER_PLAYING:
+            return ( mdate() - m_time_playback_started ) + i_ts_local_start;
+
+        case RECEIVER_IDLE:
+            msg_Dbg(p_module, "receiver idle using buffering time %" PRId64, i_ts_local_start);
+            break;
+        case RECEIVER_BUFFERING:
+            msg_Dbg(p_module, "receiver buffering using buffering time %" PRId64, i_ts_local_start);
+            break;
+        case RECEIVER_PAUSED:
+            msg_Dbg(p_module, "receiver paused using buffering time %" PRId64, i_ts_local_start);
+            break;
+        }
+        return i_ts_local_start;
+    }
+
+    double getPlaybackPosition( mtime_t i_length ) const
+    {
+        if( i_length > 0 && m_time_playback_started != VLC_TS_INVALID)
+            return (double) getPlaybackTimestamp() / (double)( i_length );
+        return 0.0;
+    }
+
+    /* local date when playback started/resumed, used by monotone clock */
+    mtime_t           m_time_playback_started;
+    /* local playback time of the input when playback started/resumed */
+    mtime_t           i_ts_local_start;
+    mtime_t           i_length;
+
     /* shared structure with the demux-filter */
     chromecast_common      common;
+
+    static void set_length(void*, mtime_t length);
+    static mtime_t get_time(void*);
+    static double get_position(void*);
 };
 
 #endif /* VLC_CHROMECAST_H */
diff --git a/modules/stream_out/chromecast/chromecast_common.h b/modules/stream_out/chromecast/chromecast_common.h
index a0d87b5..8c27272 100644
--- a/modules/stream_out/chromecast/chromecast_common.h
+++ b/modules/stream_out/chromecast/chromecast_common.h
@@ -35,6 +35,9 @@ typedef struct
 {
     void *p_opaque;
 
+    void (*pf_set_length)(void*, mtime_t length);
+    mtime_t (*pf_get_time)(void*);
+    double (*pf_get_position)(void*);
 } chromecast_common;
 
 # ifdef __cplusplus
diff --git a/modules/stream_out/chromecast/chromecast_ctrl.cpp b/modules/stream_out/chromecast/chromecast_ctrl.cpp
index c2bec9e..91500d8 100644
--- a/modules/stream_out/chromecast/chromecast_ctrl.cpp
+++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp
@@ -111,11 +111,17 @@ intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device
  , i_receiver_requestId(0)
  , i_requestId(0)
  , has_input(false)
+ , m_time_playback_started( VLC_TS_INVALID )
+ , i_ts_local_start( VLC_TS_INVALID )
+ , i_length( VLC_TS_INVALID )
 {
     vlc_mutex_init_recursive(&lock);
     vlc_cond_init(&loadCommandCond);
 
     common.p_opaque = this;
+    common.pf_get_position = get_position;
+    common.pf_get_time = get_time;
+    common.pf_set_length = set_length;
 
     assert( var_Type( p_module->p_parent->p_parent, CC_SHARED_VAR_NAME) == 0 );
     if (var_Create( p_module->p_parent->p_parent, CC_SHARED_VAR_NAME, VLC_VAR_ADDRESS ) == VLC_SUCCESS )
@@ -191,6 +197,7 @@ void intf_sys_t::setHasInput( bool b_has_input, const std::string mime_type )
         if ( receiverState == RECEIVER_IDLE )
         {
             // we cannot start a new load when the last one is still processing
+            i_ts_local_start = VLC_TS_0;
             msgPlayerLoad();
             setPlayerStatus(CMD_LOAD_SENT);
         }
@@ -555,17 +562,32 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
                 case RECEIVER_PLAYING:
                     /* TODO reset demux PCR ? */
                     setPlayerStatus(CMD_PLAYBACK_SENT);
+                    m_time_playback_started = mdate();
+#ifndef NDEBUG
+                    msg_Dbg( p_module, "Playback started now:%" PRId64 " i_ts_local_start:%" PRId64, m_time_playback_started, i_ts_local_start);
+#endif
                     break;
 
                 case RECEIVER_PAUSED:
 #ifndef NDEBUG
-                    msg_Dbg( p_module, "Playback paused");
+                    msg_Dbg( p_module, "Playback paused date_play_start:%" PRId64, m_time_playback_started);
+#endif
+
+                    if ( m_time_playback_started != VLC_TS_INVALID && oldPlayerState == RECEIVER_PLAYING )
+                    {
+                        /* this is a pause generated remotely, adjust the playback time */
+                        i_ts_local_start += mdate() - m_time_playback_started;
+#ifndef NDEBUG
+                        msg_Dbg( p_module, "updated i_ts_local_start:%" PRId64, i_ts_local_start);
 #endif
+                    }
+                    m_time_playback_started = VLC_TS_INVALID;
                     break;
 
                 case RECEIVER_IDLE:
                     if ( has_input )
                         setPlayerStatus(NO_CMD_PENDING);
+                    m_time_playback_started = VLC_TS_INVALID;
                     break;
                 }
             }
@@ -573,6 +595,7 @@ void intf_sys_t::processMessage(const castchannel::CastMessage &msg)
             if ( cmd_status != CMD_LOAD_SENT && receiverState == RECEIVER_IDLE && has_input )
             {
                 msg_Dbg( p_module, "the device missed the LOAD command");
+                i_ts_local_start = VLC_TS_0;
                 msgPlayerLoad();
                 setPlayerStatus(CMD_LOAD_SENT);
             }
@@ -1003,3 +1026,23 @@ void intf_sys_t::requestPlayerSeek()
     requested_seek = true;
     notifySendRequest();
 }
+
+mtime_t intf_sys_t::get_time(void *pt)
+{
+    intf_sys_t *p_this = reinterpret_cast<intf_sys_t*>(pt);
+    vlc_mutex_locker locker( &p_this->lock );
+    return p_this->getPlaybackTimestamp();
+}
+
+double intf_sys_t::get_position(void *pt)
+{
+    intf_sys_t *p_this = reinterpret_cast<intf_sys_t*>(pt);
+    vlc_mutex_locker locker( &p_this->lock );
+    return p_this->getPlaybackPosition( p_this->i_length );
+}
+
+void intf_sys_t::set_length(void *pt, mtime_t length)
+{
+    intf_sys_t *p_this = reinterpret_cast<intf_sys_t*>(pt);
+    p_this->i_length = length;
+}
diff --git a/modules/stream_out/chromecast/chromecast_demux.cpp b/modules/stream_out/chromecast/chromecast_demux.cpp
index 5706a69..78aaab0 100644
--- a/modules/stream_out/chromecast/chromecast_demux.cpp
+++ b/modules/stream_out/chromecast/chromecast_demux.cpp
@@ -48,6 +48,25 @@ struct demux_sys_t
     {
     }
 
+    /**
+     * @brief getPlaybackTime
+     * @return the current playback time on the device or VLC_TS_INVALID if unknown
+     */
+    mtime_t getPlaybackTime()
+    {
+        return p_renderer->pf_get_time( p_renderer->p_opaque );
+    }
+
+    double getPlaybackPosition()
+    {
+        return p_renderer->pf_get_position( p_renderer->p_opaque );
+    }
+
+    void setLength( mtime_t length )
+    {
+        p_renderer->pf_set_length( p_renderer->p_opaque, length );
+    }
+
     int Demux()
     {
         return demux_FilterDemuxNext( p_demux );
@@ -67,6 +86,32 @@ static int Demux( demux_filter_t *p_demux_filter )
 
 static int Control( demux_filter_t *p_demux_filter, int i_query, va_list args)
 {
+    demux_sys_t *p_sys = p_demux_filter->p_sys;
+
+    switch (i_query)
+    {
+    case DEMUX_GET_POSITION:
+        *va_arg( args, double * ) = p_sys->getPlaybackPosition();
+        return VLC_SUCCESS;
+
+    case DEMUX_GET_TIME:
+        *va_arg(args, int64_t *) = p_sys->getPlaybackTime();
+        return VLC_SUCCESS;
+
+    case DEMUX_GET_LENGTH:
+    {
+        int ret;
+        va_list ap;
+
+        va_copy( ap, args );
+        ret = demux_vaFilterControlNext( p_demux_filter, i_query, args );
+        if( ret == VLC_SUCCESS )
+            p_sys->setLength( *va_arg( ap, int64_t * ) );
+        va_end( ap );
+        return ret;
+    }
+    }
+
     return demux_vaFilterControlNext( p_demux_filter, i_query, args );
 }
 
-- 
2.7.0



More information about the vlc-devel mailing list