From 82f4830bf59326093f87d9ded6769dfadbbed1c1 Mon Sep 17 00:00:00 2001 From: Thomas Guillem Date: Mon, 5 Feb 2018 18:44:16 +0100 Subject: [PATCH] chromecast: rework seek Don't seek from demux filter but from the the sout. Do it only one time for every stream ids. Pause the httpd server while seeking in order to prevent the CC to flush valid post flush buffers. --- modules/stream_out/chromecast/cast.cpp | 60 ++++++++++++++++++++-- modules/stream_out/chromecast/chromecast.h | 9 +++- modules/stream_out/chromecast/chromecast_common.h | 2 - modules/stream_out/chromecast/chromecast_ctrl.cpp | 30 ++++++----- modules/stream_out/chromecast/chromecast_demux.cpp | 54 +------------------ 5 files changed, 81 insertions(+), 74 deletions(-) diff --git a/modules/stream_out/chromecast/cast.cpp b/modules/stream_out/chromecast/cast.cpp index 71c5448790..9977ddfdf6 100644 --- a/modules/stream_out/chromecast/cast.cpp +++ b/modules/stream_out/chromecast/cast.cpp @@ -47,6 +47,8 @@ struct sout_access_out_sys_t vlc_fifo_t *m_fifo; block_t *m_header; bool m_eof; + bool m_flushing; + bool m_seeking; std::string m_mime; sout_access_out_sys_t(httpd_host_t *httpd_host, intf_sys_t * const intf, @@ -55,8 +57,10 @@ struct sout_access_out_sys_t void clearUnlocked(); void clear(); + void flush(); void prepare(sout_stream_t *p_stream, const std::string &mime); int url_cb(httpd_client_t *cl, httpd_message_t *answer, const httpd_message_t *query); + void seek_done_cb(); }; struct sout_stream_sys_t @@ -312,16 +316,24 @@ static int ProxyOpen(vlc_object_t *p_this) static int httpd_url_cb(httpd_callback_sys_t *data, httpd_client_t *cl, httpd_message_t *answer, const httpd_message_t *query) { - sout_access_out_sys_t *p_sys = (sout_access_out_sys_t *) data; + sout_access_out_sys_t *p_sys = reinterpret_cast(data); return p_sys->url_cb(cl, answer, query); } +static void on_seek_done_cb(void *data) +{ + sout_access_out_sys_t *p_sys = reinterpret_cast(data); + p_sys->seek_done_cb(); +} + sout_access_out_sys_t::sout_access_out_sys_t(httpd_host_t *httpd_host, intf_sys_t * const intf, const char *psz_url) : m_intf(intf) , m_header(NULL) , m_eof(true) + , m_flushing(false) + , m_seeking(false) { m_fifo = block_FifoNew(); if (!m_fifo) @@ -362,6 +374,19 @@ void sout_access_out_sys_t::clear() vlc_fifo_Signal(m_fifo); } +void sout_access_out_sys_t::flush() +{ + vlc_fifo_Lock(m_fifo); + block_ChainRelease(vlc_fifo_DequeueAllUnlocked(m_fifo)); + vlc_fifo_Unlock(m_fifo); + + m_intf->setPacing(false); + + /* Don't seek from here since flush can be called several time (one time + * per id). */ + m_flushing = true; +} + void sout_access_out_sys_t::prepare(sout_stream_t *p_stream, const std::string &mime) { var_SetAddress(p_stream->p_sout, SOUT_CFG_PREFIX "access-out-sys", this); @@ -370,9 +395,19 @@ void sout_access_out_sys_t::prepare(sout_stream_t *p_stream, const std::string & clearUnlocked(); m_mime = mime; m_eof = false; + m_flushing = false; + m_seeking = false; vlc_fifo_Unlock(m_fifo); } +void sout_access_out_sys_t::seek_done_cb() +{ + vlc_fifo_Lock(m_fifo); + m_seeking = false; + vlc_fifo_Unlock(m_fifo); + vlc_fifo_Signal(m_fifo); +} + int sout_access_out_sys_t::url_cb(httpd_client_t *cl, httpd_message_t *answer, const httpd_message_t *query) { @@ -386,6 +421,11 @@ int sout_access_out_sys_t::url_cb(httpd_client_t *cl, httpd_message_t *answer, && !m_eof) vlc_fifo_Wait(m_fifo); + /* Wait for the seek to be done. This will prevent the CC to flush this + * buffer that came after a flush. */ + while (m_seeking && !m_eof) + vlc_fifo_Wait(m_fifo); + /* Handle block headers */ if (p_block) { @@ -457,6 +497,17 @@ static ssize_t AccessWrite(sout_access_out_t *p_access, block_t *p_block) vlc_fifo_Lock(p_sys->m_fifo); + if (p_sys->m_flushing) + { + p_sys->m_flushing = false; + p_sys->m_seeking = true; + + vlc_fifo_Unlock(p_sys->m_fifo); + /* TODO: put better timestamp */ + p_sys->m_intf->requestPlayerSeek(mdate() + INT64_C(1000000)); + vlc_fifo_Lock(p_sys->m_fifo); + } + /* Tell the demux filter to pace when the fifo starts to be full */ bool do_pace = vlc_fifo_GetBytes(p_sys->m_fifo) >= HTTPD_BUFFER_MAX; @@ -1029,10 +1080,8 @@ static void Flush( sout_stream_t *p_stream, sout_stream_id_sys_t *id ) if ( id == NULL || p_sys->drained ) return; - /* a seek on the Chromecast flushes its buffers */ - p_sys->p_intf->requestPlayerSeek( VLC_TS_INVALID ); - sout_StreamFlush( p_sys->p_out, id ); + p_sys->access_out_live.flush(); } static int Control(sout_stream_t *p_stream, int i_query, va_list args) @@ -1148,6 +1197,8 @@ static int Open(vlc_object_t *p_this) if (unlikely(p_sys == NULL)) goto error; + p_intf->setOnSeekDoneCb(on_seek_done_cb, &p_sys->access_out_live); + /* prevent sout-mux-caching since chromecast-proxy is already doing it */ var_Create( p_stream->p_sout, "sout-mux-caching", VLC_VAR_INTEGER ); var_SetInteger( p_stream->p_sout, "sout-mux-caching", 0 ); @@ -1199,6 +1250,7 @@ static void Close(vlc_object_t *p_this) httpd_host_t *httpd_host = p_sys->httpd_host; intf_sys_t *p_intf = p_sys->p_intf; + p_intf->setOnSeekDoneCb(NULL, NULL); delete p_sys; delete p_intf; /* Delete last since p_intf and p_sys depends on httpd_host */ diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h index cb0b6b3b23..201086bc2b 100644 --- a/modules/stream_out/chromecast/chromecast.h +++ b/modules/stream_out/chromecast/chromecast.h @@ -148,6 +148,8 @@ private: std::string m_serverIp; }; +typedef void (*on_seek_done_itf)( void *data ); + /***************************************************************************** * intf_sys_t: description and status of interface *****************************************************************************/ @@ -167,6 +169,7 @@ struct intf_sys_t void setHasInput(const std::string mime_type = ""); void requestPlayerSeek(mtime_t pos); + void setOnSeekDoneCb(on_seek_done_itf on_seek_done, void *on_seek_done_data); void requestPlayerStop(); States state() const; @@ -217,8 +220,6 @@ private: static void pace(void*); - static void request_seek(void*, mtime_t pos); - static void set_pause_state(void*, bool paused); static void set_meta(void*, vlc_meta_t *p_meta); @@ -238,6 +239,9 @@ private: vlc_cond_t m_pace_cond; vlc_thread_t m_chromecastThread; + on_seek_done_itf m_on_seek_done; + void *m_on_seek_done_data; + ChromecastCommunication m_communication; std::queue m_msgQueue; States m_state; @@ -260,6 +264,7 @@ private: mtime_t m_time_playback_started; /* local playback time of the input when playback started/resumed */ mtime_t m_ts_local_start; + mtime_t m_ts_seek; mtime_t m_length; /* shared structure with the demux-filter */ diff --git a/modules/stream_out/chromecast/chromecast_common.h b/modules/stream_out/chromecast/chromecast_common.h index f1ce43c232..c8e1726946 100644 --- a/modules/stream_out/chromecast/chromecast_common.h +++ b/modules/stream_out/chromecast/chromecast_common.h @@ -44,8 +44,6 @@ typedef struct void (*pf_pace)(void*); - void (*pf_request_seek)(void*, mtime_t pos); - void (*pf_set_pause_state)(void*, bool paused); void (*pf_set_meta)(void*, vlc_meta_t *p_meta); diff --git a/modules/stream_out/chromecast/chromecast_ctrl.cpp b/modules/stream_out/chromecast/chromecast_ctrl.cpp index d88e651e1e..83faa09d51 100644 --- a/modules/stream_out/chromecast/chromecast_ctrl.cpp +++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp @@ -47,8 +47,6 @@ static int httpd_file_fill_cb( httpd_file_sys_t *data, httpd_file_t *http_file, uint8_t *psz_request, uint8_t **pp_data, int *pi_data ); -static const mtime_t SEEK_FORWARD_OFFSET = 1000000; - static const char* StateToStr( States s ) { switch (s ) @@ -105,6 +103,7 @@ intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device , m_art_url(NULL) , m_time_playback_started( VLC_TS_INVALID ) , m_ts_local_start( VLC_TS_INVALID ) + , m_ts_seek( VLC_TS_INVALID ) , m_length( VLC_TS_INVALID ) , m_pingRetriesLeft( PING_WAIT_RETRIES ) { @@ -126,7 +125,6 @@ intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device m_common.pf_set_length = set_length; m_common.pf_set_initial_time = set_initial_time; m_common.pf_pace = pace; - m_common.pf_request_seek = request_seek; m_common.pf_set_pause_state = set_pause_state; m_common.pf_set_meta = set_meta; @@ -469,16 +467,16 @@ void intf_sys_t::mainLoop() break; case Seek: { - if( !isStatePlaying() || m_mediaSessionId == 0 ) + if( !isStatePlaying() || m_mediaSessionId == 0 || m_ts_seek == VLC_TS_INVALID ) break; char current_time[32]; - mtime_t seek_request_time = mdate() + SEEK_FORWARD_OFFSET; if( snprintf( current_time, sizeof(current_time), "%.3f", - double( seek_request_time ) / 1000000.0 ) >= (int)sizeof(current_time) ) + double( m_ts_seek ) / 1000000.0 ) >= (int)sizeof(current_time) ) { msg_Err( m_module, "snprintf() truncated string for mediaSessionId" ); current_time[sizeof(current_time) - 1] = '\0'; } + m_ts_seek = VLC_TS_INVALID; /* send a fake time to seek to, to make sure the device flushes its buffers */ m_communication.msgPlayerSeek( m_appTransportId, m_mediaSessionId, current_time ); setState( Seeking ); @@ -891,6 +889,7 @@ void intf_sys_t::requestPlayerStop() vlc_mutex_locker locker(&m_lock); m_request_load = false; + m_ts_seek = VLC_TS_INVALID; if( !isStatePlaying() ) return; @@ -909,11 +908,17 @@ void intf_sys_t::requestPlayerSeek(mtime_t pos) vlc_mutex_locker locker(&m_lock); if( !isStatePlaying() || m_mediaSessionId == 0 ) return; - if ( pos != VLC_TS_INVALID ) - m_ts_local_start = pos; + m_ts_seek = pos; queueMessage( Seek ); } +void intf_sys_t::setOnSeekDoneCb(on_seek_done_itf on_seek_done, void *on_seek_done_data) +{ + vlc_mutex_locker locker(&m_lock); + m_on_seek_done = on_seek_done; + m_on_seek_done_data = on_seek_done_data; +} + void intf_sys_t::setPauseState(bool paused) { msg_Dbg( m_module, "%s state", paused ? "paused" : "playing" ); @@ -991,6 +996,9 @@ void intf_sys_t::setState( States state ) #ifndef NDEBUG msg_Dbg( m_module, "Switching from state %s to %s", StateToStr( m_state ), StateToStr( state ) ); #endif + if (state == Seeking) + if (m_on_seek_done != NULL) + m_on_seek_done(m_on_seek_done_data); m_state = state; switch( m_state ) @@ -1039,12 +1047,6 @@ void intf_sys_t::pace(void *pt) p_this->pace(); } -void intf_sys_t::request_seek(void *pt, mtime_t pos) -{ - intf_sys_t *p_this = static_cast(pt); - p_this->requestPlayerSeek(pos); -} - void intf_sys_t::set_pause_state(void *pt, bool paused) { intf_sys_t *p_this = static_cast(pt); diff --git a/modules/stream_out/chromecast/chromecast_demux.cpp b/modules/stream_out/chromecast/chromecast_demux.cpp index 8872b53661..030712a3ea 100644 --- a/modules/stream_out/chromecast/chromecast_demux.cpp +++ b/modules/stream_out/chromecast/chromecast_demux.cpp @@ -150,24 +150,6 @@ struct demux_sys_t this->canSeek = canSeek; } - bool seekTo( double pos ) - { - if (i_length == -1) - return false; - return seekTo( mtime_t( i_length * pos ) ); - } - - bool seekTo( mtime_t i_pos ) - { - if ( !canSeek ) - return false; - - /* seeking will be handled with the Chromecast */ - p_renderer->pf_request_seek( p_renderer->p_opaque, i_pos ); - - return true; - } - void setLength( mtime_t length ) { this->i_length = length; @@ -235,45 +217,13 @@ struct demux_sys_t case DEMUX_SET_POSITION: { - va_list ap; - - va_copy( ap, args ); - double pos = va_arg( ap, double ); - va_end( ap ); - - if ( getPlaybackTime() == VLC_TS_INVALID ) - { - msg_Dbg( p_demux_filter, "internal seek to %f when the playback didn't start", pos ); - break; // seek before device started, likely on-the-fly restart - } - - if ( !seekTo( pos ) ) - { - msg_Err( p_demux_filter, "failed to seek to %f", pos ); - return VLC_EGENERIC; - } + m_startTime = VLC_TS_INVALID; break; } case DEMUX_SET_TIME: { - va_list ap; - - va_copy( ap, args ); - mtime_t pos = va_arg( ap, mtime_t ); - va_end( ap ); - - if ( getPlaybackTime() == VLC_TS_INVALID ) - { - msg_Dbg( p_demux_filter, "internal seek to %" PRId64 " when the playback didn't start", pos ); - break; // seek before device started, likely on-the-fly restart - } - - if ( !seekTo( pos ) ) - { - msg_Err( p_demux_filter, "failed to seek to time %" PRId64, pos ); - return VLC_EGENERIC; - } + m_startTime = VLC_TS_INVALID; break; } case DEMUX_SET_PAUSE_STATE: -- 2.11.4.GIT