Commit 0969655b authored by Thomas Guillem's avatar Thomas Guillem Committed by Jean-Baptiste Kempf

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.

(cherry picked from commit 82f4830b)
Signed-off-by: Jean-Baptiste Kempf's avatarJean-Baptiste Kempf <jb@videolan.org>
parent 1cf7db9a
...@@ -47,6 +47,8 @@ struct sout_access_out_sys_t ...@@ -47,6 +47,8 @@ struct sout_access_out_sys_t
vlc_fifo_t *m_fifo; vlc_fifo_t *m_fifo;
block_t *m_header; block_t *m_header;
bool m_eof; bool m_eof;
bool m_flushing;
bool m_seeking;
std::string m_mime; std::string m_mime;
sout_access_out_sys_t(httpd_host_t *httpd_host, intf_sys_t * const intf, 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 ...@@ -55,8 +57,10 @@ struct sout_access_out_sys_t
void clearUnlocked(); void clearUnlocked();
void clear(); void clear();
void flush();
void prepare(sout_stream_t *p_stream, const std::string &mime); 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); 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 struct sout_stream_sys_t
...@@ -314,16 +318,24 @@ static int ProxyOpen(vlc_object_t *p_this) ...@@ -314,16 +318,24 @@ static int ProxyOpen(vlc_object_t *p_this)
static int httpd_url_cb(httpd_callback_sys_t *data, httpd_client_t *cl, static int httpd_url_cb(httpd_callback_sys_t *data, httpd_client_t *cl,
httpd_message_t *answer, const httpd_message_t *query) 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<sout_access_out_sys_t *>(data);
return p_sys->url_cb(cl, answer, query); 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<sout_access_out_sys_t *>(data);
p_sys->seek_done_cb();
}
sout_access_out_sys_t::sout_access_out_sys_t(httpd_host_t *httpd_host, sout_access_out_sys_t::sout_access_out_sys_t(httpd_host_t *httpd_host,
intf_sys_t * const intf, intf_sys_t * const intf,
const char *psz_url) const char *psz_url)
: m_intf(intf) : m_intf(intf)
, m_header(NULL) , m_header(NULL)
, m_eof(true) , m_eof(true)
, m_flushing(false)
, m_seeking(false)
{ {
m_fifo = block_FifoNew(); m_fifo = block_FifoNew();
if (!m_fifo) if (!m_fifo)
...@@ -364,6 +376,19 @@ void sout_access_out_sys_t::clear() ...@@ -364,6 +376,19 @@ void sout_access_out_sys_t::clear()
vlc_fifo_Signal(m_fifo); 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) 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); var_SetAddress(p_stream->p_sout, SOUT_CFG_PREFIX "access-out-sys", this);
...@@ -372,9 +397,19 @@ void sout_access_out_sys_t::prepare(sout_stream_t *p_stream, const std::string & ...@@ -372,9 +397,19 @@ void sout_access_out_sys_t::prepare(sout_stream_t *p_stream, const std::string &
clearUnlocked(); clearUnlocked();
m_mime = mime; m_mime = mime;
m_eof = false; m_eof = false;
m_flushing = false;
m_seeking = false;
vlc_fifo_Unlock(m_fifo); 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, int sout_access_out_sys_t::url_cb(httpd_client_t *cl, httpd_message_t *answer,
const httpd_message_t *query) const httpd_message_t *query)
{ {
...@@ -388,6 +423,11 @@ int sout_access_out_sys_t::url_cb(httpd_client_t *cl, httpd_message_t *answer, ...@@ -388,6 +423,11 @@ int sout_access_out_sys_t::url_cb(httpd_client_t *cl, httpd_message_t *answer,
&& !m_eof) && !m_eof)
vlc_fifo_Wait(m_fifo); 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 */ /* Handle block headers */
if (p_block) if (p_block)
{ {
...@@ -459,6 +499,17 @@ static ssize_t AccessWrite(sout_access_out_t *p_access, block_t *p_block) ...@@ -459,6 +499,17 @@ static ssize_t AccessWrite(sout_access_out_t *p_access, block_t *p_block)
vlc_fifo_Lock(p_sys->m_fifo); 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 */ /* 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; bool do_pace = vlc_fifo_GetBytes(p_sys->m_fifo) >= HTTPD_BUFFER_MAX;
...@@ -1031,10 +1082,8 @@ static void Flush( sout_stream_t *p_stream, sout_stream_id_sys_t *id ) ...@@ -1031,10 +1082,8 @@ static void Flush( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
if ( id == NULL || p_sys->drained ) if ( id == NULL || p_sys->drained )
return; return;
/* a seek on the Chromecast flushes its buffers */
p_sys->p_intf->requestPlayerSeek( VLC_TS_INVALID );
sout_StreamFlush( p_sys->p_out, id ); 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) static int Control(sout_stream_t *p_stream, int i_query, va_list args)
...@@ -1153,6 +1202,8 @@ static int Open(vlc_object_t *p_this) ...@@ -1153,6 +1202,8 @@ static int Open(vlc_object_t *p_this)
if (unlikely(p_sys == NULL)) if (unlikely(p_sys == NULL))
goto error; 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 */ /* prevent sout-mux-caching since chromecast-proxy is already doing it */
var_Create( p_stream->p_sout, "sout-mux-caching", VLC_VAR_INTEGER ); var_Create( p_stream->p_sout, "sout-mux-caching", VLC_VAR_INTEGER );
var_SetInteger( p_stream->p_sout, "sout-mux-caching", 0 ); var_SetInteger( p_stream->p_sout, "sout-mux-caching", 0 );
...@@ -1204,6 +1255,7 @@ static void Close(vlc_object_t *p_this) ...@@ -1204,6 +1255,7 @@ static void Close(vlc_object_t *p_this)
httpd_host_t *httpd_host = p_sys->httpd_host; httpd_host_t *httpd_host = p_sys->httpd_host;
intf_sys_t *p_intf = p_sys->p_intf; intf_sys_t *p_intf = p_sys->p_intf;
p_intf->setOnSeekDoneCb(NULL, NULL);
delete p_sys; delete p_sys;
delete p_intf; delete p_intf;
/* Delete last since p_intf and p_sys depends on httpd_host */ /* Delete last since p_intf and p_sys depends on httpd_host */
......
...@@ -148,6 +148,8 @@ private: ...@@ -148,6 +148,8 @@ private:
std::string m_serverIp; std::string m_serverIp;
}; };
typedef void (*on_seek_done_itf)( void *data );
/***************************************************************************** /*****************************************************************************
* intf_sys_t: description and status of interface * intf_sys_t: description and status of interface
*****************************************************************************/ *****************************************************************************/
...@@ -167,6 +169,7 @@ struct intf_sys_t ...@@ -167,6 +169,7 @@ struct intf_sys_t
void setHasInput(const std::string mime_type = ""); void setHasInput(const std::string mime_type = "");
void requestPlayerSeek(mtime_t pos); void requestPlayerSeek(mtime_t pos);
void setOnSeekDoneCb(on_seek_done_itf on_seek_done, void *on_seek_done_data);
void requestPlayerStop(); void requestPlayerStop();
States state() const; States state() const;
...@@ -217,8 +220,6 @@ private: ...@@ -217,8 +220,6 @@ private:
static void pace(void*); static void pace(void*);
static void request_seek(void*, mtime_t pos);
static void set_pause_state(void*, bool paused); static void set_pause_state(void*, bool paused);
static void set_meta(void*, vlc_meta_t *p_meta); static void set_meta(void*, vlc_meta_t *p_meta);
...@@ -238,6 +239,9 @@ private: ...@@ -238,6 +239,9 @@ private:
vlc_cond_t m_pace_cond; vlc_cond_t m_pace_cond;
vlc_thread_t m_chromecastThread; vlc_thread_t m_chromecastThread;
on_seek_done_itf m_on_seek_done;
void *m_on_seek_done_data;
ChromecastCommunication m_communication; ChromecastCommunication m_communication;
std::queue<QueueableMessages> m_msgQueue; std::queue<QueueableMessages> m_msgQueue;
States m_state; States m_state;
...@@ -260,6 +264,7 @@ private: ...@@ -260,6 +264,7 @@ private:
mtime_t m_time_playback_started; mtime_t m_time_playback_started;
/* local playback time of the input when playback started/resumed */ /* local playback time of the input when playback started/resumed */
mtime_t m_ts_local_start; mtime_t m_ts_local_start;
mtime_t m_ts_seek;
mtime_t m_length; mtime_t m_length;
/* shared structure with the demux-filter */ /* shared structure with the demux-filter */
......
...@@ -44,8 +44,6 @@ typedef struct ...@@ -44,8 +44,6 @@ typedef struct
void (*pf_pace)(void*); void (*pf_pace)(void*);
void (*pf_request_seek)(void*, mtime_t pos);
void (*pf_set_pause_state)(void*, bool paused); void (*pf_set_pause_state)(void*, bool paused);
void (*pf_set_meta)(void*, vlc_meta_t *p_meta); void (*pf_set_meta)(void*, vlc_meta_t *p_meta);
......
...@@ -47,8 +47,6 @@ ...@@ -47,8 +47,6 @@
static int httpd_file_fill_cb( httpd_file_sys_t *data, httpd_file_t *http_file, 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 ); 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 ) static const char* StateToStr( States s )
{ {
switch (s ) switch (s )
...@@ -105,6 +103,7 @@ intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device ...@@ -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_art_url(NULL)
, m_time_playback_started( VLC_TS_INVALID ) , m_time_playback_started( VLC_TS_INVALID )
, m_ts_local_start( VLC_TS_INVALID ) , m_ts_local_start( VLC_TS_INVALID )
, m_ts_seek( VLC_TS_INVALID )
, m_length( VLC_TS_INVALID ) , m_length( VLC_TS_INVALID )
, m_pingRetriesLeft( PING_WAIT_RETRIES ) , 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 ...@@ -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_length = set_length;
m_common.pf_set_initial_time = set_initial_time; m_common.pf_set_initial_time = set_initial_time;
m_common.pf_pace = pace; 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_pause_state = set_pause_state;
m_common.pf_set_meta = set_meta; m_common.pf_set_meta = set_meta;
...@@ -469,16 +467,16 @@ void intf_sys_t::mainLoop() ...@@ -469,16 +467,16 @@ void intf_sys_t::mainLoop()
break; break;
case Seek: case Seek:
{ {
if( !isStatePlaying() || m_mediaSessionId == 0 ) if( !isStatePlaying() || m_mediaSessionId == 0 || m_ts_seek == VLC_TS_INVALID )
break; break;
char current_time[32]; char current_time[32];
mtime_t seek_request_time = mdate() + SEEK_FORWARD_OFFSET;
if( snprintf( current_time, sizeof(current_time), "%.3f", 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" ); msg_Err( m_module, "snprintf() truncated string for mediaSessionId" );
current_time[sizeof(current_time) - 1] = '\0'; 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 */ /* send a fake time to seek to, to make sure the device flushes its buffers */
m_communication.msgPlayerSeek( m_appTransportId, m_mediaSessionId, current_time ); m_communication.msgPlayerSeek( m_appTransportId, m_mediaSessionId, current_time );
setState( Seeking ); setState( Seeking );
...@@ -891,6 +889,7 @@ void intf_sys_t::requestPlayerStop() ...@@ -891,6 +889,7 @@ void intf_sys_t::requestPlayerStop()
vlc_mutex_locker locker(&m_lock); vlc_mutex_locker locker(&m_lock);
m_request_load = false; m_request_load = false;
m_ts_seek = VLC_TS_INVALID;
if( !isStatePlaying() ) if( !isStatePlaying() )
return; return;
...@@ -909,11 +908,17 @@ void intf_sys_t::requestPlayerSeek(mtime_t pos) ...@@ -909,11 +908,17 @@ void intf_sys_t::requestPlayerSeek(mtime_t pos)
vlc_mutex_locker locker(&m_lock); vlc_mutex_locker locker(&m_lock);
if( !isStatePlaying() || m_mediaSessionId == 0 ) if( !isStatePlaying() || m_mediaSessionId == 0 )
return; return;
if ( pos != VLC_TS_INVALID ) m_ts_seek = pos;
m_ts_local_start = pos;
queueMessage( Seek ); 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) void intf_sys_t::setPauseState(bool paused)
{ {
msg_Dbg( m_module, "%s state", paused ? "paused" : "playing" ); msg_Dbg( m_module, "%s state", paused ? "paused" : "playing" );
...@@ -991,6 +996,9 @@ void intf_sys_t::setState( States state ) ...@@ -991,6 +996,9 @@ void intf_sys_t::setState( States state )
#ifndef NDEBUG #ifndef NDEBUG
msg_Dbg( m_module, "Switching from state %s to %s", StateToStr( m_state ), StateToStr( state ) ); msg_Dbg( m_module, "Switching from state %s to %s", StateToStr( m_state ), StateToStr( state ) );
#endif #endif
if (state == Seeking)
if (m_on_seek_done != NULL)
m_on_seek_done(m_on_seek_done_data);
m_state = state; m_state = state;
switch( m_state ) switch( m_state )
...@@ -1039,12 +1047,6 @@ void intf_sys_t::pace(void *pt) ...@@ -1039,12 +1047,6 @@ void intf_sys_t::pace(void *pt)
p_this->pace(); p_this->pace();
} }
void intf_sys_t::request_seek(void *pt, mtime_t pos)
{
intf_sys_t *p_this = static_cast<intf_sys_t*>(pt);
p_this->requestPlayerSeek(pos);
}
void intf_sys_t::set_pause_state(void *pt, bool paused) void intf_sys_t::set_pause_state(void *pt, bool paused)
{ {
intf_sys_t *p_this = static_cast<intf_sys_t*>(pt); intf_sys_t *p_this = static_cast<intf_sys_t*>(pt);
......
...@@ -151,24 +151,6 @@ struct demux_sys_t ...@@ -151,24 +151,6 @@ struct demux_sys_t
this->canSeek = canSeek; 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 ) void setLength( mtime_t length )
{ {
this->i_length = length; this->i_length = length;
...@@ -236,45 +218,13 @@ struct demux_sys_t ...@@ -236,45 +218,13 @@ struct demux_sys_t
case DEMUX_SET_POSITION: case DEMUX_SET_POSITION:
{ {
va_list ap; m_startTime = VLC_TS_INVALID;
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;
}
break; break;
} }
case DEMUX_SET_TIME: case DEMUX_SET_TIME:
{ {
va_list ap; m_startTime = VLC_TS_INVALID;
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;
}
break; break;
} }
case DEMUX_SET_PAUSE_STATE: case DEMUX_SET_PAUSE_STATE:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment