[vlc-commits] chromecast: use our own "access out" module

Thomas Guillem git at videolan.org
Wed Jan 31 16:25:47 CET 2018


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Mon Jan 29 11:19:51 2018 +0100| [e2bf65e51b82edb48931e61155f5839f1deaa3de] | committer: Thomas Guillem

chromecast: use our own "access out" module

In order to allow finer controls and host several files (like artworks) on the
same server.

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

 modules/stream_out/chromecast/cast.cpp | 244 +++++++++++++++++++++++++++++++--
 1 file changed, 232 insertions(+), 12 deletions(-)

diff --git a/modules/stream_out/chromecast/cast.cpp b/modules/stream_out/chromecast/cast.cpp
index d1148683b2..4fedeb652e 100644
--- a/modules/stream_out/chromecast/cast.cpp
+++ b/modules/stream_out/chromecast/cast.cpp
@@ -36,16 +36,24 @@
 #include <vlc_sout.h>
 #include <vlc_block.h>
 #include <vlc_modules.h>
+#include <vlc_httpd.h>
 
 #include <cassert>
 
 struct sout_stream_sys_t
 {
-    sout_stream_sys_t(intf_sys_t * const intf, bool has_video, int port,
+    sout_stream_sys_t(httpd_host_t *httpd_host, httpd_url_t *httpd_url, vlc_fifo_t *httpd_url_fifo,
+                      intf_sys_t * const intf, bool has_video, int port,
                       const char *psz_default_muxer, const char *psz_default_mime)
-        : p_out(NULL)
+        : httpd_host(httpd_host)
+        , httpd_url(httpd_url)
+        , httpd_url_fifo(httpd_url_fifo)
+        , httpd_url_header(NULL)
+        , httpd_url_eof(true)
+        , p_out(NULL)
         , default_muxer(psz_default_muxer)
         , default_mime(psz_default_mime)
+        , mime(psz_default_mime)
         , p_intf(intf)
         , b_supports_video(has_video)
         , i_port(port)
@@ -63,6 +71,10 @@ struct sout_stream_sys_t
     {
         sout_StreamChainDelete(p_out, NULL);
         delete p_intf;
+        clearAccessOut();
+        httpd_UrlDelete(httpd_url);
+        httpd_HostDelete(httpd_host);
+        block_FifoRelease(httpd_url_fifo);
     }
 
     bool canDecodeVideo( vlc_fourcc_t i_codec ) const;
@@ -71,6 +83,15 @@ struct sout_stream_sys_t
     bool startSoutChain(sout_stream_t* p_stream,
                         const std::vector<sout_stream_id_sys_t*> &new_streams);
     void stopSoutChain(sout_stream_t* p_stream);
+    void clearAccessOutUnlocked();
+    void clearAccessOut();
+
+    httpd_host_t      *httpd_host;
+    httpd_url_t       *httpd_url;
+    vlc_fifo_t        *httpd_url_fifo;
+    block_t           *httpd_url_header;
+    bool               httpd_url_eof;
+    std::string        httpd_url_mime;
 
     sout_stream_t     *p_out;
     std::string        sout;
@@ -110,6 +131,8 @@ 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 int AccessOpen(vlc_object_t *);
+static void AccessClose(vlc_object_t *);
 
 static const char *const ppsz_sout_options[] = {
     "ip", "port",  "http-port", "mux", "mime", "video", NULL
@@ -167,6 +190,8 @@ static const char *const conversion_quality_list_text[] = {
 #define PORT_TEXT N_("Chromecast port")
 #define PORT_LONGTEXT N_("The port used to talk to the Chromecast.")
 
+#define HTTPD_BUFFER_MAX INT64_C(32 * 1024 * 1024) /* 32 MB */
+
 vlc_module_begin ()
 
     set_shortname(N_("Chromecast"))
@@ -197,6 +222,11 @@ vlc_module_begin ()
         add_shortcut("chromecast-proxy")
         set_capability("sout stream", 0)
         set_callbacks(ProxyOpen, NULL)
+    add_submodule()
+        set_subcategory(SUBCAT_SOUT_ACO)
+        add_shortcut("chromecast-http")
+        set_capability("sout access", 0)
+        set_callbacks(AccessOpen, AccessClose)
 vlc_module_end ()
 
 
@@ -270,6 +300,171 @@ static int ProxyOpen(vlc_object_t *p_this)
     return VLC_SUCCESS;
 }
 
+static int httpd_url_cb(httpd_callback_sys_t *data, httpd_client_t *cl,
+                        httpd_message_t *answer, const httpd_message_t *query)
+{
+    sout_stream_sys_t *p_sys = (sout_stream_sys_t *) data;
+
+    if (!answer || !query || !cl)
+        return VLC_SUCCESS;
+
+    vlc_fifo_Lock(p_sys->httpd_url_fifo);
+
+    block_t *p_block = NULL;
+    while ((p_block = vlc_fifo_DequeueUnlocked(p_sys->httpd_url_fifo)) == NULL
+       && !p_sys->httpd_url_eof)
+        vlc_fifo_Wait(p_sys->httpd_url_fifo);
+
+    /* Handle block headers */
+    if (p_block)
+    {
+        if (p_block->i_flags & BLOCK_FLAG_HEADER)
+        {
+            if (p_sys->httpd_url_header)
+                block_Release(p_sys->httpd_url_header);
+            p_sys->httpd_url_header = p_block;
+        }
+        if (answer->i_body_offset == 0)
+        {
+            if (p_sys->httpd_url_header != NULL && p_block != p_sys->httpd_url_header)
+            {
+                /* Using header block. Re-insert current block into fifo */
+                block_t *p_fifo = vlc_fifo_DequeueAllUnlocked(p_sys->httpd_url_fifo);
+                vlc_fifo_QueueUnlocked(p_sys->httpd_url_fifo, p_block);
+                vlc_fifo_QueueUnlocked(p_sys->httpd_url_fifo, p_fifo);
+                p_block = p_sys->httpd_url_header;
+            }
+        }
+    }
+    vlc_fifo_Unlock(p_sys->httpd_url_fifo);
+
+    answer->i_proto  = HTTPD_PROTO_HTTP;
+    answer->i_version= 0;
+    answer->i_type   = HTTPD_MSG_ANSWER;
+    answer->i_status = 200;
+
+    bool b_close = false;
+    if (p_block)
+    {
+        if (answer->i_body_offset == 0)
+        {
+            httpd_MsgAdd(answer, "Content-type", "%s", p_sys->httpd_url_mime.c_str());
+            httpd_MsgAdd(answer, "Cache-Control", "no-cache");
+            b_close = true;
+        }
+        answer->p_body = (uint8_t *) malloc(p_block->i_buffer);
+        if (answer->p_body)
+        {
+            answer->i_body = p_block->i_buffer;
+            answer->i_body_offset += answer->i_body ;
+            memcpy(answer->p_body, p_block->p_buffer, p_block->i_buffer);
+        }
+        else
+            b_close = true;
+
+        if (p_block != p_sys->httpd_url_header)
+            block_Release(p_block);
+    }
+    else
+        b_close = true;
+
+    if (b_close)
+        httpd_MsgAdd(answer, "Connection", "close");
+
+    return VLC_SUCCESS;
+}
+
+static ssize_t AccessWrite(sout_access_out_t *p_access, block_t *p_block)
+{
+    sout_stream_sys_t *p_sys = (sout_stream_sys_t *) p_access->p_sys;
+    size_t i_len = p_block->i_buffer;
+
+    vlc_fifo_Lock(p_sys->httpd_url_fifo);
+
+    while (vlc_fifo_GetBytes(p_sys->httpd_url_fifo) >= HTTPD_BUFFER_MAX)
+    {
+        block_t *p_drop = vlc_fifo_DequeueUnlocked(p_sys->httpd_url_fifo);
+        msg_Warn(p_access, "httpd buffer full: dropping %zuB", p_drop->i_buffer);
+        block_Release(p_drop);
+    }
+    vlc_fifo_QueueUnlocked(p_sys->httpd_url_fifo, p_block);
+
+    vlc_fifo_Unlock(p_sys->httpd_url_fifo);
+    vlc_fifo_Signal(p_sys->httpd_url_fifo);
+
+    return i_len;
+}
+
+static int AccessControl(sout_access_out_t *p_access, int i_query, va_list args)
+{
+    (void) p_access;
+
+    switch (i_query)
+    {
+        case ACCESS_OUT_CONTROLS_PACE:
+            *va_arg(args, bool *) = false;
+            break;
+        default:
+            return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
+}
+
+static int AccessOpen(vlc_object_t *p_this)
+{
+    sout_access_out_t *p_access = (sout_access_out_t*)p_this;
+
+    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)
+        var_InheritAddress(p_access, SOUT_CFG_PREFIX "sys");
+    if (p_sys == NULL)
+        return VLC_EGENERIC;
+
+    assert(p_sys->httpd_host && p_sys->httpd_url && p_sys->httpd_url_fifo);
+
+    vlc_fifo_Lock(p_sys->httpd_url_fifo);
+    p_sys->clearAccessOutUnlocked();
+    p_sys->httpd_url_eof = false;
+    p_sys->httpd_url_mime = p_sys->mime;
+    vlc_fifo_Unlock(p_sys->httpd_url_fifo);
+    vlc_fifo_Signal(p_sys->httpd_url_fifo);
+
+    p_access->pf_write       = AccessWrite;
+    p_access->pf_control     = AccessControl;
+    p_access->p_sys          = (sout_access_out_sys_t *)p_sys;
+
+    return VLC_SUCCESS;
+}
+
+static void AccessClose(vlc_object_t *p_this)
+{
+    sout_access_out_t *p_access = (sout_access_out_t*)p_this;
+    sout_stream_sys_t *p_sys = (sout_stream_sys_t *) p_access->p_sys;
+
+    vlc_fifo_Lock(p_sys->httpd_url_fifo);
+    p_sys->httpd_url_eof = true;
+    vlc_fifo_Unlock(p_sys->httpd_url_fifo);
+    vlc_fifo_Signal(p_sys->httpd_url_fifo);
+}
+
+void sout_stream_sys_t::clearAccessOutUnlocked()
+{
+    block_ChainRelease(vlc_fifo_DequeueAllUnlocked(httpd_url_fifo));
+    if (httpd_url_header)
+    {
+        block_Release(httpd_url_header);
+        httpd_url_header = NULL;
+    }
+    httpd_url_eof = true;
+}
+
+void sout_stream_sys_t::clearAccessOut()
+{
+    vlc_fifo_Lock(httpd_url_fifo);
+    clearAccessOutUnlocked();
+    vlc_fifo_Unlock(httpd_url_fifo);
+    vlc_fifo_Signal(httpd_url_fifo);
+}
+
 /*****************************************************************************
  * Sout callbacks
  *****************************************************************************/
@@ -334,8 +529,9 @@ static void DelInternal(sout_stream_t *p_stream, sout_stream_id_sys_t *id,
 
     if ( p_sys->out_streams.empty() )
     {
-        p_sys->p_intf->requestPlayerStop();
         p_sys->stopSoutChain(p_stream);
+        p_sys->p_intf->requestPlayerStop();
+        p_sys->clearAccessOut();
         p_sys->sout = "";
         p_sys->transcode_attempt_idx = 0;
     }
@@ -644,9 +840,8 @@ bool sout_stream_sys_t::UpdateOutput( sout_stream_t *p_stream )
         mime = default_mime;
 
     ssout << "chromecast-proxy:"
-          << "http{dst=:" << i_port << "/stream"
-          << ",mux=" << default_muxer
-          << ",access=http{mime=" << mime << "}}";
+          << "http{mux=" << default_muxer
+          << ",access=chromecast-http";
 
     sout = ssout.str();
 
@@ -767,6 +962,9 @@ static int Open(vlc_object_t *p_this)
     char *psz_mux = NULL;
     char *psz_var_mime = NULL;
     sout_stream_t *p_sout = NULL;
+    httpd_host_t *httpd_host = NULL;
+    httpd_url_t *httpd_url = NULL;
+    vlc_fifo_t *httpd_url_fifo = NULL;
     bool b_supports_video = true;
     int i_local_server_port;
     int i_device_port;
@@ -788,6 +986,14 @@ static int Open(vlc_object_t *p_this)
     i_device_port = var_InheritInteger(p_stream, SOUT_CFG_PREFIX "port");
     i_local_server_port = var_InheritInteger(p_stream, SOUT_CFG_PREFIX "http-port");
 
+    var_Create(p_stream, "http-port", VLC_VAR_INTEGER);
+    var_SetInteger(p_stream, "http-port", i_local_server_port);
+    var_Create(p_stream, "http-host", VLC_VAR_STRING);
+    var_SetString(p_stream, "http-host", "");
+    httpd_host = vlc_http_HostNew(VLC_OBJECT(p_stream));
+    if (httpd_host == NULL)
+        goto error;
+
     try
     {
         p_intf = new intf_sys_t( p_this, i_local_server_port, psz_ip, i_device_port, p_interrupt );
@@ -815,10 +1021,7 @@ static int Open(vlc_object_t *p_this)
         goto error;
 
     /* check if we can open the proper sout */
-    ss << "http{dst=:" << i_local_server_port << "/stream"
-       << ",mux=" << psz_mux
-       << ",access=http{mime=" << psz_var_mime << "}}";
-
+    ss << "http{mux=" << psz_mux << "}";
     p_sout = sout_StreamChainNew( p_stream->p_sout, ss.str().c_str(), NULL, NULL);
     if (p_sout == NULL) {
         msg_Dbg(p_stream, "could not create sout chain:%s", ss.str().c_str());
@@ -826,13 +1029,24 @@ static int Open(vlc_object_t *p_this)
     }
     sout_StreamChainDelete( p_sout, NULL );
 
+    httpd_url = httpd_UrlNew(httpd_host, "/stream", NULL, NULL);
+    if (httpd_url == NULL)
+        goto error;
+
+    httpd_url_fifo = block_FifoNew();
+    if (!httpd_url_fifo)
+        goto error;
+
     b_supports_video = var_GetBool(p_stream, SOUT_CFG_PREFIX "video");
 
-    p_sys = new(std::nothrow) sout_stream_sys_t( p_intf, b_supports_video, i_local_server_port,
-                                                 psz_mux, psz_var_mime );
+    p_sys = new(std::nothrow) sout_stream_sys_t( httpd_host, httpd_url, httpd_url_fifo, p_intf, b_supports_video,
+                                                 i_local_server_port, psz_mux, psz_var_mime );
     if (unlikely(p_sys == NULL))
         goto error;
 
+    httpd_UrlCatch(httpd_url, HTTPD_MSG_GET, httpd_url_cb,
+                   (httpd_callback_sys_t*)p_sys);
+
     /* 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 );
@@ -857,6 +1071,12 @@ error:
     if (p_interrupt)
         vlc_interrupt_destroy(p_interrupt);
     delete p_intf;
+    if (httpd_url)
+        httpd_UrlDelete(httpd_url);
+    if (httpd_host)
+        httpd_HostDelete(httpd_host);
+    if (httpd_url_fifo)
+        block_FifoRelease(httpd_url_fifo);
     free(psz_ip);
     free(psz_mux);
     free(psz_var_mime);



More information about the vlc-commits mailing list