[vlc-commits] chromecast: serve local artworks

Thomas Guillem git at videolan.org
Thu Feb 1 11:26:32 CET 2018


vlc/vlc-3.0 | branch: master | Thomas Guillem <thomas at gllm.fr> | Tue Jan 30 17:30:03 2018 +0100| [cbbaeff4705792797f4d2eebe2af35b8b919594f] | committer: Thomas Guillem

chromecast: serve local artworks

(cherry picked from commit ea00c6188b9d2123738b2490682ad841c0d530dd)
Signed-off-by: Thomas Guillem <thomas at gllm.fr>

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

 modules/stream_out/chromecast/cast.cpp             |   3 +-
 modules/stream_out/chromecast/chromecast.h         |  17 ++-
 .../chromecast/chromecast_communication.cpp        |   2 +-
 modules/stream_out/chromecast/chromecast_ctrl.cpp  | 126 ++++++++++++++++++++-
 4 files changed, 141 insertions(+), 7 deletions(-)

diff --git a/modules/stream_out/chromecast/cast.cpp b/modules/stream_out/chromecast/cast.cpp
index ffb7cc9931..e2c0093b59 100644
--- a/modules/stream_out/chromecast/cast.cpp
+++ b/modules/stream_out/chromecast/cast.cpp
@@ -1056,7 +1056,8 @@ static int Open(vlc_object_t *p_this)
 
     try
     {
-        p_intf = new intf_sys_t( p_this, i_local_server_port, psz_ip, i_device_port, p_interrupt );
+        p_intf = new intf_sys_t( p_this, i_local_server_port, psz_ip, i_device_port,
+                                 p_interrupt, httpd_host );
     }
     catch (const std::runtime_error& err )
     {
diff --git a/modules/stream_out/chromecast/chromecast.h b/modules/stream_out/chromecast/chromecast.h
index a1925c9ea5..5f6bccd9ac 100644
--- a/modules/stream_out/chromecast/chromecast.h
+++ b/modules/stream_out/chromecast/chromecast.h
@@ -33,6 +33,7 @@
 #include <vlc_plugin.h>
 #include <vlc_tls.h>
 #include <vlc_interrupt.h>
+#include <vlc_httpd.h>
 
 #include <atomic>
 #include <sstream>
@@ -120,6 +121,11 @@ public:
     void msgPlayerSetVolume( const std::string& destinationId, const std::string& mediaSessionId,
                              float volume, bool mute);
     ssize_t receive( uint8_t *p_data, size_t i_size, int i_timeout, bool *pb_timeout );
+
+    const std::string getServerIp()
+    {
+        return m_serverIp;
+    }
 private:
     int sendMessage(const castchannel::CastMessage &msg);
 
@@ -150,7 +156,8 @@ struct intf_sys_t
         Stop,
         Seek
     };
-    intf_sys_t(vlc_object_t * const p_this, int local_port, std::string device_addr, int device_port, vlc_interrupt_t *);
+    intf_sys_t(vlc_object_t * const p_this, int local_port, std::string device_addr,
+               int device_port, vlc_interrupt_t *, httpd_host_t *);
     ~intf_sys_t();
 
     bool isFinishedPlaying();
@@ -161,6 +168,7 @@ struct intf_sys_t
     void requestPlayerStop();
     States state() const;
 
+    int httpd_file_fill( uint8_t *psz_request, uint8_t **pp_data, int *pi_data );
 private:
     bool handleMessages();
 
@@ -207,6 +215,7 @@ private:
 
     static void set_meta(void*, vlc_meta_t *p_meta);
 
+    void prepareHttpArtwork();
 
 private:
     vlc_object_t  * const m_module;
@@ -229,6 +238,12 @@ private:
 
     vlc_interrupt_t *m_ctl_thread_interrupt;
 
+    httpd_host_t     *m_httpd_host;
+    httpd_file_t     *m_httpd_file;
+    std::string       m_art_http_ip;
+    char             *m_art_url;
+    stream_t         *m_art_stream;
+
     /* local date when playback started/resumed, used by monotone clock */
     mtime_t           m_time_playback_started;
     /* local playback time of the input when playback started/resumed */
diff --git a/modules/stream_out/chromecast/chromecast_communication.cpp b/modules/stream_out/chromecast/chromecast_communication.cpp
index 2da8bc346d..5ae2fd4627 100644
--- a/modules/stream_out/chromecast/chromecast_communication.cpp
+++ b/modules/stream_out/chromecast/chromecast_communication.cpp
@@ -290,7 +290,7 @@ std::string ChromecastCommunication::GetMedia( unsigned int i_port,
             }
 
             if ( psz_artwork && !strncmp( psz_artwork, "http", 4 ) )
-                ss << ",\"images\":[\"" << psz_artwork << "\"]";
+                ss << ",\"images\":[{\"url\":\"" << psz_artwork << "\"}]";
 
             ss << "},";
         }
diff --git a/modules/stream_out/chromecast/chromecast_ctrl.cpp b/modules/stream_out/chromecast/chromecast_ctrl.cpp
index 887103c816..512cd42ab1 100644
--- a/modules/stream_out/chromecast/chromecast_ctrl.cpp
+++ b/modules/stream_out/chromecast/chromecast_ctrl.cpp
@@ -36,6 +36,8 @@
 #include <cassert>
 #include <cerrno>
 
+#include <vlc_stream.h>
+
 #include "../../misc/webservices/json.h"
 
 /* deadline regarding pings sent from receiver */
@@ -81,7 +83,8 @@ static const char* StateToStr( States s )
 /*****************************************************************************
  * intf_sys_t: class definition
  *****************************************************************************/
-intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device_addr, int device_port, vlc_interrupt_t *p_interrupt)
+intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device_addr,
+                       int device_port, vlc_interrupt_t *p_interrupt, httpd_host_t *httpd_host)
  : m_module(p_this)
  , m_streaming_port(port)
  , m_communication( p_this, device_addr.c_str(), device_port )
@@ -89,6 +92,10 @@ intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device
  , m_eof( false )
  , m_meta( NULL )
  , m_ctl_thread_interrupt(p_interrupt)
+ , m_httpd_host(httpd_host)
+ , m_httpd_file(NULL)
+ , m_art_url(NULL)
+ , m_art_stream(NULL)
  , m_time_playback_started( VLC_TS_INVALID )
  , m_ts_local_start( VLC_TS_INVALID )
  , m_length( VLC_TS_INVALID )
@@ -97,6 +104,10 @@ intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device
     vlc_mutex_init(&m_lock);
     vlc_cond_init( &m_stateChangedCond );
 
+    std::stringstream ss;
+    ss << "http://" << m_communication.getServerIp() << ":" << port;
+    m_art_http_ip = ss.str();
+
     m_common.p_opaque = this;
     m_common.pf_get_position     = get_position;
     m_common.pf_get_time         = get_time;
@@ -115,9 +126,7 @@ intf_sys_t::intf_sys_t(vlc_object_t * const p_this, int port, std::string device
     // Start the Chromecast event thread.
     if (vlc_clone(&m_chromecastThread, ChromecastThread, this,
                   VLC_THREAD_PRIORITY_LOW))
-    {
-        msg_Err( m_module, "Could not start the Chromecast talking thread");
-    }
+        throw std::runtime_error( "error creating cc thread" );
 }
 
 intf_sys_t::~intf_sys_t()
@@ -151,10 +160,104 @@ intf_sys_t::~intf_sys_t()
 
     vlc_interrupt_destroy( m_ctl_thread_interrupt );
 
+    if (m_meta != NULL)
+        vlc_meta_Delete(m_meta);
+
+    if( m_httpd_file )
+        httpd_FileDelete( m_httpd_file );
+    if( m_art_stream )
+        vlc_stream_Delete( m_art_stream );
+
     vlc_cond_destroy(&m_stateChangedCond);
     vlc_mutex_destroy(&m_lock);
 }
 
+int intf_sys_t::httpd_file_fill( uint8_t *psz_request, uint8_t **pp_data, int *pi_data )
+{
+    (void) psz_request;
+
+    if( vlc_stream_Seek( m_art_stream, 0 ) )
+        return VLC_EGENERIC;
+
+    uint64_t size;
+    if( vlc_stream_GetSize( m_art_stream, &size ) != VLC_SUCCESS
+     || size > INT64_C( 10000000 ) )
+        return VLC_EGENERIC;
+
+    *pp_data = (uint8_t *)malloc( size );
+    if( !*pp_data )
+        return VLC_EGENERIC;
+
+    *pi_data = size;
+    ssize_t read = vlc_stream_Read( m_art_stream, *pp_data, size );
+    if( read < 0 || (size_t)read != size )
+    {
+        free( *pp_data );
+        return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+
+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 )
+{
+    (void) http_file;
+    intf_sys_t *p_sys = static_cast<intf_sys_t*>((void *)data);
+    return p_sys->httpd_file_fill( psz_request, pp_data, pi_data );
+}
+
+void intf_sys_t::prepareHttpArtwork()
+{
+    const char *psz_art = m_meta ? vlc_meta_Get( m_meta, vlc_meta_ArtworkURL ) : NULL;
+    /* Abort if there is no art or if the art is already served */
+    if( !psz_art || strncmp( psz_art, "http", 4) == 0
+     || ( m_art_url && strcmp( psz_art, m_art_url ) == 0 ) )
+        return;
+
+    if( m_httpd_file )
+    {
+        httpd_FileDelete( m_httpd_file );
+        m_httpd_file = NULL;
+    }
+    if( m_art_stream )
+    {
+        vlc_stream_Delete( m_art_stream );
+        m_art_stream = NULL;
+    }
+
+    m_art_stream = vlc_stream_NewURL( m_module, psz_art );
+    if( !m_art_stream )
+        return;
+
+    uint64_t size;
+    if( vlc_stream_GetSize( m_art_stream, &size ) != VLC_SUCCESS
+     || size > INT64_C( 10000000 ) )
+    {
+        msg_Warn( m_module, "art stream is too big or invalid" );
+        vlc_stream_Delete( m_art_stream );
+        return;
+    }
+
+    const char *psz_artmime = "application/octet-stream";
+    char *psz_streammime = stream_MimeType( m_art_stream );
+    if( psz_streammime )
+        psz_artmime = psz_streammime;
+
+    m_httpd_file = httpd_FileNew( m_httpd_host, "/art", psz_artmime, NULL, NULL,
+                                  httpd_file_fill_cb, (httpd_file_sys_t *) this );
+    free( psz_streammime );
+    if( !m_httpd_file )
+    {
+        vlc_stream_Delete( m_art_stream );
+        return;
+    }
+
+    std::stringstream ss;
+    ss << m_art_http_ip << "/art";
+    vlc_meta_Set( m_meta, vlc_meta_ArtworkURL, ss.str().c_str() );
+}
+
 void intf_sys_t::setHasInput( const std::string mime_type )
 {
     vlc_mutex_locker locker(&m_lock);
@@ -172,6 +275,9 @@ void intf_sys_t::setHasInput( const std::string mime_type )
         msg_Warn( m_module, "no Chromecast hook possible");
         return;
     }
+
+    prepareHttpArtwork();
+
     // We should now be in the ready state, and therefor have a valid transportId
     assert( m_appTransportId.empty() == false );
     // we cannot start a new load when the last one is still processing
@@ -650,6 +756,18 @@ bool intf_sys_t::handleMessages()
 void intf_sys_t::requestPlayerStop()
 {
     vlc_mutex_locker locker(&m_lock);
+
+    if( m_httpd_file )
+    {
+        httpd_FileDelete( m_httpd_file );
+        m_httpd_file = NULL;
+    }
+    if( m_art_stream )
+    {
+        vlc_stream_Delete( m_art_stream );
+        m_art_stream = NULL;
+    }
+
     if ( m_mediaSessionId.empty() == true )
         return;
     queueMessage( Stop );



More information about the vlc-commits mailing list