From 5fb95aaf5ea1887e670ee0faf33d71065035f938 Mon Sep 17 00:00:00 2001 From: Thomas Guillem Date: Thu, 25 Jan 2018 18:01:31 +0100 Subject: [PATCH] chromecast: add a stream out proxy This new submodule wait for all tracks to be added into the last stream out (the http one) before running a chromecast session. This fixes chromecast timeout errors when the session was started during the middle of a playback and when the http sout was still empty (because no video IFrames were available for example). This also fixes the "You can try increasing sout-mux-caching value" error (when the timeout came from VLC and not the CC). --- modules/stream_out/chromecast/cast.cpp | 101 ++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/modules/stream_out/chromecast/cast.cpp b/modules/stream_out/chromecast/cast.cpp index a017d98b92..182e0ee600 100644 --- a/modules/stream_out/chromecast/cast.cpp +++ b/modules/stream_out/chromecast/cast.cpp @@ -71,6 +71,7 @@ struct sout_stream_sys_t std::string sout; const std::string default_muxer; const std::string default_mime; + std::string mime; intf_sys_t * const p_intf; const bool b_supports_video; @@ -79,8 +80,10 @@ struct sout_stream_sys_t sout_stream_id_sys_t *GetSubId( sout_stream_t*, sout_stream_id_sys_t* ); bool es_changed; + bool cc_has_input; std::vector streams; std::vector out_streams; + unsigned int out_streams_added; unsigned int transcode_attempt_idx; States previous_state; @@ -100,6 +103,7 @@ static const char DEFAULT_MUXER[] = "avformat{mux=matroska,options={live=1}}"; *****************************************************************************/ static int Open(vlc_object_t *); static void Close(vlc_object_t *); +static int ProxyOpen(vlc_object_t *); static const char *const ppsz_sout_options[] = { "ip", "port", "http-port", "mux", "mime", "video", NULL @@ -182,6 +186,11 @@ vlc_module_begin () CONVERSION_QUALITY_TEXT, CONVERSION_QUALITY_LONGTEXT, false ); change_integer_list(conversion_quality_list, conversion_quality_list_text) + add_submodule() + /* sout proxy that start the cc input when all streams are loaded */ + add_shortcut("chromecast-proxy") + set_capability("sout stream", 0) + set_callbacks(ProxyOpen, NULL) vlc_module_end () @@ -191,6 +200,72 @@ struct sout_stream_id_sys_t sout_stream_id_sys_t *p_sub_id; }; +static sout_stream_id_sys_t *ProxyAdd(sout_stream_t *p_stream, const es_format_t *p_fmt) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + sout_stream_id_sys_t *id = sout_StreamIdAdd(p_stream->p_next, p_fmt); + if (id) + p_sys->out_streams_added++; + return id; +} + +static void ProxyDel(sout_stream_t *p_stream, sout_stream_id_sys_t *id) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + p_sys->out_streams_added--; + return sout_StreamIdDel(p_stream->p_next, id); +} + +static int ProxySend(sout_stream_t *p_stream, sout_stream_id_sys_t *id, + block_t *p_buffer) +{ + sout_stream_sys_t *p_sys = p_stream->p_sys; + if (p_sys->cc_has_input || p_sys->out_streams_added >= p_sys->out_streams.size()) + { + int ret = sout_StreamIdSend(p_stream->p_next, id, p_buffer); + if (ret == VLC_SUCCESS && !p_sys->cc_has_input) + { + /* Start the chromecast only when all streams are added into the + * last sout (the http one) */ + p_sys->p_intf->setHasInput(p_sys->mime); + p_sys->cc_has_input = true; + } + return ret; + } + else + { + block_Release(p_buffer); + return VLC_SUCCESS; + } +} + +static void ProxyFlush(sout_stream_t *p_stream, sout_stream_id_sys_t *id) +{ + return sout_StreamFlush(p_stream->p_next, id); +} + +static int ProxyControl(sout_stream_t *p_stream, int i_query, va_list args) +{ + if (!p_stream->p_next->pf_control) + return VLC_EGENERIC; + return p_stream->p_next->pf_control(p_stream->p_next, i_query, args); +} + +static int ProxyOpen(vlc_object_t *p_this) +{ + sout_stream_t *p_stream = reinterpret_cast(p_this); + p_stream->p_sys = (sout_stream_sys_t *) var_InheritAddress(p_this, SOUT_CFG_PREFIX "sys"); + if (p_stream->p_sys == NULL || p_stream->p_next == NULL) + return VLC_EGENERIC; + + p_stream->pf_add = ProxyAdd; + p_stream->pf_del = ProxyDel; + p_stream->pf_send = ProxySend; + p_stream->pf_flush = ProxyFlush; + p_stream->pf_control = ProxyControl; + return VLC_SUCCESS; +} + /***************************************************************************** * Sout callbacks *****************************************************************************/ @@ -322,6 +397,9 @@ bool sout_stream_sys_t::startSoutChain( sout_stream_t *p_stream ) } msg_Dbg( p_stream, "Creating chain %s", sout.c_str() ); + cc_has_input = false; + out_streams_added = 0; + p_out = sout_StreamChainNew( p_stream->p_sout, sout.c_str(), NULL, NULL); if (p_out == NULL) { msg_Dbg(p_stream, "could not create sout chain:%s", sout.c_str()); @@ -508,7 +586,6 @@ bool sout_stream_sys_t::UpdateOutput( sout_stream_t *p_stream ) } ssout << "}:"; } - std::string mime; if ( !p_original_video && default_muxer == DEFAULT_MUXER ) mime = "audio/x-matroska"; else if ( i_codec_audio == VLC_CODEC_VORBIS && @@ -518,18 +595,14 @@ bool sout_stream_sys_t::UpdateOutput( sout_stream_t *p_stream ) else mime = default_mime; - ssout << "http{dst=:" << i_port << "/stream" + ssout << "chromecast-proxy:" + << "http{dst=:" << i_port << "/stream" << ",mux=" << default_muxer << ",access=http{mime=" << mime << "}}"; sout = ssout.str(); - if ( startSoutChain( p_stream ) ) - { - /* tell the chromecast to load the content */ - p_intf->setHasInput( mime ); - } - else + if ( !startSoutChain( p_stream ) ) { p_intf->requestPlayerStop(); @@ -598,7 +671,11 @@ static int Send(sout_stream_t *p_stream, sout_stream_id_sys_t *id, int ret = sout_StreamIdSend(p_sys->p_out, next_id, p_buffer); if (ret != VLC_SUCCESS) + { + bool was_es_changed = p_sys->es_changed; Del(p_stream, id); + p_sys->es_changed = was_es_changed; + } return ret; } @@ -712,6 +789,13 @@ static int Open(vlc_object_t *p_this) if (unlikely(p_sys == NULL)) goto error; + /* 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 ); + + var_Create( p_stream->p_sout, SOUT_CFG_PREFIX "sys", VLC_VAR_ADDRESS ); + var_SetAddress( p_stream->p_sout, SOUT_CFG_PREFIX "sys", p_sys ); + // Set the sout callbacks. p_stream->pf_add = Add; p_stream->pf_del = Del; @@ -743,6 +827,7 @@ static void Close(vlc_object_t *p_this) { sout_stream_t *p_stream = reinterpret_cast(p_this); + var_Destroy( p_stream->p_sout, SOUT_CFG_PREFIX "sys" ); delete p_stream->p_sys; } -- 2.11.4.GIT