[vlc-commits] chromecast: add a stream out proxy

Thomas Guillem git at videolan.org
Thu Jan 25 18:33:29 CET 2018


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Thu Jan 25 18:01:31 2018 +0100| [5fb95aaf5ea1887e670ee0faf33d71065035f938] | committer: Thomas Guillem

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).

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

 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<sout_stream_id_sys_t*> streams;
     std::vector<sout_stream_id_sys_t*> 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<sout_stream_t*>(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<sout_stream_t*>(p_this);
 
+    var_Destroy( p_stream->p_sout, SOUT_CFG_PREFIX "sys" );
     delete p_stream->p_sys;
 }
 



More information about the vlc-commits mailing list