<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">p.MsoNormal,p.MsoNoSpacing{margin:0}</style>
</head>
<body><div>Hello,<br></div>
<div><br></div>
<div>On Wed, 5 Sep 2018, at 09:20, Shaleen Jain wrote:<br></div>
<blockquote type="cite"><div>On Tue, 2018-09-04 at 19:24 +0200, Jean-Baptiste Kempf wrote:<br></div>
<blockquote type="cite" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-color:rgb(114, 159, 207);border-left-style:solid;border-left-width:2px;padding-left:1ex;"><pre>Hello,<br></pre><pre><br></pre><pre>Can you explain how you query what codecs are supported by the devices?<br></pre></blockquote><div>Supported codecs are queried by the GetProcotolInfo UpnpAction which is added in a separate patch<br></div>
<div>that I planned on sending later since that is more of an RFC patch. But I will include and send a new series if you want.<br></div>
</blockquote><div><br></div>
<div>Sorry, but <b>this</b> is the difficult part of the UPnP renderer.<br></div>
<div>The rest is very similar to Chromecast.<br></div>
<div><br></div>
<div><br></div>
<div><br></div>
<blockquote type="cite"><blockquote type="cite" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-color:rgb(114, 159, 207);border-left-style:solid;border-left-width:2px;padding-left:1ex;"><pre> modules/stream_out/dlna.hpp            |  94 ++++<br></pre><pre> 7 files changed, 739 insertions(+), 1 deletion(-)<br></pre><pre> create mode 100644 modules/stream_out/dlna.cpp<br></pre><pre> create mode 100644 modules/stream_out/dlna.hpp<br></pre><pre><br></pre><pre>diff --git a/NEWS b/NEWS<br></pre><pre>index 6bc94096de..c4dbef7e7d 100644<br></pre><pre>--- a/NEWS<br></pre><pre>+++ b/NEWS<br></pre><pre>@@ -37,6 +37,9 @@ Video output:<br></pre><pre>  * Remove RealRTSP plugin<br></pre><pre>  * Remove Real demuxer plugin<br></pre><pre> <br></pre><pre>+Stream Output:<br></pre><pre>+ * Add DLNA/UPNP stream output module<br></pre><pre>+<br></pre><pre> macOS:<br></pre><pre>  * Remove Growl notification support<br></pre><pre> <br></pre><pre>diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST<br></pre><pre>index e1978cc6e4..04256242a1 100644<br></pre><pre>--- a/modules/MODULES_LIST<br></pre><pre>+++ b/modules/MODULES_LIST<br></pre><pre>@@ -375,6 +375,7 @@ $Id$<br></pre><pre>  * stream_out_delay: introduce delay in an ES when streaming<br></pre><pre>  * stream_out_description: helper module for RTSP vod<br></pre><pre>  * stream_out_display: displays a stream output chain<br></pre><pre>+ * stream_out_dlna: DLNA streaming output module<br></pre><pre>  * stream_out_dummy: dummy stream out chain module<br></pre><pre>  * stream_out_duplicate: duplicates a stream output chain<br></pre><pre>  * stream_out_es: stream out module outputing ES<br></pre><pre>diff --git a/modules/services_discovery/Makefile.am b/modules/<br></pre><pre>services_discovery/Makefile.am<br></pre><pre>index f63df23b32..3ea850c920 100644<br></pre><pre>--- a/modules/services_discovery/Makefile.am<br></pre><pre>+++ b/modules/services_discovery/Makefile.am<br></pre><pre>@@ -28,7 +28,9 @@ sd_LTLIBRARIES += $(LTLIBmtp)<br></pre><pre> <br></pre><pre> libupnp_plugin_la_SOURCES = services_discovery/upnp.cpp <br></pre><pre>services_discovery/upnp.hpp \<br></pre><pre>                      services_discovery/upnp-wrapper.hpp \<br></pre><pre>-                         services_discovery/upnp-wrapper.cpp<br></pre><pre>+                           services_discovery/upnp-wrapper.cpp \<br></pre><pre>+                         stream_out/dlna.hpp \<br></pre><pre>+                         stream_out/dlna.cpp<br></pre><pre> libupnp_plugin_la_CXXFLAGS = $(AM_CXXFLAGS) $(UPNP_CFLAGS)<br></pre><pre> libupnp_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'<br></pre><pre> libupnp_plugin_la_LIBADD = $(UPNP_LIBS)<br></pre><pre>diff --git a/modules/services_discovery/upnp.cpp b/modules/<br></pre><pre>services_discovery/upnp.cpp<br></pre><pre>index 6642e2b980..a75ec34dbd 100644<br></pre><pre>--- a/modules/services_discovery/upnp.cpp<br></pre><pre>+++ b/modules/services_discovery/upnp.cpp<br></pre><pre>@@ -147,6 +147,23 @@ vlc_module_begin()<br></pre><pre> <br></pre><pre>     VLC_RD_PROBE_SUBMODULE<br></pre><pre> <br></pre><pre>+    add_submodule()<br></pre><pre>+        set_shortname("dlna")<br></pre><pre>+        set_description(N_("UPnP/DLNA stream output"))<br></pre><pre>+        set_capability("sout stream", 0)<br></pre><pre>+        add_shortcut("dlna")<br></pre><pre>+        set_category(CAT_SOUT)<br></pre><pre>+        set_subcategory(SUBCAT_SOUT_STREAM)<br></pre><pre>+        set_callbacks(Sout::OpenSout, Sout::CloseSout)<br></pre><pre>+<br></pre><pre>+        add_string(SOUT_CFG_PREFIX "ip", NULL, IP_ADDR_TEXT, <br></pre><pre>IP_ADDR_LONGTEXT, false)<br></pre><pre>+        add_integer(SOUT_CFG_PREFIX "port", NULL, PORT_TEXT, <br></pre><pre>PORT_LONGTEXT, false)<br></pre><pre>+        add_integer(SOUT_CFG_PREFIX "http-port", HTTP_PORT, <br></pre><pre>HTTP_PORT_TEXT, HTTP_PORT_LONGTEXT, false)<br></pre><pre>+        add_bool(SOUT_CFG_PREFIX "video", true, HAS_VIDEO_TEXT, <br></pre><pre>HAS_VIDEO_LONGTEXT, false)<br></pre><pre>+        add_string(SOUT_CFG_PREFIX "mux", DEFAULT_MUXER, MUX_TEXT, <br></pre><pre>MUX_LONGTEXT, false)<br></pre><pre>+        add_string(SOUT_CFG_PREFIX "mime", "video/x-matroska", <br></pre><pre>MIME_TEXT, MIME_LONGTEXT, false)<br></pre><pre>+        add_string(SOUT_CFG_PREFIX "base_url", NULL, BASE_URL_TEXT, <br></pre><pre>BASE_URL_LONGTEXT, false)<br></pre><pre>+        add_string(SOUT_CFG_PREFIX "url", NULL, URL_TEXT, URL_LONGTEXT, <br></pre><pre>false)<br></pre><pre> vlc_module_end()<br></pre><pre> <br></pre><pre> /*<br></pre><pre>diff --git a/modules/services_discovery/upnp.hpp b/modules/<br></pre><pre>services_discovery/upnp.hpp<br></pre><pre>index 5a0de1f284..711ef200c5 100644<br></pre><pre>--- a/modules/services_discovery/upnp.hpp<br></pre><pre>+++ b/modules/services_discovery/upnp.hpp<br></pre><pre>@@ -33,6 +33,7 @@<br></pre><pre> #endif<br></pre><pre> <br></pre><pre> #include "upnp-wrapper.hpp"<br></pre><pre>+#include "../stream_out/dlna.hpp"<br></pre><pre> <br></pre><pre> #include <vlc_url.h><br></pre><pre> #include <vlc_interrupt.h><br></pre><pre>diff --git a/modules/stream_out/dlna.cpp b/modules/stream_out/dlna.cpp<br></pre><pre>new file mode 100644<br></pre><pre>index 0000000000..8fe1e27ccc<br></pre><pre>--- /dev/null<br></pre><pre>+++ b/modules/stream_out/dlna.cpp<br></pre><pre>@@ -0,0 +1,620 @@<br></pre><pre>+/<br></pre><pre>*****************************************************************************<br></pre><pre>+ * dlna.cpp : DLNA/UPNP (renderer) sout module<br></pre><pre>+ <br></pre><pre>*****************************************************************************<br></pre><pre>+ * Copyright (C) 2004-2018 VLC authors and VideoLAN<br></pre><pre>+ *<br></pre><pre>+ * Authors: William Ung <<a href="mailto:william1.ung@epitech.eu">william1.ung@epitech.eu</a>><br></pre><pre>+ *          Shaleen Jain <<a href="mailto:shaleen@jain.sh">shaleen@jain.sh</a>><br></pre><pre>+ *<br></pre><pre>+ * This program is free software; you can redistribute it and/or modify <br></pre><pre>it<br></pre><pre>+ * under the terms of the GNU Lesser General Public License as <br></pre><pre>published by<br></pre><pre>+ * the Free Software Foundation; either version 2.1 of the License, or<br></pre><pre>+ * (at your option) any later version.<br></pre><pre>+ *<br></pre><pre>+ * This program is distributed in the hope that it will be useful,<br></pre><pre>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br></pre><pre>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br></pre><pre>+ * GNU Lesser General Public License for more details.<br></pre><pre>+ *<br></pre><pre>+ * You should have received a copy of the GNU Lesser General Public <br></pre><pre>License<br></pre><pre>+ * along with this program; if not, write to the Free Software <br></pre><pre>Foundation,<br></pre><pre>+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.<br></pre><pre>+ <br></pre><pre>*****************************************************************************/<br></pre><pre>+<br></pre><pre>+#ifdef HAVE_CONFIG_H<br></pre><pre>+# include "config.h"<br></pre><pre>+#endif<br></pre><pre>+<br></pre><pre>+#include "dlna.hpp"<br></pre><pre>+<br></pre><pre>+#include <vector><br></pre><pre>+#include <string><br></pre><pre>+#include <sstream><br></pre><pre>+<br></pre><pre>+#include <vlc_plugin.h><br></pre><pre>+#include <vlc_renderer_discovery.h><br></pre><pre>+#include <vlc_sout.h><br></pre><pre>+<br></pre><pre>+const char* AV_TRANSPORT_SERVICE_TYPE = <br></pre><pre>"urn:schemas-upnp-org:service:AVTransport:1";<br></pre><pre>+const char* CONNECTION_MANAGER_SERVICE_TYPE = <br></pre><pre>"urn:schemas-upnp-org:service:ConnectionManager:1";<br></pre><pre>+<br></pre><pre>+static const char *const ppsz_sout_options[] = {<br></pre><pre>+    "ip", "port", "http-port", "mux", "mime", "video", "base_url", <br></pre><pre>"url", NULL<br></pre><pre>+};<br></pre><pre>+<br></pre><pre>+struct sout_stream_id_sys_t<br></pre><pre>+{<br></pre><pre>+    es_format_t           fmt;<br></pre><pre>+    sout_stream_id_sys_t  *p_sub_id;<br></pre><pre>+};<br></pre><pre>+<br></pre><pre>+struct sout_stream_sys_t<br></pre><pre>+{<br></pre><pre>+    sout_stream_sys_t(int http_port, bool supports_video,<br></pre><pre>+            std::string default_mux, std::string default_mime)<br></pre><pre>+        : p_out(NULL)<br></pre><pre>+        , default_muxer(default_mux)<br></pre><pre>+        , default_mime(default_mime)<br></pre><pre>+        , b_supports_video(supports_video)<br></pre><pre>+        , es_changed(true)<br></pre><pre>+        , http_port(http_port)<br></pre><pre>+    {<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    std::shared_ptr<Sout::MediaRenderer> renderer;<br></pre><pre>+    UpnpInstanceWrapper *p_upnp;<br></pre><pre>+<br></pre><pre>+    bool canDecodeAudio( vlc_fourcc_t i_codec ) const;<br></pre><pre>+    bool canDecodeVideo( vlc_fourcc_t i_codec ) const;<br></pre><pre>+    bool startSoutChain( sout_stream_t* p_stream,<br></pre><pre>+                         const std::vector<sout_stream_id_sys_t*> <br></pre><pre>&new_streams,<br></pre><pre>+                         const std::string &sout );<br></pre><pre>+    void stopSoutChain( sout_stream_t* p_stream );<br></pre><pre>+    sout_stream_id_sys_t *GetSubId( sout_stream_t *p_stream,<br></pre><pre>+                                    sout_stream_id_sys_t *id,<br></pre><pre>+                                    bool update = true );<br></pre><pre>+<br></pre><pre>+    sout_stream_t                       *p_out;<br></pre><pre>+    std::string                         default_muxer;<br></pre><pre>+    std::string                         default_mime;<br></pre><pre>+    bool                                b_supports_video;<br></pre><pre>+    bool                                es_changed;<br></pre><pre>+    int                                 http_port;<br></pre><pre>+    std::vector<sout_stream_id_sys_t*>  streams;<br></pre><pre>+    std::vector<sout_stream_id_sys_t*>  out_streams;<br></pre><pre>+<br></pre><pre>+    int UpdateOutput( sout_stream_t *p_stream );<br></pre><pre>+<br></pre><pre>+};<br></pre><pre>+<br></pre><pre>+bool sout_stream_sys_t::canDecodeAudio(vlc_fourcc_t i_codec) const<br></pre><pre>+{<br></pre><pre>+    return i_codec == VLC_CODEC_VORBIS ||<br></pre><pre>+        i_codec == VLC_CODEC_MP4A ||<br></pre><pre>+        i_codec == VLC_FOURCC('h', 'a', 'a', 'c') ||<br></pre><pre>+        i_codec == VLC_FOURCC('l', 'a', 'a', 'c') ||<br></pre><pre>+        i_codec == VLC_FOURCC('s', 'a', 'a', 'c') ||<br></pre><pre>+        i_codec == VLC_CODEC_OPUS ||<br></pre><pre>+        i_codec == VLC_CODEC_MP3 ||<br></pre><pre>+        i_codec == VLC_CODEC_A52 ||<br></pre><pre>+        i_codec == VLC_CODEC_EAC3;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+bool sout_stream_sys_t::canDecodeVideo(vlc_fourcc_t i_codec) const<br></pre><pre>+{<br></pre><pre>+    return i_codec == VLC_CODEC_H264 || i_codec == VLC_CODEC_VP8;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+bool sout_stream_sys_t::startSoutChain(sout_stream_t *p_stream,<br></pre><pre>+                                       const <br></pre><pre>std::vector<sout_stream_id_sys_t*> &new_streams,<br></pre><pre>+                                       const std::string &sout)<br></pre><pre>+{<br></pre><pre>+    stopSoutChain( p_stream );<br></pre><pre>+<br></pre><pre>+    msg_Dbg( p_stream, "Creating chain %s", sout.c_str() );<br></pre><pre>+    out_streams = new_streams;<br></pre><pre>+<br></pre><pre>+    p_out = sout_StreamChainNew( p_stream->p_sout, sout.c_str(), NULL, <br></pre><pre>NULL);<br></pre><pre>+    if (p_out == NULL) {<br></pre><pre>+        msg_Dbg(p_stream, "could not create sout chain:%s", <br></pre><pre>sout.c_str());<br></pre><pre>+        out_streams.clear();<br></pre><pre>+        return false;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    /* check the streams we can actually add */<br></pre><pre>+    for (std::vector<sout_stream_id_sys_t*>::iterator it = <br></pre><pre>out_streams.begin();<br></pre><pre>+            it != out_streams.end(); )<br></pre><pre>+    {<br></pre><pre>+        sout_stream_id_sys_t *p_sys_id = *it;<br></pre><pre>+        p_sys_id->p_sub_id = static_cast<sout_stream_id_sys_t *>(<br></pre><pre>+                sout_StreamIdAdd( p_out, &p_sys_id->fmt ) );<br></pre><pre>+        if ( p_sys_id->p_sub_id == NULL )<br></pre><pre>+        {<br></pre><pre>+            msg_Err( p_stream, "can't handle %4.4s stream",<br></pre><pre>+                    (char *)&p_sys_id->fmt.i_codec );<br></pre><pre>+            es_format_Clean( &p_sys_id->fmt );<br></pre><pre>+            it = out_streams.erase( it );<br></pre><pre>+        }<br></pre><pre>+        else<br></pre><pre>+            ++it;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    if (out_streams.empty())<br></pre><pre>+    {<br></pre><pre>+        stopSoutChain( p_stream );<br></pre><pre>+        return false;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    return true;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+void sout_stream_sys_t::stopSoutChain(sout_stream_t *p_stream)<br></pre><pre>+{<br></pre><pre>+    (void) p_stream;<br></pre><pre>+<br></pre><pre>+    if ( unlikely( p_out != NULL ) )<br></pre><pre>+    {<br></pre><pre>+        for ( size_t i = 0; i < out_streams.size(); i++ )<br></pre><pre>+        {<br></pre><pre>+            if ( out_streams[i]->p_sub_id != NULL )<br></pre><pre>+            {<br></pre><pre>+                sout_StreamIdDel( p_out, out_streams[i]->p_sub_id );<br></pre><pre>+                out_streams[i]->p_sub_id = NULL;<br></pre><pre>+            }<br></pre><pre>+        }<br></pre><pre>+        out_streams.clear();<br></pre><pre>+        sout_StreamChainDelete( p_out, NULL );<br></pre><pre>+        p_out = NULL;<br></pre><pre>+    }<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+sout_stream_id_sys_t *sout_stream_sys_t::GetSubId( sout_stream_t <br></pre><pre>*p_stream,<br></pre><pre>+                                                   sout_stream_id_sys_t <br></pre><pre>*id,<br></pre><pre>+                                                   bool update)<br></pre><pre>+{<br></pre><pre>+    size_t i;<br></pre><pre>+<br></pre><pre>+    assert( p_stream->p_sys == this );<br></pre><pre>+<br></pre><pre>+    if ( update && UpdateOutput( p_stream ) != VLC_SUCCESS )<br></pre><pre>+        return NULL;<br></pre><pre>+<br></pre><pre>+    for (i = 0; i < out_streams.size(); ++i)<br></pre><pre>+    {<br></pre><pre>+        if ( id == (sout_stream_id_sys_t*) out_streams[i] )<br></pre><pre>+            return out_streams[i]->p_sub_id;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    msg_Err( p_stream, "unknown stream ID" );<br></pre><pre>+    return NULL;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+int sout_stream_sys_t::UpdateOutput( sout_stream_t *p_stream )<br></pre><pre>+{<br></pre><pre>+    assert( p_stream->p_sys == this );<br></pre><pre>+<br></pre><pre>+    if ( !es_changed )<br></pre><pre>+        return VLC_SUCCESS;<br></pre><pre>+<br></pre><pre>+    es_changed = false;<br></pre><pre>+<br></pre><pre>+    bool canRemux = true;<br></pre><pre>+    vlc_fourcc_t i_codec_video = 0, i_codec_audio = 0;<br></pre><pre>+    std::vector<sout_stream_id_sys_t*> new_streams;<br></pre><pre>+<br></pre><pre>+    for (std::vector<sout_stream_id_sys_t*>::iterator it = <br></pre><pre>streams.begin();<br></pre><pre>+            it != streams.end(); ++it)<br></pre><pre>+    {<br></pre><pre>+        const es_format_t *p_es = &(*it)->fmt;<br></pre><pre>+        if (p_es->i_cat == AUDIO_ES)<br></pre><pre>+        {<br></pre><pre>+            if (!canDecodeAudio( p_es->i_codec ))<br></pre><pre>+            {<br></pre><pre>+                msg_Dbg( p_stream, "can't remux audio track %d codec <br></pre><pre>%4.4s",<br></pre><pre>+                        p_es->i_id, (const char*)&p_es->i_codec );<br></pre><pre>+                canRemux = false;<br></pre><pre>+            }<br></pre><pre>+            else if (i_codec_audio == 0)<br></pre><pre>+            {<br></pre><pre>+                i_codec_audio = p_es->i_codec;<br></pre><pre>+            }<br></pre><pre>+            new_streams.push_back(*it);<br></pre><pre>+        }<br></pre><pre>+        else if (b_supports_video && p_es->i_cat == VIDEO_ES)<br></pre><pre>+        {<br></pre><pre>+            if (!canDecodeVideo( p_es->i_codec ))<br></pre><pre>+            {<br></pre><pre>+                msg_Dbg( p_stream, "can't remux video track %d codec <br></pre><pre>%4.4s",<br></pre><pre>+                        p_es->i_id, (const char*)&p_es->i_codec );<br></pre><pre>+                canRemux = false;<br></pre><pre>+            }<br></pre><pre>+            else if (i_codec_video == 0)<br></pre><pre>+            {<br></pre><pre>+                i_codec_video = p_es->i_codec;<br></pre><pre>+            }<br></pre><pre>+            new_streams.push_back(*it);<br></pre><pre>+        }<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    if (new_streams.empty())<br></pre><pre>+    {<br></pre><pre>+        return VLC_SUCCESS;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    std::stringstream ssout;<br></pre><pre>+    if ( !canRemux )<br></pre><pre>+    {<br></pre><pre>+        /* TODO: provide audio samplerate and channels */<br></pre><pre>+        ssout << "transcode{";<br></pre><pre>+        char s_fourcc[5];<br></pre><pre>+        if ( i_codec_audio == 0 )<br></pre><pre>+        {<br></pre><pre>+            i_codec_audio = DEFAULT_TRANSCODE_AUDIO;<br></pre><pre>+            msg_Dbg( p_stream, "Converting audio to %.4s",<br></pre><pre>+                    (const char*)&i_codec_audio );<br></pre><pre>+            ssout << "acodec=";<br></pre><pre>+            vlc_fourcc_to_char( i_codec_audio, s_fourcc );<br></pre><pre>+            s_fourcc[4] = '\0';<br></pre><pre>+            ssout << s_fourcc << ',';<br></pre><pre>+        }<br></pre><pre>+        if ( b_supports_video && i_codec_video == 0 )<br></pre><pre>+        {<br></pre><pre>+            i_codec_video = DEFAULT_TRANSCODE_VIDEO;<br></pre><pre>+            msg_Dbg( p_stream, "Converting video to %.4s",<br></pre><pre>+                    (const char*)&i_codec_video );<br></pre><pre>+            /* TODO: provide maxwidth,maxheight */<br></pre><pre>+            ssout << "vcodec=";<br></pre><pre>+            vlc_fourcc_to_char( i_codec_video, s_fourcc );<br></pre><pre>+            s_fourcc[4] = '\0';<br></pre><pre>+            ssout << s_fourcc;<br></pre><pre>+        }<br></pre><pre>+        ssout << "}:";<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    std::string mime;<br></pre><pre>+    if ( !b_supports_video && default_muxer == DEFAULT_MUXER )<br></pre><pre>+        mime = "audio/x-matroska";<br></pre><pre>+    else if ( i_codec_audio == VLC_CODEC_VORBIS &&<br></pre><pre>+              i_codec_video == VLC_CODEC_VP8 &&<br></pre><pre>+              default_muxer == DEFAULT_MUXER )<br></pre><pre>+        mime = "video/webm";<br></pre><pre>+    else<br></pre><pre>+        mime = default_mime;<br></pre><pre>+<br></pre><pre>+    ssout << "http{dst=:" << http_port << "/stream.mp4"<br></pre><pre>+          << ",mux=" << default_muxer<br></pre><pre>+          << ",access=http{mime=" << mime << "}}";<br></pre><pre>+<br></pre><pre>+    if ( !startSoutChain( p_stream, new_streams, ssout.str() ) )<br></pre><pre>+        return VLC_EGENERIC;<br></pre><pre>+<br></pre><pre>+    char *ip = getIpv4ForMulticast();<br></pre><pre>+    if (ip == NULL)<br></pre><pre>+    {<br></pre><pre>+        ip = UpnpGetServerIpAddress();<br></pre><pre>+    }<br></pre><pre>+    if (ip == NULL)<br></pre><pre>+    {<br></pre><pre>+        msg_Err(p_stream, "could not get the local ip address");<br></pre><pre>+        return VLC_EGENERIC;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    char *uri;<br></pre><pre>+    if (asprintf(&uri, "<a href="http://%s:%d/stream.mp4">http://%s:%d/stream.mp4</a>", ip, http_port) < 0) {<br></pre><pre>+        return VLC_ENOMEM;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    msg_Dbg(p_stream, "AVTransportURI: %s", uri);<br></pre><pre>+    renderer->SetAVTransportURI(uri);<br></pre><pre>+    renderer->Play("1");<br></pre><pre>+<br></pre><pre>+    return VLC_SUCCESS;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+namespace Sout<br></pre><pre>+{<br></pre><pre>+<br></pre><pre>+char *MediaRenderer::getServiceURL(const char* type, const char <br></pre><pre>*service)<br></pre><pre>+{<br></pre><pre>+    IXML_Document *p_description_doc = NULL;<br></pre><pre>+<br></pre><pre>+    UpnpDownloadXmlDoc(device_url.c_str(), &p_description_doc);<br></pre><pre>+    if (!p_description_doc)<br></pre><pre>+        return NULL;<br></pre><pre>+<br></pre><pre>+    IXML_NodeList* p_device_list = <br></pre><pre>ixmlDocument_getElementsByTagName( p_description_doc, "device");<br></pre><pre>+    if ( !p_device_list)<br></pre><pre>+        return NULL;<br></pre><pre>+    for (unsigned int i = 0; i < ixmlNodeList_length(p_device_list); +<br></pre><pre>+i)<br></pre><pre>+    {<br></pre><pre>+        IXML_Element* p_device_element = ( IXML_Element* ) <br></pre><pre>ixmlNodeList_item( p_device_list, i );<br></pre><pre>+        if( !p_device_element )<br></pre><pre>+            continue;<br></pre><pre>+<br></pre><pre>+        IXML_NodeList* p_service_list = <br></pre><pre>ixmlElement_getElementsByTagName( p_device_element, "service" );<br></pre><pre>+        if ( !p_service_list )<br></pre><pre>+            continue;<br></pre><pre>+        for ( unsigned int j = 0; j < <br></pre><pre>ixmlNodeList_length( p_service_list ); j++ )<br></pre><pre>+        {<br></pre><pre>+            IXML_Element* p_service_element = <br></pre><pre>(IXML_Element*)ixmlNodeList_item( p_service_list, j );<br></pre><pre>+<br></pre><pre>+            const char* psz_service_type = <br></pre><pre>xml_getChildElementValue( p_service_element, "serviceType" );<br></pre><pre>+            if ( !psz_service_type || !strstr(psz_service_type, type))<br></pre><pre>+                continue;<br></pre><pre>+            const char* psz_control_url = <br></pre><pre>xml_getChildElementValue( p_service_element,<br></pre><pre>+                                                                    <br></pre><pre>service );<br></pre><pre>+            if ( !psz_control_url )<br></pre><pre>+                continue;<br></pre><pre>+<br></pre><pre>+            char* psz_url = ( char* ) malloc( base_url.length() + <br></pre><pre>strlen( psz_control_url ) + 1 );<br></pre><pre>+            if ( psz_url )<br></pre><pre>+            {<br></pre><pre>+                if ( UpnpResolveURL( base_url.c_str(), psz_control_url, <br></pre><pre>psz_url ) == UPNP_E_SUCCESS )<br></pre><pre>+                    return psz_url;<br></pre><pre>+            }<br></pre><pre>+            free(psz_url);<br></pre><pre>+            return NULL;<br></pre><pre>+        }<br></pre><pre>+    }<br></pre><pre>+    return NULL;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+/**<br></pre><pre>+ * Send an action to the control url of the service specified.<br></pre><pre>+ *<br></pre><pre>+ * \return the response as a IXML document or NULL for failure<br></pre><pre>+ **/<br></pre><pre>+IXML_Document *MediaRenderer::SendAction(const char* action_name,const <br></pre><pre>char *service_type,<br></pre><pre>+                    std::list<std::pair<const char*, const char*>> <br></pre><pre>arguments)<br></pre><pre>+{<br></pre><pre>+<br></pre><pre>+    int ret;<br></pre><pre>+    IXML_Document *action = NULL, *response = NULL;<br></pre><pre>+<br></pre><pre>+    /* Create action */<br></pre><pre>+    action = UpnpMakeAction(action_name, service_type, 0, NULL);<br></pre><pre>+<br></pre><pre>+    /* Add argument to action */<br></pre><pre>+    std::list<std::pair<const char*, const char*>>::iterator arg;<br></pre><pre>+    for (arg=arguments.begin(); arg != arguments.end(); ++arg) {<br></pre><pre>+      const char *arg_name, *arg_val;<br></pre><pre>+      arg_name = arg->first;<br></pre><pre>+      arg_val  = arg->second;<br></pre><pre>+      UpnpAddToAction(&action, action_name, service_type, arg_name, <br></pre><pre>arg_val);<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    /* Get the controlURL of the service */<br></pre><pre>+    char *control_url = getServiceURL(service_type, "controlURL");<br></pre><pre>+<br></pre><pre>+    /* Send action */<br></pre><pre>+    ret = UpnpSendAction(handle, control_url, service_type,<br></pre><pre>+                                    NULL, action, &response);<br></pre><pre>+<br></pre><pre>+    /* Free action */<br></pre><pre>+    if (action) ixmlDocument_free(action);<br></pre><pre>+    if (control_url) free(control_url);<br></pre><pre>+<br></pre><pre>+    if (ret != UPNP_E_SUCCESS) {<br></pre><pre>+        msg_Err(parent, "Unable to send action: %d (%s)\n", ret, <br></pre><pre>UpnpGetErrorMessage(ret));<br></pre><pre>+        if (response) ixmlDocument_free(response);<br></pre><pre>+        return NULL;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    return response;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+int MediaRenderer::Play(const char *speed)<br></pre><pre>+{<br></pre><pre>+    IXML_Document* p_response = NULL;<br></pre><pre>+    std::list<std::pair<const char*, const char*>> arg_list;<br></pre><pre>+    arg_list.push_back(std::make_pair("InstanceID", "0"));<br></pre><pre>+    arg_list.push_back(std::make_pair("Speed", speed));<br></pre><pre>+<br></pre><pre>+    p_response = SendAction("Play", AV_TRANSPORT_SERVICE_TYPE, <br></pre><pre>arg_list);<br></pre><pre>+    ixmlDocument_free(p_response);<br></pre><pre>+    return VLC_SUCCESS;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+int MediaRenderer::Stop()<br></pre><pre>+{<br></pre><pre>+    IXML_Document* p_response = NULL;<br></pre><pre>+    std::list<std::pair<const char*, const char*>> arg_list;<br></pre><pre>+    arg_list.push_back(std::make_pair("InstanceID", "0"));<br></pre><pre>+<br></pre><pre>+    p_response = SendAction("Stop", AV_TRANSPORT_SERVICE_TYPE, <br></pre><pre>arg_list);<br></pre><pre>+    ixmlDocument_free(p_response);<br></pre><pre>+    return VLC_SUCCESS;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+int MediaRenderer::SetAVTransportURI(const char* uri)<br></pre><pre>+{<br></pre><pre>+    IXML_Document* p_response = NULL;<br></pre><pre>+    std::list<std::pair<const char*, const char*>> arg_list;<br></pre><pre>+    arg_list.push_back(std::make_pair("InstanceID", "0"));<br></pre><pre>+    arg_list.push_back(std::make_pair("CurrentURI", uri));<br></pre><pre>+    arg_list.push_back(std::make_pair("CurrentURIMetaData", "")); // <br></pre><pre>NOT_IMPLEMENTED<br></pre><pre>+<br></pre><pre>+    p_response = SendAction("SetAVTransportURI", <br></pre><pre>AV_TRANSPORT_SERVICE_TYPE, arg_list);<br></pre><pre>+    ixmlDocument_free(p_response);<br></pre><pre>+    return VLC_SUCCESS;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+static void *Add(sout_stream_t *p_stream, const es_format_t *p_fmt)<br></pre><pre>+{<br></pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t <br></pre><pre>*>( p_stream->p_sys );<br></pre><pre>+<br></pre><pre>+    if (!p_sys->b_supports_video)<br></pre><pre>+    {<br></pre><pre>+        if (p_fmt->i_cat != AUDIO_ES)<br></pre><pre>+            return NULL;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    sout_stream_id_sys_t *p_sys_id = (sout_stream_id_sys_t <br></pre><pre>*)malloc(sizeof(sout_stream_id_sys_t));<br></pre><pre>+    if(p_sys_id != NULL)<br></pre><pre>+    {<br></pre><pre>+        es_format_Copy(&p_sys_id->fmt, p_fmt);<br></pre><pre>+        p_sys_id->p_sub_id = NULL;<br></pre><pre>+        p_sys->streams.push_back(p_sys_id);<br></pre><pre>+        p_sys->es_changed = true;<br></pre><pre>+    }<br></pre><pre>+    return p_sys_id;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+static int Send(sout_stream_t *p_stream, void *id,<br></pre><pre>+                block_t *p_buffer)<br></pre><pre>+{<br></pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t <br></pre><pre>*>( p_stream->p_sys );<br></pre><pre>+    sout_stream_id_sys_t *id_sys = <br></pre><pre>static_cast<sout_stream_id_sys_t*>( id );<br></pre><pre>+<br></pre><pre>+    id_sys = p_sys->GetSubId( p_stream, id_sys );<br></pre><pre>+    if ( id_sys == NULL )<br></pre><pre>+        return VLC_EGENERIC;<br></pre><pre>+<br></pre><pre>+    return sout_StreamIdSend(p_sys->p_out, id_sys, p_buffer);<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+static void Flush( sout_stream_t *p_stream, void *id )<br></pre><pre>+{<br></pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t <br></pre><pre>*>( p_stream->p_sys );<br></pre><pre>+    sout_stream_id_sys_t *id_sys = <br></pre><pre>static_cast<sout_stream_id_sys_t*>( id );<br></pre><pre>+<br></pre><pre>+    id_sys = p_sys->GetSubId( p_stream, id_sys, false );<br></pre><pre>+    if ( id_sys == NULL )<br></pre><pre>+        return;<br></pre><pre>+<br></pre><pre>+    sout_StreamFlush( p_sys->p_out, id_sys );<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+static int Control(sout_stream_t *p_stream, int i_query, va_list args)<br></pre><pre>+{<br></pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t <br></pre><pre>*>( p_stream->p_sys );<br></pre><pre>+<br></pre><pre>+    if (i_query == SOUT_STREAM_EMPTY)<br></pre><pre>+        return VLC_SUCCESS;<br></pre><pre>+    if (!p_sys->p_out->pf_control)<br></pre><pre>+        return VLC_EGENERIC;<br></pre><pre>+    return p_sys->p_out->pf_control(p_sys->p_out, i_query, args);<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+static void Del(sout_stream_t *p_stream, void *_id)<br></pre><pre>+{<br></pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t <br></pre><pre>*>( p_stream->p_sys );<br></pre><pre>+    sout_stream_id_sys_t *id = static_cast<sout_stream_id_sys_t <br></pre><pre>*>( _id );<br></pre><pre>+<br></pre><pre>+    for (std::vector<sout_stream_id_sys_t*>::iterator it = p_sys-<br></pre><pre><br></pre><pre>streams.begin();<br></pre><pre>+         it != p_sys->streams.end(); )<br></pre><pre>+    {<br></pre><pre>+        sout_stream_id_sys_t *p_sys_id = *it;<br></pre><pre>+        if ( p_sys_id == id )<br></pre><pre>+        {<br></pre><pre>+            if ( p_sys_id->p_sub_id != NULL )<br></pre><pre>+            {<br></pre><pre>+                sout_StreamIdDel( p_sys->p_out, p_sys_id->p_sub_id );<br></pre><pre>+                for (std::vector<sout_stream_id_sys_t*>::iterator <br></pre><pre>out_it = p_sys->out_streams.begin();<br></pre><pre>+                     out_it != p_sys->out_streams.end(); )<br></pre><pre>+                {<br></pre><pre>+                    if (*out_it == id)<br></pre><pre>+                    {<br></pre><pre>+                        p_sys->out_streams.erase(out_it);<br></pre><pre>+                        break;<br></pre><pre>+                    }<br></pre><pre>+                    out_it++;<br></pre><pre>+                }<br></pre><pre>+            }<br></pre><pre>+<br></pre><pre>+            es_format_Clean( &p_sys_id->fmt );<br></pre><pre>+            free( p_sys_id );<br></pre><pre>+            p_sys->streams.erase( it );<br></pre><pre>+            break;<br></pre><pre>+        }<br></pre><pre>+        it++;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    if (p_sys->out_streams.empty())<br></pre><pre>+    {<br></pre><pre>+        p_sys->stopSoutChain(p_stream);<br></pre><pre>+        p_sys->renderer->Stop();<br></pre><pre>+    }<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+int OpenSout( vlc_object_t *p_this )<br></pre><pre>+{<br></pre><pre>+    sout_stream_t *p_stream = reinterpret_cast<sout_stream_t*>(p_this);<br></pre><pre>+    sout_stream_sys_t *p_sys = NULL;<br></pre><pre>+    bool b_supports_video = true;<br></pre><pre>+    char *default_muxer = NULL;<br></pre><pre>+    char *default_mime = NULL;<br></pre><pre>+    char *base_url = NULL;<br></pre><pre>+    char *device_url = NULL;<br></pre><pre>+    int http_port;<br></pre><pre>+<br></pre><pre>+    config_ChainParse(p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, <br></pre><pre>p_stream->p_cfg);<br></pre><pre>+<br></pre><pre>+    http_port = var_InheritInteger(p_stream, SOUT_CFG_PREFIX "http-<br></pre><pre>port");<br></pre><pre>+    b_supports_video = var_GetBool(p_stream, SOUT_CFG_PREFIX "video");<br></pre><pre>+    default_muxer = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX <br></pre><pre>"mux");<br></pre><pre>+    default_mime = var_GetNonEmptyString(p_stream,  SOUT_CFG_PREFIX <br></pre><pre>"mime");<br></pre><pre>+<br></pre><pre>+    try {<br></pre><pre>+        p_sys = new sout_stream_sys_t(http_port, b_supports_video,<br></pre><pre>+                                        default_muxer, default_mime);<br></pre><pre>+    } catch ( std::exception& ex ) {<br></pre><pre>+        msg_Err( p_stream, "Failed to instantiate sout_stream_sys_t: <br></pre><pre>%s", ex.what() );<br></pre><pre>+        return VLC_EGENERIC;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    base_url = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX <br></pre><pre>"base_url");<br></pre><pre>+    device_url = var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX <br></pre><pre>"url");<br></pre><pre>+    if ( device_url == NULL)<br></pre><pre>+    {<br></pre><pre>+        msg_Err( p_stream, "missing Url" );<br></pre><pre>+        goto error;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    p_sys->p_upnp = UpnpInstanceWrapper::get( p_this );<br></pre><pre>+    if ( !p_sys->p_upnp )<br></pre><pre>+        goto error;<br></pre><pre>+    try {<br></pre><pre>+        p_sys->renderer = <br></pre><pre>std::make_shared<Sout::MediaRenderer>(p_stream,<br></pre><pre>+                            p_sys->p_upnp, base_url, device_url);<br></pre><pre>+    }<br></pre><pre>+    catch (const std::bad_alloc&) {<br></pre><pre>+        msg_Err( p_stream, "Failed to create a MediaRenderer");<br></pre><pre>+        p_sys->p_upnp->release();<br></pre><pre>+        goto error;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    p_stream->pf_add     = Add;<br></pre><pre>+    p_stream->pf_del     = Del;<br></pre><pre>+    p_stream->pf_send    = Send;<br></pre><pre>+    p_stream->pf_flush   = Flush;<br></pre><pre>+    p_stream->pf_control = Control;<br></pre><pre>+<br></pre><pre>+    p_stream->p_sys = p_sys;<br></pre><pre>+<br></pre><pre>+    free(default_mime);<br></pre><pre>+    free(default_muxer);<br></pre><pre>+    free(base_url);<br></pre><pre>+    free(device_url);<br></pre><pre>+<br></pre><pre>+    return VLC_SUCCESS;<br></pre><pre>+<br></pre><pre>+error:<br></pre><pre>+    free(default_mime);<br></pre><pre>+    free(default_muxer);<br></pre><pre>+    free(base_url);<br></pre><pre>+    free(device_url);<br></pre><pre>+    delete p_sys;<br></pre><pre>+    return VLC_EGENERIC;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+void CloseSout( vlc_object_t *p_this)<br></pre><pre>+{<br></pre><pre>+    sout_stream_t *p_stream = <br></pre><pre>reinterpret_cast<sout_stream_t*>( p_this );<br></pre><pre>+    sout_stream_sys_t *p_sys = static_cast<sout_stream_sys_t <br></pre><pre>*>( p_stream->p_sys );<br></pre><pre>+<br></pre><pre>+    p_sys->p_upnp->release();<br></pre><pre>+    delete p_sys;<br></pre><pre>+}<br></pre><pre>+<br></pre><pre>+}<br></pre><pre>diff --git a/modules/stream_out/dlna.hpp b/modules/stream_out/dlna.hpp<br></pre><pre>new file mode 100644<br></pre><pre>index 0000000000..9f966b8237<br></pre><pre>--- /dev/null<br></pre><pre>+++ b/modules/stream_out/dlna.hpp<br></pre><pre>@@ -0,0 +1,94 @@<br></pre><pre>+/<br></pre><pre>*****************************************************************************<br></pre><pre>+ * dlna.hpp : DLNA/UPNP (renderer) sout module header<br></pre><pre>+ <br></pre><pre>*****************************************************************************<br></pre><pre>+ * Copyright (C) 2004-2018 VLC authors and VideoLAN<br></pre><pre>+ *<br></pre><pre>+ * Authors: William Ung <<a href="mailto:william1.ung@epitech.eu">william1.ung@epitech.eu</a>><br></pre><pre>+ *          Shaleen Jain <<a href="mailto:shaleen@jain.sh">shaleen@jain.sh</a>><br></pre><pre>+ *<br></pre><pre>+ * This program is free software; you can redistribute it and/or modify <br></pre><pre>it<br></pre><pre>+ * under the terms of the GNU Lesser General Public License as <br></pre><pre>published by<br></pre><pre>+ * the Free Software Foundation; either version 2.1 of the License, or<br></pre><pre>+ * (at your option) any later version.<br></pre><pre>+ *<br></pre><pre>+ * This program is distributed in the hope that it will be useful,<br></pre><pre>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br></pre><pre>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br></pre><pre>+ * GNU Lesser General Public License for more details.<br></pre><pre>+ *<br></pre><pre>+ * You should have received a copy of the GNU Lesser General Public <br></pre><pre>License<br></pre><pre>+ * along with this program; if not, write to the Free Software <br></pre><pre>Foundation,<br></pre><pre>+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.<br></pre><pre>+ <br></pre><pre>*****************************************************************************/<br></pre><pre>+<br></pre><pre>+#include "../services_discovery/upnp-wrapper.hpp"<br></pre><pre>+<br></pre><pre>+#include <list><br></pre><pre>+<br></pre><pre>+#include <vlc_fourcc.h><br></pre><pre>+<br></pre><pre>+#define SOUT_CFG_PREFIX "sout-upnp-"<br></pre><pre>+<br></pre><pre>+#define HTTP_PORT         8080<br></pre><pre>+<br></pre><pre>+#define HTTP_PORT_TEXT N_("HTTP port")<br></pre><pre>+#define HTTP_PORT_LONGTEXT N_("This sets the HTTP port of the local <br></pre><pre>server used to stream the media to the UPnP Renderer.")<br></pre><pre>+#define HAS_VIDEO_TEXT N_("Video")<br></pre><pre>+#define HAS_VIDEO_LONGTEXT N_("The UPnP Renderer can receive video.")<br></pre><pre>+#define MUX_TEXT N_("Muxer")<br></pre><pre>+#define MUX_LONGTEXT N_("This sets the muxer used to stream to the UPnP <br></pre><pre>Renderer.")<br></pre><pre>+#define MIME_TEXT N_("MIME content type")<br></pre><pre>+#define MIME_LONGTEXT N_("This sets the media MIME content type sent to <br></pre><pre>the UPnP Renderer.")<br></pre><pre>+<br></pre><pre>+#define IP_ADDR_TEXT N_("IP Address")<br></pre><pre>+#define IP_ADDR_LONGTEXT N_("IP Address of the UPnP Renderer.")<br></pre><pre>+#define PORT_TEXT N_("UPnP Renderer port")<br></pre><pre>+#define PORT_LONGTEXT N_("The port used to talk to the UPnP Renderer.")<br></pre><pre>+#define BASE_URL_TEXT N_("base URL")<br></pre><pre>+#define BASE_URL_LONGTEXT N_("The base Url relative to which all other <br></pre><pre>UPnP operations must be called")<br></pre><pre>+#define URL_TEXT N_("description URL")<br></pre><pre>+#define URL_LONGTEXT N_("The Url used to get the xml descriptor of the <br></pre><pre>UPnP Renderer")<br></pre><pre>+<br></pre><pre>+static const vlc_fourcc_t DEFAULT_TRANSCODE_AUDIO = VLC_CODEC_MP3;<br></pre><pre>+static const vlc_fourcc_t DEFAULT_TRANSCODE_VIDEO = VLC_CODEC_H264;<br></pre><pre>+static const char DEFAULT_MUXER[] = <br></pre><pre>"avformat{mux=matroska,options={live=1}}}";<br></pre><pre>+<br></pre><pre>+namespace Sout<br></pre><pre>+{<br></pre><pre>+<br></pre><pre>+/* module callbacks */<br></pre><pre>+int OpenSout(vlc_object_t *);<br></pre><pre>+void CloseSout(vlc_object_t *);<br></pre><pre>+<br></pre><pre>+class MediaRenderer<br></pre><pre>+{<br></pre><pre>+public:<br></pre><pre>+    MediaRenderer(sout_stream_t *p_stream, UpnpInstanceWrapper *upnp,<br></pre><pre>+            std::string base_url, std::string device_url)<br></pre><pre>+        : parent(p_stream)<br></pre><pre>+        , base_url(base_url)<br></pre><pre>+        , device_url(device_url)<br></pre><pre>+        , handle(upnp->handle())<br></pre><pre>+    {<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    ~MediaRenderer()<br></pre><pre>+    {<br></pre><pre>+         parent = NULL;<br></pre><pre>+    }<br></pre><pre>+<br></pre><pre>+    sout_stream_t *parent;<br></pre><pre>+    std::string base_url;<br></pre><pre>+    std::string device_url;<br></pre><pre>+    UpnpClient_Handle handle;<br></pre><pre>+<br></pre><pre>+    char *getServiceURL(const char* type, const char* service);<br></pre><pre>+    IXML_Document *SendAction(const char* action_name, const char <br></pre><pre>*service_type,<br></pre><pre>+                    std::list<std::pair<const char*, const char*>> <br></pre><pre>arguments);<br></pre><pre>+<br></pre><pre>+    int Play(const char *speed);<br></pre><pre>+    int Stop();<br></pre><pre>+    int SetAVTransportURI(const char* uri);<br></pre><pre>+};<br></pre><pre>+<br></pre><pre>+}<br></pre><pre>-- <br></pre><pre>2.18.0<br></pre><pre>_______________________________________________<br></pre><pre>vlc-devel mailing list<br></pre><pre>To unsubscribe or modify your subscription options:<br></pre><pre><a href="https://mailman.videolan.org/listinfo/vlc-devel">https://mailman.videolan.org/listinfo/vlc-devel</a><br></pre><pre><br></pre><pre><br></pre><pre><br></pre></blockquote><div><div><span></span><br></div>
<pre><span>-- </span><br></pre><div style="width:71ch;"><span>Regards,</span><br></div>
<div style="width:71ch;"><span>Shaleen Jain</span><br></div>
<div><span></span><br></div>
</div>
</blockquote><div><br></div>
<div id="sig60240713"><div class="signature">--<br></div>
<div class="signature">Jean-Baptiste Kempf -  President<br></div>
<div class="signature">+33 672 704 734<br></div>
<div class="signature"> <br></div>
<div class="signature"><br></div>
</div>
<div><br></div>
</body>
</html>