<html dir="ltr"><head></head><body style="text-align:left; direction:ltr;"><div>On Mon, 2018-11-26 at 15:48 +0100, Thomas Guillem wrote:</div><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>Hello Shaleen,</pre><pre>Sorry for the very late review.</pre><pre><br></pre><pre>On Tue, Oct 23, 2018, at 07:51, Shaleen Jain wrote:</pre><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>Add support for casting to a DLNA Media Renderers</pre><pre>which implement the AVTransport service with the</pre><pre>initial support of the default media format.</pre><pre>---</pre><pre> NEWS                                    |   1 +</pre><pre> modules/MODULES_LIST                    |   1 +</pre><pre> modules/services_discovery/Makefile.am  |   5 +-</pre><pre> modules/services_discovery/upnp.cpp     |  54 ++</pre><pre> modules/services_discovery/upnp.hpp     |   1 +</pre><pre> modules/stream_out/dlna/dlna.cpp        | 886 ++++++++++++++++++++++++</pre><pre> modules/stream_out/dlna/dlna.hpp        |  60 ++</pre><pre> modules/stream_out/dlna/dlna_common.hpp |  56 ++</pre><pre> 8 files changed, 1063 insertions(+), 1 deletion(-)</pre><pre> create mode 100644 modules/stream_out/dlna/dlna.cpp</pre><pre> create mode 100644 modules/stream_out/dlna/dlna.hpp</pre><pre> create mode 100644 modules/stream_out/dlna/dlna_common.hpp</pre><pre><br></pre><pre>diff --git a/NEWS b/NEWS</pre><pre>index 3054bb84a7..7fe0c4d39b 100644</pre><pre>--- a/NEWS</pre><pre>+++ b/NEWS</pre><pre>@@ -40,6 +40,7 @@ Video output:</pre><pre> Stream output:</pre><pre>  * New SDI output with improved audio and ancillary support.</pre><pre>    Candidate for deprecation of decklink vout/aout modules.</pre><pre>+ * Support for DLNA/UPNP renderers</pre><pre> </pre><pre> macOS:</pre><pre>  * Remove Growl notification support</pre><pre>diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST</pre><pre>index 79161ae3ed..65815ed22e 100644</pre><pre>--- a/modules/MODULES_LIST</pre><pre>+++ b/modules/MODULES_LIST</pre><pre>@@ -377,6 +377,7 @@ $Id$</pre><pre>  * stream_out_delay: introduce delay in an ES when streaming</pre><pre>  * stream_out_description: helper module for RTSP vod</pre><pre>  * stream_out_display: displays a stream output chain</pre><pre>+ * stream_out_dlna: DLNA streaming output module</pre><pre>  * stream_out_dummy: dummy stream out chain module</pre><pre>  * stream_out_duplicate: duplicates a stream output chain</pre><pre>  * stream_out_es: stream out module outputing ES</pre><pre>diff --git a/modules/services_discovery/Makefile.am b/modules/</pre><pre>services_discovery/Makefile.am</pre><pre>index f63df23b32..1b59cb1e4f 100644</pre><pre>--- a/modules/services_discovery/Makefile.am</pre><pre>+++ b/modules/services_discovery/Makefile.am</pre><pre>@@ -28,7 +28,10 @@ sd_LTLIBRARIES += $(LTLIBmtp)</pre><pre> </pre><pre> libupnp_plugin_la_SOURCES = services_discovery/upnp.cpp </pre><pre>services_discovery/upnp.hpp \</pre><pre>                         services_discovery/upnp-wrapper.hpp \</pre><pre>-                           services_discovery/upnp-wrapper.cpp</pre><pre>+                     services_discovery/upnp-wrapper.cpp \</pre><pre>+                           stream_out/dlna/dlna_common.hpp \</pre><pre>+                       stream_out/dlna/dlna.hpp \</pre><pre>+                      stream_out/dlna/dlna.cpp</pre><pre> libupnp_plugin_la_CXXFLAGS = $(AM_CXXFLAGS) $(UPNP_CFLAGS)</pre><pre> libupnp_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'</pre><pre> libupnp_plugin_la_LIBADD = $(UPNP_LIBS)</pre><pre>diff --git a/modules/services_discovery/upnp.cpp b/modules/</pre><pre>services_discovery/upnp.cpp</pre><pre>index c1c2b947b2..bf025a6393 100644</pre><pre>--- a/modules/services_discovery/upnp.cpp</pre><pre>+++ b/modules/services_discovery/upnp.cpp</pre><pre>@@ -54,6 +54,40 @@ const char* SATIP_SERVER_DEVICE_TYPE = </pre><pre>"urn:ses-com:device:SatIPServer:1";</pre><pre> #define UPNP_SEARCH_TIMEOUT_SECONDS 15</pre><pre> #define SATIP_CHANNEL_LIST N_("SAT>IP channel list")</pre><pre> #define SATIP_CHANNEL_LIST_URL N_("Custom SAT>IP channel list URL")</pre><pre>+</pre><pre>+#define HTTP_PORT         7070</pre><pre>+</pre><pre>+#define HTTP_PORT_TEXT N_("HTTP port")</pre><pre>+#define HTTP_PORT_LONGTEXT N_("This sets the HTTP port of the local </pre><pre>server used to stream the media to the UPnP Renderer.")</pre><pre>+#define HAS_VIDEO_TEXT N_("Video")</pre><pre>+#define HAS_VIDEO_LONGTEXT N_("The UPnP Renderer can receive video.")</pre><pre>+</pre><pre>+#define PERF_TEXT N_( "Performance warning" )</pre><pre>+#define PERF_LONGTEXT N_( "Display a performance warning when </pre><pre>transcoding" )</pre><pre>+#define CONVERSION_QUALITY_TEXT N_( "Conversion quality" )</pre><pre>+#define CONVERSION_QUALITY_LONGTEXT N_( "Change this option to increase </pre><pre>conversion speed or quality." )</pre><pre>+</pre><pre>+#define IP_ADDR_TEXT N_("IP Address")</pre><pre>+#define IP_ADDR_LONGTEXT N_("IP Address of the UPnP Renderer.")</pre><pre>+#define PORT_TEXT N_("UPnP Renderer port")</pre><pre>+#define PORT_LONGTEXT N_("The port used to talk to the UPnP Renderer.")</pre><pre>+#define BASE_URL_TEXT N_("base URL")</pre><pre>+#define BASE_URL_LONGTEXT N_("The base Url relative to which all other </pre><pre>UPnP operations must be called")</pre><pre>+#define URL_TEXT N_("description URL")</pre><pre>+#define URL_LONGTEXT N_("The Url used to get the xml descriptor of the </pre><pre>UPnP Renderer")</pre><pre>+</pre><pre>+#if defined (__ANDROID__) || defined (__arm__) || (defined </pre><pre>(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)</pre><pre>+# define CONVERSION_QUALITY_DEFAULT CONVERSION_QUALITY_LOW</pre><pre>+#else</pre><pre>+# define CONVERSION_QUALITY_DEFAULT CONVERSION_QUALITY_MEDIUM</pre><pre>+#endif</pre><pre>+static const char *const conversion_quality_list_text[] = {</pre><pre>+    N_( "High (high quality and high bandwidth)" ),</pre><pre>+    N_( "Medium (medium quality and medium bandwidth)" ),</pre><pre>+    N_( "Low (low quality and low bandwidth)" ),</pre><pre>+    N_( "Low CPU (low quality but high bandwidth)" ),</pre><pre>+};</pre><pre>+</pre><pre> static const char *const ppsz_satip_channel_lists[] = {</pre><pre>     "Auto", "ASTRA_19_2E", "ASTRA_28_2E", "ASTRA_23_5E", "MasterList", </pre><pre>"ServerList", "CustomList"</pre><pre> };</pre><pre>@@ -147,6 +181,26 @@ vlc_module_begin()</pre><pre> </pre><pre>     VLC_RD_PROBE_SUBMODULE</pre><pre> </pre><pre>+    add_submodule()</pre><pre>+        set_shortname("dlna")</pre><pre>+        set_description(N_("UPnP/DLNA stream output"))</pre><pre>+        set_capability("sout stream", 0)</pre><pre>+        add_shortcut("dlna")</pre><pre>+        set_category(CAT_SOUT)</pre><pre>+        set_subcategory(SUBCAT_SOUT_STREAM)</pre><pre>+        set_callbacks(DLNA::OpenSout, DLNA::CloseSout)</pre><pre>+</pre><pre>+        add_string(SOUT_CFG_PREFIX "ip", NULL, IP_ADDR_TEXT, </pre><pre>IP_ADDR_LONGTEXT, false)</pre><pre>+        add_integer(SOUT_CFG_PREFIX "port", NULL, PORT_TEXT, </pre><pre>PORT_LONGTEXT, false)</pre><pre>+        add_integer(SOUT_CFG_PREFIX "http-port", HTTP_PORT, </pre><pre>HTTP_PORT_TEXT, HTTP_PORT_LONGTEXT, false)</pre><pre>+        add_bool(SOUT_CFG_PREFIX "video", true, HAS_VIDEO_TEXT, </pre><pre>HAS_VIDEO_LONGTEXT, false)</pre><pre>+        add_string(SOUT_CFG_PREFIX "base_url", NULL, BASE_URL_TEXT, </pre><pre>BASE_URL_LONGTEXT, false)</pre><pre>+        add_string(SOUT_CFG_PREFIX "url", NULL, URL_TEXT, URL_LONGTEXT, </pre><pre>false)</pre><pre>+        add_integer(SOUT_CFG_PREFIX "show-perf-warning", 1, PERF_TEXT, </pre><pre>PERF_LONGTEXT, true )</pre><pre>+            change_private()</pre><pre>+        add_integer(SOUT_CFG_PREFIX "conversion-quality", </pre><pre>CONVERSION_QUALITY_DEFAULT,</pre><pre>+                    CONVERSION_QUALITY_TEXT, </pre><pre>CONVERSION_QUALITY_LONGTEXT, false );</pre><pre>+            change_integer_list(conversion_quality_list, </pre><pre>conversion_quality_list_text)</pre><pre> vlc_module_end()</pre></blockquote><pre><br></pre><pre>These options could be merged with  the chromecast.</pre></blockquote><div><br></div><div>Do you mean by having the same prefix as that of the chromecast ones?</div><div><br></div><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre> </pre><pre> /*</pre><pre>diff --git a/modules/services_discovery/upnp.hpp b/modules/</pre><pre>services_discovery/upnp.hpp</pre><pre>index 5a0de1f284..3b2e80b209 100644</pre><pre>--- a/modules/services_discovery/upnp.hpp</pre><pre>+++ b/modules/services_discovery/upnp.hpp</pre><pre>@@ -33,6 +33,7 @@</pre><pre> #endif</pre><pre> </pre><pre> #include "upnp-wrapper.hpp"</pre><pre>+#include "../stream_out/dlna/dlna_common.hpp"</pre><pre> </pre><pre> #include <vlc_url.h></pre><pre> #include <vlc_interrupt.h></pre><pre>diff --git a/modules/stream_out/dlna/dlna.cpp b/modules/stream_out/dlna/</pre><pre>dlna.cpp</pre><pre>new file mode 100644</pre><pre>index 0000000000..e0c266d8e3</pre><pre>--- /dev/null</pre><pre>+++ b/modules/stream_out/dlna/dlna.cpp</pre><pre>@@ -0,0 +1,886 @@</pre><pre>+/</pre><pre>*****************************************************************************</pre><pre>+ * dlna.cpp : DLNA/UPNP (renderer) sout module</pre><pre>+ </pre><pre>*****************************************************************************</pre><pre>+ * Copyright (C) 2004-2018 VLC authors and VideoLAN</pre><pre>+ *</pre><pre>+ * Authors: William Ung <</pre><a href="mailto:william1.ung@epitech.eu"><pre>william1.ung@epitech.eu</pre></a><pre>></pre><pre>+ *          Shaleen Jain <</pre><a href="mailto:shaleen@jain.sh"><pre>shaleen@jain.sh</pre></a><pre>></pre><pre>+ *</pre><pre>+ * This program is free software; you can redistribute it and/or modify </pre><pre>it</pre><pre>+ * under the terms of the GNU Lesser General Public License as </pre><pre>published by</pre><pre>+ * the Free Software Foundation; either version 2.1 of the License, or</pre><pre>+ * (at your option) any later version.</pre><pre>+ *</pre><pre>+ * This program is distributed in the hope that it will be useful,</pre><pre>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</pre><pre>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</pre><pre>+ * GNU Lesser General Public License for more details.</pre><pre>+ *</pre><pre>+ * You should have received a copy of the GNU Lesser General Public </pre><pre>License</pre><pre>+ * along with this program; if not, write to the Free Software </pre><pre>Foundation,</pre><pre>+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.</pre><pre>+ </pre><pre>*****************************************************************************/</pre><pre>+</pre><pre>+#ifdef HAVE_CONFIG_H</pre><pre>+# include "config.h"</pre><pre>+#endif</pre><pre>+</pre><pre>+#include "dlna.hpp"</pre><pre>+</pre><pre>+#include <vector></pre><pre>+#include <string></pre><pre>+#include <sstream></pre><pre>+</pre><pre>+#include <vlc_dialog.h></pre><pre>+#include <vlc_rand.h></pre><pre>+#include <vlc_sout.h></pre><pre>+</pre><pre>+static const char* AV_TRANSPORT_SERVICE_TYPE = </pre><pre>"urn:schemas-upnp-org:service:AVTransport:1";</pre><pre>+static const char* CONNECTION_MANAGER_SERVICE_TYPE = </pre><pre>"urn:schemas-upnp-org:service:ConnectionManager:1";</pre><pre>+</pre><pre>+static const char *const ppsz_sout_options[] = {</pre><pre>+    "ip", "port", "http-port", "video", "base_url", "url", NULL</pre><pre>+};</pre><pre>+</pre><pre>+namespace DLNA</pre><pre>+{</pre><pre>+</pre><pre>+struct sout_stream_id_sys_t</pre><pre>+{</pre><pre>+    es_format_t           fmt;</pre><pre>+    sout_stream_id_sys_t  *p_sub_id;</pre><pre>+};</pre><pre>+</pre><pre>+struct sout_stream_sys_t</pre><pre>+{</pre><pre>+    sout_stream_sys_t(int http_port, bool supports_video)</pre><pre>+        : p_out( NULL )</pre><pre>+        , es_changed( true )</pre><pre>+        , b_supports_video( supports_video )</pre><pre>+        , perf_warning_shown( false )</pre><pre>+        , venc_opt_idx ( -1 )</pre><pre>+        , http_port( http_port )</pre><pre>+    {</pre><pre>+    }</pre><pre>+</pre><pre>+    std::shared_ptr<MediaRenderer> renderer;</pre><pre>+    UpnpInstanceWrapper *p_upnp;</pre><pre>+</pre><pre>+    bool canDecodeAudio( vlc_fourcc_t i_codec ) const;</pre><pre>+    bool canDecodeVideo( vlc_fourcc_t i_codec ) const;</pre><pre>+    bool startSoutChain( sout_stream_t* p_stream,</pre><pre>+                         const std::vector<sout_stream_id_sys_t*> </pre><pre>&new_streams,</pre><pre>+                         const std::string &sout );</pre><pre>+    void stopSoutChain( sout_stream_t* p_stream );</pre><pre>+    sout_stream_id_sys_t *GetSubId( sout_stream_t *p_stream,</pre><pre>+                                    sout_stream_id_sys_t *id,</pre><pre>+                                    bool update = true );</pre><pre>+</pre><pre>+    sout_stream_t                       *p_out;</pre><pre>+    bool                                es_changed;</pre><pre>+    bool                                b_supports_video;</pre><pre>+    bool                                perf_warning_shown;</pre><pre>+    int                                 venc_opt_idx;</pre><pre>+    int                                 http_port;</pre><pre>+    std::vector<sout_stream_id_sys_t*>  streams;</pre><pre>+    std::vector<sout_stream_id_sys_t*>  out_streams;</pre><pre>+</pre><pre>+private:</pre><pre>+    std::string GetVencOption( sout_stream_t *, vlc_fourcc_t *,</pre><pre>+                               const video_format_t *, int );</pre><pre>+    std::string GetAcodecOption( sout_stream_t *, vlc_fourcc_t *, const </pre><pre>audio_format_t *, int );</pre><pre>+    std::string GetVcodecOption( sout_stream_t *, vlc_fourcc_t *, const </pre><pre>video_format_t *, int );</pre><pre>+    int UpdateOutput( sout_stream_t *p_stream );</pre><pre>+</pre><pre>+};</pre><pre>+</pre><pre>+char *getServerIPAddress() {</pre><pre>+    char *ip = NULL;</pre><pre>+#ifdef UPNP_ENABLE_IPV6</pre><pre>+#ifdef _WIN32</pre><pre>+    IP_ADAPTER_UNICAST_ADDRESS *p_best_ip = NULL;</pre><pre>+    wchar_t psz_uri[32];</pre><pre>+    DWORD strSize;</pre><pre>+    IP_ADAPTER_ADDRESSES *p_adapter, *addresses;</pre><pre>+</pre><pre>+    addresses = ListAdapters();</pre><pre>+    if (addresses == NULL)</pre><pre>+        return NULL;</pre><pre>+</pre><pre>+    p_adapter = addresses;</pre><pre>+    while (p_adapter != NULL)</pre><pre>+    {</pre><pre>+        if (isAdapterSuitable(p_adapter, false))</pre><pre>+        {</pre><pre>+            IP_ADAPTER_UNICAST_ADDRESS *p_unicast = p_adapter-</pre><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>FirstUnicastAddress;</pre></blockquote><pre>+            while (p_unicast != NULL)</pre><pre>+            {</pre><pre>+                strSize = sizeof( psz_uri ) / sizeof( wchar_t );</pre><pre>+                if( WSAAddressToString( p_unicast->Address.lpSockaddr,</pre><pre>+                                        p_unicast-</pre><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>Address.iSockaddrLength,</pre></blockquote><pre>+                                        NULL, psz_uri, &strSize ) == </pre><pre>0 )</pre><pre>+                {</pre><pre>+                    if ( p_best_ip == NULL ||</pre><pre>+                         p_best_ip->ValidLifetime > p_unicast-</pre><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>ValidLifetime )</pre></blockquote><pre>+                    {</pre><pre>+                        p_best_ip = p_unicast;</pre><pre>+                    }</pre><pre>+                }</pre><pre>+                p_unicast = p_unicast->Next;</pre><pre>+            }</pre><pre>+        }</pre><pre>+        p_adapter = p_adapter->Next;</pre><pre>+    }</pre><pre>+</pre><pre>+    if (p_best_ip != NULL)</pre><pre>+    {</pre><pre>+        strSize = sizeof( psz_uri ) / sizeof( wchar_t );</pre><pre>+        WSAAddressToString( p_best_ip->Address.lpSockaddr,</pre><pre>+                            p_best_ip->Address.iSockaddrLength,</pre><pre>+                            NULL, psz_uri, &strSize );</pre><pre>+        free(addresses);</pre><pre>+        return FromWide( psz_uri );</pre><pre>+    }</pre><pre>+    free(addresses);</pre><pre>+    return NULL;</pre><pre>+#endif /* _WIN32 */</pre><pre>+#else /* UPNP_ENABLE_IPV6 */</pre><pre>+    ip = getIpv4ForMulticast();</pre><pre>+#endif /* UPNP_ENABLE_IPV6 */</pre><pre>+    if (ip == NULL)</pre><pre>+    {</pre><pre>+        ip = UpnpGetServerIpAddress();</pre><pre>+    }</pre><pre>+    return ip;</pre><pre>+}</pre><pre>+</pre><pre>+bool sout_stream_sys_t::canDecodeAudio(vlc_fourcc_t i_codec) const</pre><pre>+{</pre><pre>+    return i_codec == VLC_CODEC_MP4A;</pre><pre>+}</pre><pre>+</pre><pre>+bool sout_stream_sys_t::canDecodeVideo(vlc_fourcc_t i_codec) const</pre><pre>+{</pre><pre>+    return i_codec == VLC_CODEC_H264;</pre><pre>+}</pre><pre>+</pre><pre>+bool sout_stream_sys_t::startSoutChain(sout_stream_t *p_stream,</pre><pre>+                                       const </pre><pre>std::vector<sout_stream_id_sys_t*> &new_streams,</pre><pre>+                                       const std::string &sout)</pre><pre>+{</pre><pre>+    msg_Dbg( p_stream, "Creating chain %s", sout.c_str() );</pre><pre>+    out_streams = new_streams;</pre><pre>+</pre><pre>+    p_out = sout_StreamChainNew( p_stream->p_sout, sout.c_str(), NULL, </pre><pre>NULL);</pre><pre>+    if (p_out == NULL) {</pre><pre>+        msg_Err(p_stream, "could not create sout chain:%s", </pre><pre>sout.c_str());</pre><pre>+        out_streams.clear();</pre><pre>+        return false;</pre><pre>+    }</pre><pre>+</pre><pre>+    /* check the streams we can actually add */</pre><pre>+    for (std::vector<sout_stream_id_sys_t*>::iterator it = </pre><pre>out_streams.begin();</pre><pre>+            it != out_streams.end(); )</pre><pre>+    {</pre><pre>+        sout_stream_id_sys_t *p_sys_id = *it;</pre><pre>+        p_sys_id->p_sub_id = static_cast<sout_stream_id_sys_t *>(</pre><pre>+                sout_StreamIdAdd( p_out, &p_sys_id->fmt ) );</pre><pre>+        if ( p_sys_id->p_sub_id == NULL )</pre><pre>+        {</pre><pre>+            msg_Err( p_stream, "can't handle %4.4s stream",</pre><pre>+                    (char *)&p_sys_id->fmt.i_codec );</pre><pre>+            es_format_Clean( &p_sys_id->fmt );</pre><pre>+            it = out_streams.erase( it );</pre><pre>+        }</pre><pre>+        else</pre><pre>+            ++it;</pre><pre>+    }</pre><pre>+</pre><pre>+    if (out_streams.empty())</pre><pre>+    {</pre><pre>+        stopSoutChain( p_stream );</pre><pre>+        return false;</pre><pre>+    }</pre><pre>+</pre><pre>+    return true;</pre><pre>+}</pre><pre>+</pre><pre>+void sout_stream_sys_t::stopSoutChain(sout_stream_t *p_stream)</pre><pre>+{</pre><pre>+    (void) p_stream;</pre><pre>+</pre><pre>+    for ( size_t i = 0; i < out_streams.size(); i++ )</pre><pre>+    {</pre><pre>+        sout_StreamIdDel( p_out, out_streams[i]->p_sub_id );</pre><pre>+        out_streams[i]->p_sub_id = NULL;</pre><pre>+    }</pre><pre>+    out_streams.clear();</pre><pre>+    sout_StreamChainDelete( p_out, NULL );</pre><pre>+    p_out = NULL;</pre><pre>+}</pre><pre>+</pre><pre>+sout_stream_id_sys_t *sout_stream_sys_t::GetSubId( sout_stream_t </pre><pre>*p_stream,</pre><pre>+                                                   sout_stream_id_sys_t </pre><pre>*id,</pre><pre>+                                                   bool update)</pre><pre>+{</pre><pre>+    assert( p_stream->p_sys == this );</pre><pre>+</pre><pre>+    if ( update && UpdateOutput( p_stream ) != VLC_SUCCESS )</pre><pre>+        return NULL;</pre><pre>+</pre><pre>+    for (size_t i = 0; i < out_streams.size(); ++i)</pre><pre>+    {</pre><pre>+        if ( id == (sout_stream_id_sys_t*) out_streams[i] )</pre><pre>+            return out_streams[i]->p_sub_id;</pre><pre>+    }</pre><pre>+</pre><pre>+    msg_Err( p_stream, "unknown stream ID" );</pre><pre>+    return NULL;</pre><pre>+}</pre><pre>+</pre><pre>+static std::string GetVencQSVH264Option( sout_stream_t * /* p_stream </pre><pre>*/,</pre><pre>+                                         const video_format_t * /* </pre><pre>p_vid */,</pre><pre>+                                         int i_quality )</pre><pre>+{</pre><pre>+    std::stringstream ssout;</pre><pre>+    static const char video_target_usage_quality[]  = "quality";</pre><pre>+    static const char video_target_usage_balanced[] = "balanced";</pre><pre>+    static const char video_target_usage_speed[]    = "speed";</pre><pre>+    static const char video_bitrate_high[] = "vb=8000000";</pre><pre>+    static const char video_bitrate_low[]  = "vb=3000000";</pre><pre>+    const char *psz_video_target_usage;</pre><pre>+    const char *psz_video_bitrate;</pre><pre>+</pre><pre>+    switch ( i_quality )</pre><pre>+    {</pre><pre>+        case CONVERSION_QUALITY_HIGH:</pre><pre>+            psz_video_target_usage = video_target_usage_quality;</pre><pre>+            psz_video_bitrate = video_bitrate_high;</pre><pre>+            break;</pre><pre>+        case CONVERSION_QUALITY_MEDIUM:</pre><pre>+            psz_video_target_usage = video_target_usage_balanced;</pre><pre>+            psz_video_bitrate = video_bitrate_high;</pre><pre>+            break;</pre><pre>+        case CONVERSION_QUALITY_LOW:</pre><pre>+            psz_video_target_usage = video_target_usage_balanced;</pre><pre>+            psz_video_bitrate = video_bitrate_low;</pre><pre>+            break;</pre><pre>+        default:</pre><pre>+        case CONVERSION_QUALITY_LOWCPU:</pre><pre>+            psz_video_target_usage = video_target_usage_speed;</pre><pre>+            psz_video_bitrate = video_bitrate_low;</pre><pre>+            break;</pre><pre>+    }</pre><pre>+</pre><pre>+    ssout << "venc=qsv{target-usage=" << psz_video_target_usage <<</pre><pre>+             "}," << psz_video_bitrate;</pre><pre>+    return ssout.str();</pre><pre>+}</pre><pre>+</pre><pre>+static std::string GetVencX264Option( sout_stream_t * /* p_stream */,</pre><pre>+                                      const video_format_t *p_vid,</pre><pre>+                                      int i_quality )</pre><pre>+{</pre><pre>+    std::stringstream ssout;</pre><pre>+    static const char video_x264_preset_veryfast[] = "veryfast";</pre><pre>+    static const char video_x264_preset_ultrafast[] = "ultrafast";</pre><pre>+    const char *psz_video_x264_preset;</pre><pre>+    unsigned i_video_x264_crf_hd, i_video_x264_crf_720p;</pre><pre>+</pre><pre>+    switch ( i_quality )</pre><pre>+    {</pre><pre>+        case CONVERSION_QUALITY_HIGH:</pre><pre>+            i_video_x264_crf_hd = i_video_x264_crf_720p = 21;</pre><pre>+            psz_video_x264_preset = video_x264_preset_veryfast;</pre><pre>+            break;</pre><pre>+        case CONVERSION_QUALITY_MEDIUM:</pre><pre>+            i_video_x264_crf_hd = 23;</pre><pre>+            i_video_x264_crf_720p = 21;</pre><pre>+            psz_video_x264_preset = video_x264_preset_veryfast;</pre><pre>+            break;</pre><pre>+        case CONVERSION_QUALITY_LOW:</pre><pre>+            i_video_x264_crf_hd = i_video_x264_crf_720p = 23;</pre><pre>+            psz_video_x264_preset = video_x264_preset_veryfast;</pre><pre>+            break;</pre><pre>+        default:</pre><pre>+        case CONVERSION_QUALITY_LOWCPU:</pre><pre>+            i_video_x264_crf_hd = i_video_x264_crf_720p = 23;</pre><pre>+            psz_video_x264_preset = video_x264_preset_ultrafast;</pre><pre>+            break;</pre><pre>+    }</pre><pre>+</pre><pre>+    const bool b_hdres = p_vid->i_height == 0 || p_vid->i_height >= </pre><pre>800;</pre><pre>+    unsigned i_video_x264_crf = b_hdres ? i_video_x264_crf_hd : </pre><pre>i_video_x264_crf_720p;</pre><pre>+</pre><pre>+    ssout << "venc=x264{preset=" << psz_video_x264_preset</pre><pre>+          << ",crf=" << i_video_x264_crf << "}";</pre><pre>+    return ssout.str();</pre><pre>+}</pre><pre>+</pre><pre>+#ifdef __APPLE__</pre><pre>+static std::string GetVencAvcodecVTOption( sout_stream_t * /* p_stream </pre><pre>*/,</pre><pre>+                                           const video_format_t * </pre><pre>p_vid,</pre><pre>+                                           int i_quality )</pre><pre>+{</pre><pre>+    std::stringstream ssout;</pre><pre>+    ssout << </pre><pre>"venc=avcodec{codec=h264_videotoolbox,options{realtime=1}}";</pre><pre>+    switch( i_quality )</pre><pre>+    {</pre><pre>+        /* Here, performances issues won't come from videotoolbox but </pre><pre>from</pre><pre>+         * some old chromecast devices */</pre><pre>+</pre><pre>+        case CONVERSION_QUALITY_HIGH:</pre><pre>+            break;</pre><pre>+        case CONVERSION_QUALITY_MEDIUM:</pre><pre>+            ssout << ",vb=8000000";</pre><pre>+            break;</pre><pre>+        case CONVERSION_QUALITY_LOW:</pre><pre>+        case CONVERSION_QUALITY_LOWCPU:</pre><pre>+            ssout << ",vb=3000000";</pre><pre>+            break;</pre><pre>+    }</pre><pre>+</pre><pre>+    return ssout.str();</pre><pre>+}</pre><pre>+#endif</pre><pre>+</pre><pre>+static struct</pre><pre>+{</pre><pre>+    vlc_fourcc_t fcc;</pre><pre>+    std::string (*get_opt)( sout_stream_t *, const video_format_t *, </pre><pre>int);</pre><pre>+} venc_opt_list[] = {</pre><pre>+#ifdef __APPLE__</pre><pre>+    { .fcc = VLC_CODEC_H264, .get_opt = GetVencAvcodecVTOption },</pre><pre>+#endif</pre><pre>+    { .fcc = VLC_CODEC_H264, .get_opt = GetVencQSVH264Option },</pre><pre>+    { .fcc = VLC_CODEC_H264, .get_opt = GetVencX264Option },</pre><pre>+    { .fcc = VLC_CODEC_H264, .get_opt = NULL },</pre><pre>+};</pre><pre>+</pre><pre>+std::string</pre><pre>+sout_stream_sys_t::GetVencOption( sout_stream_t *p_stream, vlc_fourcc_t </pre><pre>*p_codec_video,</pre><pre>+                                  const video_format_t *p_vid, int </pre><pre>i_quality )</pre><pre>+{</pre><pre>+    for( size_t i = (venc_opt_idx == -1 ? 0 : venc_opt_idx);</pre><pre>+         i < ARRAY_SIZE(venc_opt_list); ++i )</pre><pre>+    {</pre><pre>+        std::stringstream ssout, ssvenc;</pre><pre>+        char fourcc[5];</pre><pre>+        ssvenc << "vcodec=";</pre><pre>+        vlc_fourcc_to_char( venc_opt_list[i].fcc, fourcc );</pre><pre>+        fourcc[4] = '\0';</pre><pre>+        ssvenc << fourcc << ',';</pre><pre>+</pre><pre>+        if( venc_opt_list[i].get_opt != NULL )</pre><pre>+            ssvenc << venc_opt_list[i].get_opt( p_stream, p_vid, </pre><pre>i_quality ) << ',';</pre><pre>+</pre><pre>+        if( venc_opt_list[i].get_opt == NULL</pre><pre>+         || ( venc_opt_idx != -1 && (unsigned) venc_opt_idx == i) )</pre><pre>+        {</pre><pre>+            venc_opt_idx = i;</pre><pre>+            *p_codec_video = venc_opt_list[i].fcc;</pre><pre>+            return ssvenc.str();</pre><pre>+        }</pre><pre>+</pre><pre>+        /* Test if a module can encode with the specified options / </pre><pre>fmt_video. */</pre><pre>+        ssout << "transcode{" << ssvenc.str() << "}:dummy";</pre><pre>+</pre><pre>+        sout_stream_t *p_sout_test =</pre><pre>+            sout_StreamChainNew( p_stream->p_sout, ssout.str().c_str(), </pre><pre>NULL, NULL );</pre><pre>+</pre><pre>+        if( p_sout_test != NULL )</pre><pre>+        {</pre><pre>+            p_sout_test->obj.flags |= OBJECT_FLAGS_QUIET|</pre><pre>OBJECT_FLAGS_NOINTERACT;</pre><pre>+</pre><pre>+            es_format_t fmt;</pre><pre>+            es_format_InitFromVideo( &fmt, p_vid );</pre><pre>+            fmt.i_codec = fmt.video.i_chroma = VLC_CODEC_I420;</pre><pre>+</pre><pre>+            /* Test the maximum size/fps we will encode */</pre><pre>+            fmt.video.i_visible_width = fmt.video.i_width = 1920;</pre><pre>+            fmt.video.i_visible_height = fmt.video.i_height = 1080;</pre><pre>+            fmt.video.i_frame_rate = 30;</pre><pre>+            fmt.video.i_frame_rate_base = 1;</pre><pre>+</pre><pre>+            void *id = sout_StreamIdAdd( p_sout_test, &fmt );</pre><pre>+</pre><pre>+            es_format_Clean( &fmt );</pre><pre>+            const bool success = id != NULL;</pre><pre>+</pre><pre>+            if( id )</pre><pre>+                sout_StreamIdDel( p_sout_test, id );</pre><pre>+            sout_StreamChainDelete( p_sout_test, NULL );</pre><pre>+</pre><pre>+            if( success )</pre><pre>+            {</pre><pre>+                venc_opt_idx = i;</pre><pre>+                *p_codec_video = venc_opt_list[i].fcc;</pre><pre>+                return ssvenc.str();</pre><pre>+            }</pre><pre>+        }</pre><pre>+    }</pre><pre>+    vlc_assert_unreachable();</pre><pre>+}</pre><pre>+</pre><pre>+std::string</pre><pre>+sout_stream_sys_t::GetVcodecOption( sout_stream_t *p_stream, </pre><pre>vlc_fourcc_t *p_codec_video,</pre><pre>+                                    const video_format_t *p_vid, int </pre><pre>i_quality )</pre><pre>+{</pre><pre>+    std::stringstream ssout;</pre><pre>+    static const char video_maxres_hd[] = </pre><pre>"maxwidth=1920,maxheight=1080";</pre><pre>+    static const char video_maxres_720p[] = </pre><pre>"maxwidth=1280,maxheight=720";</pre><pre>+</pre><pre>+    ssout << GetVencOption( p_stream, p_codec_video, p_vid, </pre><pre>i_quality );</pre><pre>+</pre><pre>+    switch ( i_quality )</pre><pre>+    {</pre><pre>+        case CONVERSION_QUALITY_HIGH:</pre><pre>+        case CONVERSION_QUALITY_MEDIUM:</pre><pre>+            ssout << ( ( p_vid->i_width > 1920 ) ? "width=1920," : "" ) </pre><pre><< video_maxres_hd << ',';</pre><pre>+            break;</pre><pre>+        default:</pre><pre>+            ssout << ( ( p_vid->i_width > 1280 ) ? "width=1280," : "" ) </pre><pre><< video_maxres_720p << ',';</pre><pre>+    }</pre><pre>+</pre><pre>+    if( p_vid->i_frame_rate == 0 || p_vid->i_frame_rate_base == 0</pre><pre>+     || ( p_vid->i_frame_rate / p_vid->i_frame_rate_base ) > 30 )</pre><pre>+    {</pre><pre>+        /* Even force 24fps if the frame rate is unknown */</pre><pre>+        msg_Warn( p_stream, "lowering frame rate to 24fps" );</pre><pre>+        ssout << "fps=24,";</pre><pre>+    }</pre><pre>+</pre><pre>+    msg_Dbg( p_stream, "Converting video to %.4s", (const </pre><pre>char*)p_codec_video );</pre><pre>+</pre><pre>+    return ssout.str();</pre><pre>+}</pre></blockquote><pre><br></pre><pre>GetVencOption() and hardware specific encoder functions are the same than the chromecast ones, right ?</pre><pre>They should be factorized. I'm afraid we'll forget to check for upnp when we do a fix on the chromecast sout (or vice-versa).</pre><pre><br></pre><pre>The functions could be moved on a separate file, like stream_out/renderer_common.c/.h</pre><pre><br></pre></blockquote><pre><br></pre><pre>There is a slight difference, only H264 encoders are used and the VP8 encoder option is removed.</pre><pre><br></pre><pre>Maybe only refactor the individual encoder option functions and have different GetVencOption()</pre><pre>or maybe just the venc_opt_list struct.</pre><pre><br></pre><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>+</pre><pre>+std::string</pre><pre>+sout_stream_sys_t::GetAcodecOption( sout_stream_t *p_stream, </pre><pre>vlc_fourcc_t *p_codec_audio,</pre><pre>+                                    const audio_format_t *p_aud, int </pre><pre>i_quality )</pre><pre>+{</pre><pre>+    VLC_UNUSED(p_aud);</pre><pre>+    VLC_UNUSED(i_quality);</pre><pre>+    std::stringstream ssout;</pre><pre>+</pre><pre>+    msg_Dbg( p_stream, "Converting audio to %.4s", (const </pre><pre>char*)p_codec_audio );</pre><pre>+</pre><pre>+    ssout << "acodec=";</pre><pre>+    char fourcc[5];</pre><pre>+    vlc_fourcc_to_char( *p_codec_audio, fourcc );</pre><pre>+    fourcc[4] = '\0';</pre><pre>+    ssout << fourcc << ',';</pre><pre>+</pre><pre>+    return ssout.str();</pre><pre>+}</pre><pre>+</pre><pre>+int sout_stream_sys_t::UpdateOutput( sout_stream_t *p_stream )</pre><pre>+{</pre><pre>+    assert( p_stream->p_sys == this );</pre><pre>+</pre><pre>+    if ( !es_changed )</pre><pre>+        return VLC_SUCCESS;</pre><pre>+</pre><pre>+    es_changed = false;</pre><pre>+</pre><pre>+    bool canRemux = true;</pre><pre>+    // To keep track of which stream needs transcoding if at all.</pre><pre>+    vlc_fourcc_t i_codec_video = 0, i_codec_audio = 0;</pre><pre>+    const es_format_t *p_original_audio = NULL;</pre><pre>+    const es_format_t *p_original_video = NULL;</pre><pre>+    std::vector<sout_stream_id_sys_t*> new_streams;</pre><pre>+</pre><pre>+    for (sout_stream_id_sys_t *stream : streams)</pre><pre>+    {</pre><pre>+        const es_format_t *p_es = &stream->fmt;</pre><pre>+        if (p_es->i_cat == AUDIO_ES)</pre><pre>+        {</pre><pre>+            if (!canDecodeAudio( p_es->i_codec ))</pre><pre>+            {</pre><pre>+                msg_Dbg( p_stream, "can't remux audio track %d codec </pre><pre>%4.4s",</pre><pre>+                        p_es->i_id, (const char*)&p_es->i_codec );</pre><pre>+                p_original_audio = p_es;</pre><pre>+                canRemux = false;</pre><pre>+            }</pre><pre>+            else if (i_codec_audio == 0)</pre><pre>+            {</pre><pre>+                i_codec_audio = p_es->i_codec;</pre><pre>+            }</pre><pre>+            new_streams.push_back(stream);</pre><pre>+        }</pre><pre>+        else if (b_supports_video && p_es->i_cat == VIDEO_ES)</pre><pre>+        {</pre><pre>+            if (!canDecodeVideo( p_es->i_codec ))</pre><pre>+            {</pre><pre>+                msg_Dbg( p_stream, "can't remux video track %d codec </pre><pre>%4.4s",</pre><pre>+                        p_es->i_id, (const char*)&p_es->i_codec );</pre><pre>+                p_original_video = p_es;</pre><pre>+                canRemux = false;</pre><pre>+            }</pre><pre>+            else if (i_codec_video == 0)</pre><pre>+            {</pre><pre>+                i_codec_video = p_es->i_codec;</pre><pre>+            }</pre><pre>+            new_streams.push_back(stream);</pre><pre>+        }</pre><pre>+    }</pre><pre>+</pre><pre>+    if (new_streams.empty())</pre><pre>+        return VLC_SUCCESS;</pre><pre>+</pre><pre>+    std::ostringstream ssout;</pre><pre>+    if ( !canRemux )</pre><pre>+    {</pre><pre>+        if ( !perf_warning_shown && i_codec_video == 0 && </pre><pre>p_original_video</pre><pre>+          && var_InheritInteger( p_stream, SOUT_CFG_PREFIX "show-perf-</pre><pre>warning" ) )</pre><pre>+        {</pre><pre>+            int res = vlc_dialog_wait_question( p_stream,</pre><pre>+                          VLC_DIALOG_QUESTION_WARNING,</pre><pre>+                         _("Cancel"), _("OK"), _("Ok, Don't warn me </pre><pre>again"),</pre><pre>+                         _("Performance warning"),</pre><pre>+                         _("Casting this video requires conversion. "</pre><pre>+                           "This conversion can use all the available </pre><pre>power and "</pre><pre>+                           "could quickly drain your battery." ) );</pre><pre>+            if ( res <= 0 )</pre><pre>+                 return false;</pre><pre>+            perf_warning_shown = true;</pre><pre>+            if ( res == 2 )</pre><pre>+                config_PutInt(SOUT_CFG_PREFIX "show-perf-warning", 0 );</pre><pre>+        }</pre><pre>+</pre><pre>+        const int i_quality = var_InheritInteger( p_stream, </pre><pre>SOUT_CFG_PREFIX "conversion-quality" );</pre><pre>+</pre><pre>+        /* TODO: provide audio samplerate and channels */</pre><pre>+        ssout << "transcode{";</pre><pre>+        if ( i_codec_audio == 0 && p_original_audio )</pre><pre>+        {</pre><pre>+            i_codec_audio = VLC_CODEC_MP4A;</pre><pre>+            ssout << GetAcodecOption( p_stream, &i_codec_audio,</pre><pre>+                                      &p_original_audio->audio, </pre><pre>i_quality );</pre><pre>+        }</pre><pre>+        if ( i_codec_video == 0 && p_original_video )</pre><pre>+        {</pre><pre>+            i_codec_video = VLC_CODEC_H264;</pre><pre>+            ssout << GetVcodecOption( p_stream, &i_codec_video,</pre><pre>+                                      &p_original_video->video, </pre><pre>i_quality );</pre><pre>+        }</pre><pre>+        ssout << "}:";</pre><pre>+    }</pre><pre>+</pre><pre>+    std::ostringstream ss;</pre><pre>+    ss << "/dlna"</pre><pre>+       << "/" << vlc_tick_now()</pre><pre>+       << "/" << static_cast<uint64_t>( vlc_mrand48() )</pre><pre>+       << "/stream";</pre><pre>+    std::string root_url = ss.str();</pre><pre>+</pre><pre>+    ssout << "http{dst=:" << http_port << root_url</pre><pre>+          << ",mux=" << "mp4stream"</pre><pre>+          << ",access=http{mime=" << "video/mp4" << "}}";</pre><pre>+</pre><pre>+    char *ip = getServerIPAddress();</pre><pre>+    if (ip == NULL)</pre><pre>+    {</pre><pre>+        msg_Err(p_stream, "could not get the local ip address");</pre><pre>+        return VLC_EGENERIC;</pre><pre>+    }</pre><pre>+</pre><pre>+    char *uri;</pre><pre>+    if (asprintf(&uri, "</pre><a href="http://%s:%d%s"><pre>http://%s:%d%s</pre></a><pre>", ip, http_port, </pre><pre>root_url.c_str()) < 0) {</pre><pre>+        return VLC_ENOMEM;</pre><pre>+    }</pre><pre>+</pre><pre>+    if ( !startSoutChain( p_stream, new_streams, ssout.str() ) )</pre><pre>+        return VLC_EGENERIC;</pre><pre>+</pre><pre>+    msg_Dbg(p_stream, "AVTransportURI: %s", uri);</pre><pre>+    renderer->Stop();</pre><pre>+    renderer->SetAVTransportURI(uri);</pre><pre>+    renderer->Play("1");</pre><pre>+</pre><pre>+    free(uri);</pre><pre>+    return VLC_SUCCESS;</pre><pre>+}</pre><pre>+</pre><pre>+char *MediaRenderer::getServiceURL(const char* type, const char </pre><pre>*service)</pre><pre>+{</pre><pre>+    IXML_Document *p_description_doc = NULL;</pre><pre>+    if (UpnpDownloadXmlDoc(device_url.c_str(), &p_description_doc) != </pre><pre>UPNP_E_SUCCESS)</pre><pre>+        return NULL;</pre><pre>+</pre><pre>+    IXML_NodeList* p_device_list = </pre><pre>ixmlDocument_getElementsByTagName( p_description_doc, "device");</pre><pre>+    free(p_description_doc);</pre><pre>+    if ( !p_device_list )</pre><pre>+        return NULL;</pre><pre>+</pre><pre>+    for (unsigned int i = 0; i < ixmlNodeList_length(p_device_list); +</pre><pre>+i)</pre><pre>+    {</pre><pre>+        IXML_Element* p_device_element = ( IXML_Element* ) </pre><pre>ixmlNodeList_item( p_device_list, i );</pre><pre>+        if( !p_device_element )</pre><pre>+            continue;</pre><pre>+</pre><pre>+        IXML_NodeList* p_service_list = </pre><pre>ixmlElement_getElementsByTagName( p_device_element, "service" );</pre><pre>+        if ( !p_service_list )</pre><pre>+            continue;</pre><pre>+        for ( unsigned int j = 0; j < </pre><pre>ixmlNodeList_length( p_service_list ); j++ )</pre><pre>+        {</pre><pre>+            IXML_Element* p_service_element = </pre><pre>(IXML_Element*)ixmlNodeList_item( p_service_list, j );</pre><pre>+</pre><pre>+            const char* psz_service_type = </pre><pre>xml_getChildElementValue( p_service_element, "serviceType" );</pre><pre>+            if ( !psz_service_type || !strstr(psz_service_type, type))</pre><pre>+                continue;</pre><pre>+            const char* psz_control_url = </pre><pre>xml_getChildElementValue( p_service_element,</pre><pre>+                                                                    </pre><pre>service );</pre><pre>+            if ( !psz_control_url )</pre><pre>+                continue;</pre><pre>+</pre><pre>+            char* psz_url = ( char* ) malloc( base_url.length() + </pre><pre>strlen( psz_control_url ) + 1 );</pre><pre>+            if ( psz_url && UpnpResolveURL( base_url.c_str(), </pre><pre>psz_control_url, psz_url ) == UPNP_E_SUCCESS )</pre><pre>+                return psz_url;</pre><pre>+            return NULL;</pre><pre>+        }</pre><pre>+    }</pre><pre>+    return NULL;</pre><pre>+}</pre><pre>+</pre><pre>+/**</pre><pre>+ * Send an action to the control url of the service specified.</pre><pre>+ *</pre><pre>+ * \return the response as a IXML document or NULL for failure</pre><pre>+ **/</pre><pre>+IXML_Document *MediaRenderer::SendAction(const char* action_name,const </pre><pre>char *service_type,</pre><pre>+                    std::list<std::pair<const char*, const char*>> </pre><pre>arguments)</pre><pre>+{</pre><pre>+    /* Create action */</pre><pre>+    IXML_Document *action = UpnpMakeAction(action_name, service_type, </pre><pre>0, NULL);</pre><pre>+</pre><pre>+    /* Add argument to action */</pre><pre>+    for (std::pair<const char*, const char*> arg : arguments) {</pre><pre>+      const char *arg_name, *arg_val;</pre><pre>+      arg_name = arg.first;</pre><pre>+      arg_val  = arg.second;</pre><pre>+      UpnpAddToAction(&action, action_name, service_type, arg_name, </pre><pre>arg_val);</pre><pre>+    }</pre><pre>+</pre><pre>+    /* Get the controlURL of the service */</pre><pre>+    char *control_url = getServiceURL(service_type, "controlURL");</pre><pre>+</pre><pre>+    /* Send action */</pre><pre>+    IXML_Document *response = NULL;</pre><pre>+    int ret = UpnpSendAction(handle, control_url, service_type,</pre><pre>+                                    NULL, action, &response);</pre><pre>+</pre><pre>+    /* Free action */</pre><pre>+    if (action) ixmlDocument_free(action);</pre><pre>+    if (control_url) free(control_url);</pre><pre>+</pre><pre>+    if (ret != UPNP_E_SUCCESS) {</pre><pre>+        msg_Err(parent, "Unable to send action: %s (%d: %s) response: </pre><pre>%s",</pre><pre>+                action_name, ret, UpnpGetErrorMessage(ret), </pre><pre>ixmlPrintDocument(response));</pre><pre>+        if (response) ixmlDocument_free(response);</pre><pre>+        return NULL;</pre><pre>+    }</pre><pre>+</pre><pre>+    return response;</pre><pre>+}</pre><pre>+</pre><pre>+int MediaRenderer::Play(const char *speed)</pre><pre>+{</pre><pre>+    std::list<std::pair<const char*, const char*>> arg_list;</pre><pre>+    arg_list.push_back(std::make_pair("InstanceID", "0"));</pre><pre>+    arg_list.push_back(std::make_pair("Speed", speed));</pre><pre>+</pre><pre>+    IXML_Document *p_response = SendAction("Play", </pre><pre>AV_TRANSPORT_SERVICE_TYPE, arg_list);</pre><pre>+    if(!p_response)</pre><pre>+    {</pre><pre>+        return VLC_EGENERIC;</pre><pre>+    }</pre><pre>+    ixmlDocument_free(p_response);</pre><pre>+    return VLC_SUCCESS;</pre><pre>+}</pre><pre>+</pre><pre>+int MediaRenderer::Stop()</pre><pre>+{</pre><pre>+    std::list<std::pair<const char*, const char*>> arg_list;</pre><pre>+    arg_list.push_back(std::make_pair("InstanceID", "0"));</pre><pre>+</pre><pre>+    IXML_Document *p_response = SendAction("Stop", </pre><pre>AV_TRANSPORT_SERVICE_TYPE, arg_list);</pre><pre>+    if(!p_response)</pre><pre>+    {</pre><pre>+        return VLC_EGENERIC;</pre><pre>+    }</pre><pre>+    ixmlDocument_free(p_response);</pre><pre>+    return VLC_SUCCESS;</pre><pre>+}</pre><pre>+</pre><pre>+int MediaRenderer::SetAVTransportURI(const char* uri)</pre><pre>+{</pre><pre>+    std::list<std::pair<const char*, const char*>> arg_list;</pre><pre>+    arg_list.push_back(std::make_pair("InstanceID", "0"));</pre><pre>+    arg_list.push_back(std::make_pair("CurrentURI", uri));</pre><pre>+    arg_list.push_back(std::make_pair("CurrentURIMetaData", "")); // </pre><pre>NOT_IMPLEMENTED</pre><pre>+</pre><pre>+    IXML_Document *p_response = SendAction("SetAVTransportURI",</pre><pre>+                                    AV_TRANSPORT_SERVICE_TYPE, </pre><pre>arg_list);</pre><pre>+    if(!p_response)</pre><pre>+    {</pre><pre>+        return VLC_EGENERIC;</pre><pre>+    }</pre><pre>+    ixmlDocument_free(p_response);</pre><pre>+    return VLC_SUCCESS;</pre><pre>+}</pre><pre>+</pre><pre>+static void *Add(sout_stream_t *p_stream, const es_format_t *p_fmt)</pre><pre>+{</pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t </pre><pre>*>( p_stream->p_sys );</pre><pre>+</pre><pre>+    if (!p_sys->b_supports_video)</pre><pre>+    {</pre><pre>+        if (p_fmt->i_cat != AUDIO_ES)</pre><pre>+            return NULL;</pre><pre>+    }</pre><pre>+</pre><pre>+    sout_stream_id_sys_t *p_sys_id = (sout_stream_id_sys_t </pre><pre>*)malloc(sizeof(sout_stream_id_sys_t));</pre><pre>+    if(p_sys_id != NULL)</pre><pre>+    {</pre><pre>+        es_format_Copy(&p_sys_id->fmt, p_fmt);</pre><pre>+        p_sys_id->p_sub_id = NULL;</pre><pre>+        p_sys->streams.push_back(p_sys_id);</pre><pre>+        p_sys->es_changed = true;</pre><pre>+    }</pre><pre>+    return p_sys_id;</pre><pre>+}</pre><pre>+</pre><pre>+static int Send(sout_stream_t *p_stream, void *id,</pre><pre>+                block_t *p_buffer)</pre><pre>+{</pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t </pre><pre>*>( p_stream->p_sys );</pre><pre>+    sout_stream_id_sys_t *id_sys = </pre><pre>static_cast<sout_stream_id_sys_t*>( id );</pre><pre>+</pre><pre>+    id_sys = p_sys->GetSubId( p_stream, id_sys );</pre><pre>+    if ( id_sys == NULL )</pre><pre>+        return VLC_EGENERIC;</pre><pre>+</pre><pre>+    return sout_StreamIdSend(p_sys->p_out, id_sys, p_buffer);</pre><pre>+}</pre><pre>+</pre><pre>+static void Flush( sout_stream_t *p_stream, void *id )</pre><pre>+{</pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t </pre><pre>*>( p_stream->p_sys );</pre><pre>+    sout_stream_id_sys_t *id_sys = </pre><pre>static_cast<sout_stream_id_sys_t*>( id );</pre><pre>+</pre><pre>+    id_sys = p_sys->GetSubId( p_stream, id_sys, false );</pre><pre>+    if ( id_sys == NULL )</pre><pre>+        return;</pre><pre>+</pre><pre>+    sout_StreamFlush( p_sys->p_out, id_sys );</pre><pre>+}</pre><pre>+</pre><pre>+static void Del(sout_stream_t *p_stream, void *_id)</pre><pre>+{</pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t </pre><pre>*>( p_stream->p_sys );</pre><pre>+    sout_stream_id_sys_t *id = static_cast<sout_stream_id_sys_t </pre><pre>*>( _id );</pre><pre>+</pre><pre>+    for (std::vector<sout_stream_id_sys_t*>::iterator it = p_sys-</pre><blockquote type="cite" style="margin:0 0 0 .8ex; border-left:2px #729fcf solid;padding-left:1ex"><pre>streams.begin();</pre></blockquote><pre>+         it != p_sys->streams.end(); )</pre><pre>+    {</pre><pre>+        sout_stream_id_sys_t *p_sys_id = *it;</pre><pre>+        if ( p_sys_id == id )</pre><pre>+        {</pre><pre>+            if ( p_sys_id->p_sub_id != NULL )</pre><pre>+            {</pre><pre>+                sout_StreamIdDel( p_sys->p_out, p_sys_id->p_sub_id );</pre><pre>+                for (std::vector<sout_stream_id_sys_t*>::iterator </pre><pre>out_it = p_sys->out_streams.begin();</pre><pre>+                     out_it != p_sys->out_streams.end(); )</pre><pre>+                {</pre><pre>+                    if (*out_it == id)</pre><pre>+                    {</pre><pre>+                        p_sys->out_streams.erase(out_it);</pre><pre>+                        break;</pre><pre>+                    }</pre><pre>+                    out_it++;</pre><pre>+                }</pre><pre>+            }</pre><pre>+</pre><pre>+            es_format_Clean( &p_sys_id->fmt );</pre><pre>+            free( p_sys_id );</pre><pre>+            p_sys->streams.erase( it );</pre><pre>+            break;</pre><pre>+        }</pre><pre>+        it++;</pre><pre>+    }</pre><pre>+</pre><pre>+    if (p_sys->out_streams.empty())</pre><pre>+    {</pre><pre>+        p_sys->stopSoutChain(p_stream);</pre><pre>+        p_sys->renderer->Stop();</pre><pre>+    }</pre><pre>+}</pre><pre>+</pre><pre>+int OpenSout( vlc_object_t *p_this )</pre><pre>+{</pre><pre>+    sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_this);</pre><pre>+    sout_stream_sys_t *p_sys = NULL;</pre><pre>+</pre><pre>+    config_ChainParse(p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, </pre><pre>p_stream->p_cfg);</pre><pre>+</pre><pre>+    int http_port = var_InheritInteger(p_stream, SOUT_CFG_PREFIX "http-</pre><pre>port");</pre><pre>+    bool b_supports_video = var_GetBool(p_stream, SOUT_CFG_PREFIX </pre><pre>"video");</pre><pre>+    char *base_url = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX </pre><pre>"base_url");</pre><pre>+    char *device_url = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX </pre><pre>"url");</pre><pre>+    if ( device_url == NULL)</pre><pre>+    {</pre><pre>+        msg_Err( p_stream, "missing Url" );</pre><pre>+        goto error;</pre><pre>+    }</pre><pre>+</pre><pre>+    try {</pre><pre>+        p_sys = new sout_stream_sys_t(http_port, b_supports_video);</pre><pre>+    }</pre><pre>+    catch ( const std::exception& ex ) {</pre><pre>+        msg_Err( p_stream, "Failed to instantiate sout_stream_sys_t: </pre><pre>%s", ex.what() );</pre><pre>+        return VLC_EGENERIC;</pre><pre>+    }</pre><pre>+</pre><pre>+    p_sys->p_upnp = UpnpInstanceWrapper::get( p_this );</pre><pre>+    if ( !p_sys->p_upnp )</pre><pre>+        goto error;</pre><pre>+    try {</pre><pre>+        p_sys->renderer = std::make_shared<MediaRenderer>(p_stream,</pre><pre>+                            p_sys->p_upnp, base_url, device_url);</pre><pre>+    }</pre><pre>+    catch ( const std::bad_alloc& ) {</pre><pre>+        msg_Err( p_stream, "Failed to create a MediaRenderer");</pre><pre>+        p_sys->p_upnp->release();</pre><pre>+        goto error;</pre><pre>+    }</pre><pre>+</pre><pre>+    p_stream->pf_add     = Add;</pre><pre>+    p_stream->pf_del     = Del;</pre><pre>+    p_stream->pf_send    = Send;</pre><pre>+    p_stream->pf_flush   = Flush;</pre><pre>+</pre><pre>+    p_stream->p_sys = p_sys;</pre><pre>+</pre><pre>+    free(base_url);</pre><pre>+    free(device_url);</pre><pre>+</pre><pre>+    return VLC_SUCCESS;</pre><pre>+</pre><pre>+error:</pre><pre>+    free(base_url);</pre><pre>+    free(device_url);</pre><pre>+    delete p_sys;</pre><pre>+    return VLC_EGENERIC;</pre><pre>+}</pre><pre>+</pre><pre>+void CloseSout( vlc_object_t *p_this)</pre><pre>+{</pre><pre>+    sout_stream_t *p_stream = </pre><pre>reinterpret_cast<sout_stream_t*>( p_this );</pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t </pre><pre>*>( p_stream->p_sys );</pre><pre>+</pre><pre>+    p_sys->p_upnp->release();</pre><pre>+    delete p_sys;</pre><pre>+}</pre><pre>+</pre><pre>+}</pre><pre>diff --git a/modules/stream_out/dlna/dlna.hpp b/modules/stream_out/dlna/</pre><pre>dlna.hpp</pre><pre>new file mode 100644</pre><pre>index 0000000000..59ff3d6c8d</pre><pre>--- /dev/null</pre><pre>+++ b/modules/stream_out/dlna/dlna.hpp</pre><pre>@@ -0,0 +1,60 @@</pre><pre>+/</pre><pre>*****************************************************************************</pre><pre>+ * dlna.hpp : DLNA/UPNP (renderer) sout module header</pre><pre>+ </pre><pre>*****************************************************************************</pre><pre>+ * Copyright (C) 2004-2018 VLC authors and VideoLAN</pre><pre>+ *</pre><pre>+ * Authors: William Ung <</pre><a href="mailto:william1.ung@epitech.eu"><pre>william1.ung@epitech.eu</pre></a><pre>></pre><pre>+ *          Shaleen Jain <</pre><a href="mailto:shaleen@jain.sh"><pre>shaleen@jain.sh</pre></a><pre>></pre><pre>+ *</pre><pre>+ * This program is free software; you can redistribute it and/or modify </pre><pre>it</pre><pre>+ * under the terms of the GNU Lesser General Public License as </pre><pre>published by</pre><pre>+ * the Free Software Foundation; either version 2.1 of the License, or</pre><pre>+ * (at your option) any later version.</pre><pre>+ *</pre><pre>+ * This program is distributed in the hope that it will be useful,</pre><pre>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</pre><pre>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</pre><pre>+ * GNU Lesser General Public License for more details.</pre><pre>+ *</pre><pre>+ * You should have received a copy of the GNU Lesser General Public </pre><pre>License</pre><pre>+ * along with this program; if not, write to the Free Software </pre><pre>Foundation,</pre><pre>+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.</pre><pre>+ </pre><pre>*****************************************************************************/</pre><pre>+</pre><pre>+#ifndef DLNA_H</pre><pre>+#define DLNA_H</pre><pre>+</pre><pre>+#include "../../services_discovery/upnp-wrapper.hpp"</pre><pre>+#include "dlna_common.hpp"</pre><pre>+</pre><pre>+namespace DLNA</pre><pre>+{</pre><pre>+</pre><pre>+class MediaRenderer</pre><pre>+{</pre><pre>+public:</pre><pre>+    MediaRenderer(sout_stream_t *p_stream, UpnpInstanceWrapper *upnp,</pre><pre>+            std::string base_url, std::string device_url)</pre><pre>+        : parent(p_stream)</pre><pre>+        , base_url(base_url)</pre><pre>+        , device_url(device_url)</pre><pre>+        , handle(upnp->handle())</pre><pre>+    {</pre><pre>+    }</pre><pre>+</pre><pre>+    sout_stream_t *parent;</pre><pre>+    std::string base_url;</pre><pre>+    std::string device_url;</pre><pre>+    UpnpClient_Handle handle;</pre><pre>+</pre><pre>+    char *getServiceURL(const char* type, const char* service);</pre><pre>+    IXML_Document *SendAction(const char* action_name, const char </pre><pre>*service_type,</pre><pre>+                    std::list<std::pair<const char*, const char*>> </pre><pre>arguments);</pre><pre>+</pre><pre>+    int Play(const char *speed);</pre><pre>+    int Stop();</pre><pre>+    int SetAVTransportURI(const char* uri);</pre><pre>+};</pre><pre>+</pre><pre>+}</pre><pre>+#endif /* DLNA_H */</pre><pre>diff --git a/modules/stream_out/dlna/dlna_common.hpp b/modules/</pre><pre>stream_out/dlna/dlna_common.hpp</pre><pre>new file mode 100644</pre><pre>index 0000000000..a09283255e</pre><pre>--- /dev/null</pre><pre>+++ b/modules/stream_out/dlna/dlna_common.hpp</pre><pre>@@ -0,0 +1,56 @@</pre><pre>+/</pre><pre>*****************************************************************************</pre><pre>+ * dlna.hpp : DLNA/UPNP (renderer) sout module header</pre><pre>+ </pre><pre>*****************************************************************************</pre><pre>+ * Copyright (C) 2004-2018 VLC authors and VideoLAN</pre><pre>+ *</pre><pre>+ * Authors: William Ung <</pre><a href="mailto:william1.ung@epitech.eu"><pre>william1.ung@epitech.eu</pre></a><pre>></pre><pre>+ *          Shaleen Jain <</pre><a href="mailto:shaleen@jain.sh"><pre>shaleen@jain.sh</pre></a><pre>></pre><pre>+ *</pre><pre>+ * This program is free software; you can redistribute it and/or modify </pre><pre>it</pre><pre>+ * under the terms of the GNU Lesser General Public License as </pre><pre>published by</pre><pre>+ * the Free Software Foundation; either version 2.1 of the License, or</pre><pre>+ * (at your option) any later version.</pre><pre>+ *</pre><pre>+ * This program is distributed in the hope that it will be useful,</pre><pre>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</pre><pre>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</pre><pre>+ * GNU Lesser General Public License for more details.</pre><pre>+ *</pre><pre>+ * You should have received a copy of the GNU Lesser General Public </pre><pre>License</pre><pre>+ * along with this program; if not, write to the Free Software </pre><pre>Foundation,</pre><pre>+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.</pre><pre>+ </pre><pre>*****************************************************************************/</pre><pre>+</pre><pre>+#ifndef DLNA_COMMON_H</pre><pre>+#define DLNA_COMMON_H</pre><pre>+</pre><pre>+#include <list></pre><pre>+</pre><pre>+#include <vlc_common.h></pre><pre>+#include <vlc_fourcc.h></pre><pre>+</pre><pre>+enum {</pre><pre>+    CONVERSION_QUALITY_HIGH = 0,</pre><pre>+    CONVERSION_QUALITY_MEDIUM = 1,</pre><pre>+    CONVERSION_QUALITY_LOW = 2,</pre><pre>+    CONVERSION_QUALITY_LOWCPU = 3,</pre><pre>+};</pre><pre>+</pre><pre>+static const int conversion_quality_list[] = {</pre><pre>+    CONVERSION_QUALITY_HIGH,</pre><pre>+    CONVERSION_QUALITY_MEDIUM,</pre><pre>+    CONVERSION_QUALITY_LOW,</pre><pre>+    CONVERSION_QUALITY_LOWCPU,</pre><pre>+};</pre><pre>+</pre><pre>+#define SOUT_CFG_PREFIX "sout-dlna-"</pre><pre>+</pre><pre>+namespace DLNA</pre><pre>+{</pre><pre>+</pre><pre>+/* module callbacks */</pre><pre>+int OpenSout(vlc_object_t *);</pre><pre>+void CloseSout(vlc_object_t *);</pre><pre>+</pre><pre>+}</pre><pre>+#endif /* DLNA_COMMON_H */</pre><pre>-- </pre><pre>2.19.1</pre><pre><br></pre><pre>_______________________________________________</pre><pre>vlc-devel mailing list</pre><pre>To unsubscribe or modify your subscription options:</pre><a href="https://mailman.videolan.org/listinfo/vlc-devel"><pre>https://mailman.videolan.org/listinfo/vlc-devel</pre></a><pre><br></pre></blockquote><pre><br></pre><pre>_______________________________________________</pre><pre>vlc-devel mailing list</pre><pre>To unsubscribe or modify your subscription options:</pre><a href="https://mailman.videolan.org/listinfo/vlc-devel"><pre>https://mailman.videolan.org/listinfo/vlc-devel</pre></a></blockquote><div><span><pre>-- <br></pre><div style="width: 71ch;">Regards,</div><div style="width: 71ch;">Shaleen Jain</div></span></div></body></html>