[vlc-devel] [PATCH 4/5] dlna: add a DLNA stream out

Shaleen Jain shaleen at jain.sh
Wed Oct 17 16:38:02 CEST 2018


Hi,
On Mon, 2018-10-15 at 16:11 +0200, Steve Lhomme wrote:
> Hi,
> On 15/10/2018 10:18, Shaleen Jain wrote:
> > Add support for casting to a DLNA Media Rendererswhich implement
> > the AVTransport service with theinitial support of the default
> > media format.---  NEWS                                    |   1
> > +  modules/MODULES_LIST                    |   1
> > +  modules/services_discovery/Makefile.am  |   5
> > +-  modules/services_discovery/upnp.cpp     |  15
> > +  modules/services_discovery/upnp.hpp     |   1
> > +  modules/stream_out/dlna/dlna.cpp        | 569
> > ++++++++++++++++++++++++  modules/stream_out/dlna/dlna.hpp        |
> >   60 +++  modules/stream_out/dlna/dlna_common.hpp |  61 +++  8
> > files changed, 712 insertions(+), 1 deletion(-)  create mode 100644
> > modules/stream_out/dlna/dlna.cpp  create mode 100644
> > modules/stream_out/dlna/dlna.hpp  create mode 100644
> > modules/stream_out/dlna/dlna_common.hpp
> > diff --git a/NEWS b/NEWSindex 3054bb84a7..7fe0c4d39b 100644---
> > a/NEWS+++ b/NEWS@@ -40,6 +40,7 @@ Video output:  Stream output:   *
> > New SDI output with improved audio and ancillary
> > support.     Candidate for deprecation of decklink vout/aout
> > modules.+ * Support for DLNA/UPNP renderers    macOS:   * Remove
> > Growl notification supportdiff --git a/modules/MODULES_LIST
> > b/modules/MODULES_LISTindex 79161ae3ed..65815ed22e 100644---
> > a/modules/MODULES_LIST+++ b/modules/MODULES_LIST@@ -377,6 +377,7 @@
> > $Id$   * stream_out_delay: introduce delay in an ES when
> > streaming   * stream_out_description: helper module for RTSP
> > vod   * stream_out_display: displays a stream output chain+ *
> > stream_out_dlna: DLNA streaming output module   * stream_out_dummy:
> > dummy stream out chain module   * stream_out_duplicate: duplicates
> > a stream output chain   * stream_out_es: stream out module
> > outputing ESdiff --git a/modules/services_discovery/Makefile.am
> > b/modules/services_discovery/Makefile.amindex
> > f63df23b32..1b59cb1e4f 100644---
> > a/modules/services_discovery/Makefile.am+++
> > b/modules/services_discovery/Makefile.am@@ -28,7 +28,10 @@
> > sd_LTLIBRARIES += $(LTLIBmtp)    libupnp_plugin_la_SOURCES =
> > services_discovery/upnp.cpp services_discovery/upnp.hpp \  		
> > 	    services_discovery/upnp-wrapper.hpp \-			   
> >  services_discovery/upnp-wrapper.cpp+			    ser
> > vices_discovery/upnp-wrapper.cpp \+			    stream_out/
> > dlna/dlna_common.hpp \+			    stream_out/dlna/dln
> > a.hpp \+			    stream_out/dlna/dlna.cpp  libupnp_p
> > lugin_la_CXXFLAGS = $(AM_CXXFLAGS)
> > $(UPNP_CFLAGS)  libupnp_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath
> > '$(sddir)'  libupnp_plugin_la_LIBADD = $(UPNP_LIBS)diff --git
> > a/modules/services_discovery/upnp.cpp
> > b/modules/services_discovery/upnp.cppindex c1c2b947b2..b22f13bec8
> > 100644--- a/modules/services_discovery/upnp.cpp+++
> > b/modules/services_discovery/upnp.cpp@@ -147,6 +147,21 @@
> > vlc_module_begin()        VLC_RD_PROBE_SUBMODULE  +    add_submodul
> > e()+        set_shortname("dlna")+        set_description(N_("UPnP/
> > DLNA stream output"))+        set_capability("sout stream",
> > 0)+        add_shortcut("dlna")+        set_category(CAT_SOUT)+    
> >     set_subcategory(SUBCAT_SOUT_STREAM)+        set_callbacks(DLNA:
> > :OpenSout, DLNA::CloseSout)++        add_string(SOUT_CFG_PREFIX
> > "ip", NULL, IP_ADDR_TEXT, IP_ADDR_LONGTEXT,
> > false)+        add_integer(SOUT_CFG_PREFIX "port", NULL, PORT_TEXT,
> > PORT_LONGTEXT, false)+        add_integer(SOUT_CFG_PREFIX "http-
> > port", HTTP_PORT, HTTP_PORT_TEXT, HTTP_PORT_LONGTEXT,
> > false)+        add_bool(SOUT_CFG_PREFIX "video", true,
> > HAS_VIDEO_TEXT, HAS_VIDEO_LONGTEXT,
> > false)+        add_string(SOUT_CFG_PREFIX "base_url", NULL,
> > BASE_URL_TEXT, BASE_URL_LONGTEXT,
> > false)+        add_string(SOUT_CFG_PREFIX "url", NULL, URL_TEXT,
> > URL_LONGTEXT, false)  vlc_module_end()    /*diff --git
> > a/modules/services_discovery/upnp.hpp
> > b/modules/services_discovery/upnp.hppindex 5a0de1f284..3b2e80b209
> > 100644--- a/modules/services_discovery/upnp.hpp+++
> > b/modules/services_discovery/upnp.hpp@@ -33,6 +33,7
> > @@  #endif    #include "upnp-wrapper.hpp"+#include
> > "../stream_out/dlna/dlna_common.hpp"    #include
> > <vlc_url.h>  #include <vlc_interrupt.h>diff --git
> > a/modules/stream_out/dlna/dlna.cpp
> > b/modules/stream_out/dlna/dlna.cppnew file mode 100644index
> > 0000000000..43da65d055--- /dev/null+++
> > b/modules/stream_out/dlna/dlna.cpp@@ -0,0 +1,569
> > @@+/***************************************************************
> > **************+ * dlna.cpp : DLNA/UPNP (renderer) sout module+
> > *******************************************************************
> > **********+ * Copyright (C) 2004-2018 VLC authors and VideoLAN+ *+
> > * Authors: William Ung <william1.ung at epitech.eu>+
> > *          Shaleen Jain <shaleen at jain.sh>+ *+ * This program is
> > free software; you can redistribute it and/or modify it+ * under
> > the terms of the GNU Lesser General Public License as published by+
> > * the Free Software Foundation; either version 2.1 of the License,
> > or+ * (at your option) any later version.+ *+ * This program is
> > distributed in the hope that it will be useful,+ * but WITHOUT ANY
> > WARRANTY; without even the implied warranty of+ * MERCHANTABILITY
> > or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU Lesser General
> > Public License for more details.+ *+ * You should have received a
> > copy of the GNU Lesser General Public License+ * along with this
> > program; if not, write to the Free Software Foundation,+ * Inc., 51
> > Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.+
> > *******************************************************************
> > **********/++#ifdef HAVE_CONFIG_H+# include
> > "config.h"+#endif++#include "dlna.hpp"++#include <vector>+#include
> > <string>+#include <sstream>++#include <vlc_rand.h>+#include
> > <vlc_sout.h>++static const char* AV_TRANSPORT_SERVICE_TYPE =
> > "urn:schemas-upnp-org:service:AVTransport:1";+static const char*
> > CONNECTION_MANAGER_SERVICE_TYPE = "urn:schemas-upnp-
> > org:service:ConnectionManager:1";++static const char *const
> > ppsz_sout_options[] = {+    "ip", "port", "http-port", "video",
> > "base_url", "url", NULL+};++namespace DLNA+{++struct
> > sout_stream_id_sys_t+{+    es_format_t           fmt;+    sout_stre
> > am_id_sys_t  *p_sub_id;+};++struct
> > sout_stream_sys_t+{+    sout_stream_sys_t(int http_port, bool
> > supports_video)+        : p_out(NULL)+        ,
> > b_supports_video(supports_video)+        ,
> > es_changed(true)+        ,
> > http_port(http_port)+    {+    }++    std::shared_ptr<MediaRenderer
> > > renderer;+    UpnpInstanceWrapper *p_upnp;++    bool
> > canDecodeAudio( vlc_fourcc_t i_codec ) const;+    bool
> > canDecodeVideo( vlc_fourcc_t i_codec ) const;+    bool
> > startSoutChain( sout_stream_t*
> > p_stream,+                         const
> > std::vector<sout_stream_id_sys_t*>
> > &new_streams,+                         const std::string &sout
> > );+    void stopSoutChain( sout_stream_t* p_stream
> > );+    sout_stream_id_sys_t *GetSubId( sout_stream_t
> > *p_stream,+                                    sout_stream_id_sys_t
> > *id,+                                    bool update = true
> > );++    sout_stream_t                       *p_out;+    bool       
> >                          b_supports_video;+    bool                
> >                 es_changed;+    int                                
> >  http_port;+    std::vector<sout_stream_id_sys_t*>  streams;+    st
> > d::vector<sout_stream_id_sys_t*>  out_streams;++    int
> > UpdateOutput( sout_stream_t *p_stream );++};++bool
> > sout_stream_sys_t::canDecodeAudio(vlc_fourcc_t i_codec)
> > const+{+    return i_codec == VLC_CODEC_MP4A;+}++bool
> > sout_stream_sys_t::canDecodeVideo(vlc_fourcc_t i_codec)
> > const+{+    return i_codec == VLC_CODEC_H264;+}++bool
> > sout_stream_sys_t::startSoutChain(sout_stream_t
> > *p_stream,+                                       const
> > std::vector<sout_stream_id_sys_t*>
> > &new_streams,+                                       const
> > std::string &sout)+{+    msg_Dbg( p_stream, "Creating chain %s",
> > sout.c_str() );+    out_streams = new_streams;++    p_out =
> > sout_StreamChainNew( p_stream->p_sout, sout.c_str(), NULL,
> > NULL);+    if (p_out == NULL) {+        msg_Err(p_stream, "could
> > not create sout chain:%s",
> > sout.c_str());+        out_streams.clear();+        return
> > false;+    }++    /* check the streams we can actually add
> > */+    for (std::vector<sout_stream_id_sys_t*>::iterator it =
> > out_streams.begin();+            it != out_streams.end();
> > )+    {+        sout_stream_id_sys_t *p_sys_id =
> > *it;+        p_sys_id->p_sub_id = static_cast<sout_stream_id_sys_t
> > *>(+                sout_StreamIdAdd( p_out, &p_sys_id->fmt )
> > );+        if ( p_sys_id->p_sub_id == NULL
> > )+        {+            msg_Err( p_stream, "can't handle %4.4s
> > stream",+                    (char *)&p_sys_id->fmt.i_codec
> > );+            es_format_Clean( &p_sys_id->fmt );+            it =
> > out_streams.erase( it
> > );+        }+        else+            ++it;+    }++    if
> > (out_streams.empty())+    {+        stopSoutChain( p_stream
> > );+        return false;+    }++    return true;+}++void
> > sout_stream_sys_t::stopSoutChain(sout_stream_t
> > *p_stream)+{+    (void) p_stream;++    for ( size_t i = 0; i <
> > out_streams.size(); i++ )+    {+        sout_StreamIdDel( p_out,
> > out_streams[i]->p_sub_id );+        out_streams[i]->p_sub_id =
> > NULL;+    }+    out_streams.clear();+    sout_StreamChainDelete(
> > p_out, NULL );+    p_out = NULL;+}++sout_stream_id_sys_t
> > *sout_stream_sys_t::GetSubId( sout_stream_t
> > *p_stream,+                                                   sout_
> > stream_id_sys_t
> > *id,+                                                   bool
> > update)+{+    assert( p_stream->p_sys == this );++    if ( update
> > && UpdateOutput( p_stream ) != VLC_SUCCESS )+        return
> > NULL;++    for (size_t i = 0; i < out_streams.size();
> > ++i)+    {+        if ( id == (sout_stream_id_sys_t*)
> > out_streams[i] )+            return out_streams[i]-
> > >p_sub_id;+    }++    msg_Err( p_stream, "unknown stream ID"
> > );+    return NULL;+}++int sout_stream_sys_t::UpdateOutput(
> > sout_stream_t *p_stream )+{+    assert( p_stream->p_sys == this
> > );++    if ( !es_changed )+        return
> > VLC_SUCCESS;++    es_changed = false;++    bool canRemux =
> > true;+    vlc_fourcc_t i_codec_video = 0, i_codec_audio =
> > 0;+    std::vector<sout_stream_id_sys_t*> new_streams;++    for
> > (sout_stream_id_sys_t *stream : streams)+    {+        const
> > es_format_t *p_es = &stream->fmt;+        if (p_es->i_cat ==
> > AUDIO_ES)+        {+            if (!canDecodeAudio( p_es->i_codec
> > ))+            {+                msg_Dbg( p_stream, "can't remux
> > audio track %d codec %4.4s",+                        p_es->i_id,
> > (const char*)&p_es->i_codec );+                canRemux =
> > false;+            }+            else if (i_codec_audio ==
> > 0)+            {+                i_codec_audio = p_es-
> > >i_codec;+            }+            new_streams.push_back(stream);+
> >         }+        else if (b_supports_video && p_es->i_cat ==
> > VIDEO_ES)+        {+            if (!canDecodeVideo( p_es->i_codec
> > ))+            {+                msg_Dbg( p_stream, "can't remux
> > video track %d codec %4.4s",+                        p_es->i_id,
> > (const char*)&p_es->i_codec );+                canRemux =
> > false;+            }+            else if (i_codec_video ==
> > 0)+            {+                i_codec_video = p_es-
> > >i_codec;+            }+            new_streams.push_back(stream);+
> >         }+    }++    if (new_streams.empty())+        return
> > VLC_SUCCESS;++    std::ostringstream ssout;+    if ( !canRemux
> > )+    {+        /* TODO: provide audio samplerate and channels
> > */+        ssout << "transcode{";+        char
> > s_fourcc[5];+        if ( i_codec_audio == 0
> > )+        {+            i_codec_audio =
> > DEFAULT_TRANSCODE_AUDIO;+            msg_Dbg( p_stream, "Converting
> > audio to %.4s",+                    (const char*)&i_codec_audio
> > );+            ssout << "acodec=";+            vlc_fourcc_to_char(
> > i_codec_audio, s_fourcc );+            s_fourcc[4] =
> > '\0';+            ssout << s_fourcc << ',';+        }+        if (
> > b_supports_video && i_codec_video == 0
> > )+        {+            i_codec_video =
> > DEFAULT_TRANSCODE_VIDEO;+            msg_Dbg( p_stream, "Converting
> > video to %.4s",+                    (const char*)&i_codec_video
> > );+            /* TODO: provide maxwidth,maxheight
> > */+            ssout << "vcodec=";+            vlc_fourcc_to_char(
> > i_codec_video, s_fourcc );+            s_fourcc[4] =
> > '\0';+            ssout << s_fourcc;+        }+        ssout <<
> > "}:";+    }++    std::ostringstream ss;+    ss << "/dlna"+       <<
> > "/" << vlc_tick_now()+       << "/" << static_cast<uint64_t>(
> > vlc_mrand48() )+       << "/stream";+    std::string root_url =
> > ss.str();++    ssout << "http{dst=:" << http_port <<
> > root_url+          << ",mux=" << "mp4stream"+          <<
> > ",access=http{mime=" << "video/mp4" << "}}";++    if (
> > !startSoutChain( p_stream, new_streams, ssout.str() )
> > )+        return VLC_EGENERIC;++    char *ip =
> > getIpv4ForMulticast();
> 
> This is not defined if UPNP_ENABLE_IPV6 is defined.

I'm not too fimiliar with Windows programming but from my research both
GetAdapterAddresses and WSAAddressToString are IPv4 and IPv6 aware.So
it might be prudent to move getIpv4ForMulticast out of UPNP_ENABLE_IPV6
define even though It might not be used for UpnpInit2.What do you
think?
> > +    if (ip == NULL)+    {+        ip =
> > UpnpGetServerIpAddress();+    }+    if (ip ==
> > NULL)+    {+        msg_Err(p_stream, "could not get the local ip
> > address");+        return VLC_EGENERIC;+    }++    char
> > *uri;+    if (asprintf(&uri, "http://%s:%d%s", ip, http_port,
> > root_url.c_str()) < 0) {+        return VLC_ENOMEM;+    }
> 
> Maybe do the startSoutChain() only if this is valid ?
> > ++    msg_Dbg(p_stream, "AVTransportURI: %s", uri);+    renderer-
> > >Stop();+    renderer->SetAVTransportURI(uri);+    renderer-
> > >Play("1");++    return VLC_SUCCESS;+}++char
> > *MediaRenderer::getServiceURL(const char* type, const char
> > *service)+{+    IXML_Document *p_description_doc = NULL;+    if
> > (UpnpDownloadXmlDoc(device_url.c_str(), &p_description_doc) !=
> > UPNP_E_SUCCESS)+        return NULL;++    IXML_NodeList*
> > p_device_list = ixmlDocument_getElementsByTagName(
> > p_description_doc, "device");+    free(p_description_doc);+    if (
> > !p_device_list )+        return NULL;++    for (unsigned int i = 0;
> > i < ixmlNodeList_length(p_device_list);
> > ++i)+    {+        IXML_Element* p_device_element = ( IXML_Element*
> > ) ixmlNodeList_item( p_device_list, i );+        if(
> > !p_device_element )+            continue;++        IXML_NodeList*
> > p_service_list = ixmlElement_getElementsByTagName(
> > p_device_element, "service" );+        if ( !p_service_list
> > )+            continue;+        for ( unsigned int j = 0; j <
> > ixmlNodeList_length( p_service_list ); j++
> > )+        {+            IXML_Element* p_service_element =
> > (IXML_Element*)ixmlNodeList_item( p_service_list, j
> > );++            const char* psz_service_type =
> > xml_getChildElementValue( p_service_element, "serviceType"
> > );+            if ( !psz_service_type || !strstr(psz_service_type,
> > type))+                continue;+            const char*
> > psz_control_url = xml_getChildElementValue(
> > p_service_element,+                                                
> >                     service );+            if ( !psz_control_url
> > )+                continue;++            char* psz_url = ( char* )
> > malloc( base_url.length() + strlen( psz_control_url ) + 1
> > );+            if ( psz_url && UpnpResolveURL( base_url.c_str(),
> > psz_control_url, psz_url ) == UPNP_E_SUCCESS
> > )+                return psz_url;+            return
> > NULL;+        }+    }+    return NULL;+}++/**+ * Send an action to
> > the control url of the service specified.+ *+ * \return the
> > response as a IXML document or NULL for failure+ **/+IXML_Document
> > *MediaRenderer::SendAction(const char* action_name,const char
> > *service_type,+                    std::list<std::pair<const char*,
> > const char*>> arguments)+{+    /* Create action
> > */+    IXML_Document *action = UpnpMakeAction(action_name,
> > service_type, 0, NULL);++    /* Add argument to action */+    for
> > (std::pair<const char*, const char*> arg : arguments) {+      const
> > char *arg_name, *arg_val;+      arg_name =
> > arg.first;+      arg_val  =
> > arg.second;+      UpnpAddToAction(&action, action_name,
> > service_type, arg_name, arg_val);+    }++    /* Get the controlURL
> > of the service */+    char *control_url =
> > getServiceURL(service_type, "controlURL");++    /* Send action
> > */+    IXML_Document *response = NULL;+    int ret =
> > UpnpSendAction(handle, control_url,
> > service_type,+                                    NULL, action,
> > &response);++    /* Free action */+    if (action)
> > ixmlDocument_free(action);+    if (control_url)
> > free(control_url);++    if (ret != UPNP_E_SUCCESS)
> > {+        msg_Err(parent, "Unable to send action: %s (%d: %s)
> > response: %s",+                action_name, ret,
> > UpnpGetErrorMessage(ret), ixmlPrintDocument(response));+        if
> > (response) ixmlDocument_free(response);+        return
> > NULL;+    }++    return response;+}++int MediaRenderer::Play(const
> > char *speed)+{+    std::list<std::pair<const char*, const char*>>
> > arg_list;+    arg_list.push_back(std::make_pair("InstanceID",
> > "0"));+    arg_list.push_back(std::make_pair("Speed",
> > speed));++    IXML_Document *p_response = SendAction("Play",
> > AV_TRANSPORT_SERVICE_TYPE,
> > arg_list);+    if(!p_response)+    {+        return
> > VLC_EGENERIC;+    }+    ixmlDocument_free(p_response);+    return
> > VLC_SUCCESS;+}++int
> > MediaRenderer::Stop()+{+    std::list<std::pair<const char*, const
> > char*>>
> > arg_list;+    arg_list.push_back(std::make_pair("InstanceID",
> > "0"));++    IXML_Document *p_response = SendAction("Stop",
> > AV_TRANSPORT_SERVICE_TYPE,
> > arg_list);+    if(!p_response)+    {+        return
> > VLC_EGENERIC;+    }+    ixmlDocument_free(p_response);+    return
> > VLC_SUCCESS;+}++int MediaRenderer::SetAVTransportURI(const char*
> > uri)+{+    std::list<std::pair<const char*, const char*>>
> > arg_list;+    arg_list.push_back(std::make_pair("InstanceID",
> > "0"));+    arg_list.push_back(std::make_pair("CurrentURI",
> > uri));+    arg_list.push_back(std::make_pair("CurrentURIMetaData",
> > "")); // NOT_IMPLEMENTED++    IXML_Document *p_response =
> > SendAction("SetAVTransportURI",+                                   
> >  AV_TRANSPORT_SERVICE_TYPE,
> > arg_list);+    if(!p_response)+    {+        return
> > VLC_EGENERIC;+    }+    ixmlDocument_free(p_response);+    return
> > VLC_SUCCESS;+}++static void *Add(sout_stream_t *p_stream, const
> > es_format_t *p_fmt)+{+    sout_stream_sys_t *p_sys =
> > static_cast<sout_stream_sys_t *>( p_stream->p_sys );++    if
> > (!p_sys->b_supports_video)+    {+        if (p_fmt->i_cat !=
> > AUDIO_ES)+            return NULL;+    }++    sout_stream_id_sys_t
> > *p_sys_id = (sout_stream_id_sys_t
> > *)malloc(sizeof(sout_stream_id_sys_t));+    if(p_sys_id !=
> > NULL)+    {+        es_format_Copy(&p_sys_id->fmt,
> > p_fmt);+        p_sys_id->p_sub_id = NULL;+        p_sys-
> > >streams.push_back(p_sys_id);+        p_sys->es_changed =
> > true;+    }+    return p_sys_id;+}++static int Send(sout_stream_t
> > *p_stream, void *id,+                block_t
> > *p_buffer)+{+    sout_stream_sys_t *p_sys =
> > static_cast<sout_stream_sys_t *>( p_stream->p_sys
> > );+    sout_stream_id_sys_t *id_sys =
> > static_cast<sout_stream_id_sys_t*>( id );++    id_sys = p_sys-
> > >GetSubId( p_stream, id_sys );+    if ( id_sys == NULL
> > )+        return VLC_EGENERIC;++    return sout_StreamIdSend(p_sys-
> > >p_out, id_sys, p_buffer);+}++static void Flush( sout_stream_t
> > *p_stream, void *id )+{+    sout_stream_sys_t *p_sys =
> > static_cast<sout_stream_sys_t *>( p_stream->p_sys
> > );+    sout_stream_id_sys_t *id_sys =
> > static_cast<sout_stream_id_sys_t*>( id );++    id_sys = p_sys-
> > >GetSubId( p_stream, id_sys, false );+    if ( id_sys == NULL
> > )+        return;++    sout_StreamFlush( p_sys->p_out, id_sys
> > );+}++static void Del(sout_stream_t *p_stream, void
> > *_id)+{+    sout_stream_sys_t *p_sys =
> > static_cast<sout_stream_sys_t *>( p_stream->p_sys
> > );+    sout_stream_id_sys_t *id = static_cast<sout_stream_id_sys_t
> > *>( _id );++    for (std::vector<sout_stream_id_sys_t*>::iterator
> > it = p_sys->streams.begin();+         it != p_sys->streams.end();
> > )+    {+        sout_stream_id_sys_t *p_sys_id = *it;+        if (
> > p_sys_id == id )+        {+            if ( p_sys_id->p_sub_id !=
> > NULL )+            {+                sout_StreamIdDel( p_sys-
> > >p_out, p_sys_id->p_sub_id );+                for
> > (std::vector<sout_stream_id_sys_t*>::iterator out_it = p_sys-
> > >out_streams.begin();+                     out_it != p_sys-
> > >out_streams.end(); )+                {+                    if
> > (*out_it ==
> > id)+                    {+                        p_sys-
> > >out_streams.erase(out_it);+                        break;+        
> >             }+                    out_it++;+                }+     
> >        }++            es_format_Clean( &p_sys_id->fmt
> > );+            free( p_sys_id );+            p_sys->streams.erase(
> > it );+            break;+        }+        it++;+    }++    if
> > (p_sys->out_streams.empty())+    {+        p_sys-
> > >stopSoutChain(p_stream);+        p_sys->renderer-
> > >Stop();+    }+}++int OpenSout( vlc_object_t *p_this
> > )+{+    sout_stream_t *p_stream =
> > reinterpret_cast<sout_stream_t*>(p_this);+    sout_stream_sys_t
> > *p_sys = NULL;++    config_ChainParse(p_stream, SOUT_CFG_PREFIX,
> > ppsz_sout_options, p_stream->p_cfg);++    int http_port =
> > var_InheritInteger(p_stream, SOUT_CFG_PREFIX "http-port");+    bool 
> > b_supports_video = var_GetBool(p_stream, SOUT_CFG_PREFIX
> > "video");+    char *base_url = var_GetNonEmptyString(p_stream,
> > SOUT_CFG_PREFIX "base_url");+    char *device_url =
> > var_GetNonEmptyString(p_stream, SOUT_CFG_PREFIX "url");+    if (
> > device_url == NULL)+    {+        msg_Err( p_stream, "missing Url"
> > );+        goto error;+    }++    try {+        p_sys = new
> > sout_stream_sys_t(http_port, b_supports_video);+    }+    catch (
> > const std::exception& ex ) {+        msg_Err( p_stream, "Failed to
> > instantiate sout_stream_sys_t: %s", ex.what() );+        return
> > VLC_EGENERIC;+    }++    p_sys->p_upnp = UpnpInstanceWrapper::get(
> > p_this );+    if ( !p_sys->p_upnp )+        goto error;+    try
> > {+        p_sys->renderer =
> > std::make_shared<MediaRenderer>(p_stream,+                         
> >    p_sys->p_upnp, base_url, device_url);+    }+    catch ( const
> > std::bad_alloc& ) {+        msg_Err( p_stream, "Failed to create a
> > MediaRenderer");+        p_sys->p_upnp->release();+        goto
> > error;+    }++    p_stream->pf_add     = Add;+    p_stream-
> > >pf_del     = Del;+    p_stream->pf_send    = Send;+    p_stream-
> > >pf_flush   = Flush;++    p_stream->p_sys =
> > p_sys;++    free(base_url);+    free(device_url);++    return
> > VLC_SUCCESS;++error:+    free(base_url);+    free(device_url);+    
> > delete p_sys;+    return VLC_EGENERIC;+}++void CloseSout(
> > vlc_object_t *p_this)+{+    sout_stream_t *p_stream =
> > reinterpret_cast<sout_stream_t*>( p_this );+    sout_stream_sys_t
> > *p_sys = static_cast<sout_stream_sys_t *>( p_stream->p_sys
> > );++    p_sys->p_upnp->release();+    delete p_sys;+}++}diff --git
> > a/modules/stream_out/dlna/dlna.hpp
> > b/modules/stream_out/dlna/dlna.hppnew file mode 100644index
> > 0000000000..59ff3d6c8d--- /dev/null+++
> > b/modules/stream_out/dlna/dlna.hpp@@ -0,0 +1,60
> > @@+/***************************************************************
> > **************+ * dlna.hpp : DLNA/UPNP (renderer) sout module
> > header+
> > *******************************************************************
> > **********+ * Copyright (C) 2004-2018 VLC authors and VideoLAN+ *+
> > * Authors: William Ung <william1.ung at epitech.eu>+
> > *          Shaleen Jain <shaleen at jain.sh>+ *+ * This program is
> > free software; you can redistribute it and/or modify it+ * under
> > the terms of the GNU Lesser General Public License as published by+
> > * the Free Software Foundation; either version 2.1 of the License,
> > or+ * (at your option) any later version.+ *+ * This program is
> > distributed in the hope that it will be useful,+ * but WITHOUT ANY
> > WARRANTY; without even the implied warranty of+ * MERCHANTABILITY
> > or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU Lesser General
> > Public License for more details.+ *+ * You should have received a
> > copy of the GNU Lesser General Public License+ * along with this
> > program; if not, write to the Free Software Foundation,+ * Inc., 51
> > Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.+
> > *******************************************************************
> > **********/++#ifndef DLNA_H+#define DLNA_H++#include
> > "../../services_discovery/upnp-wrapper.hpp"+#include
> > "dlna_common.hpp"++namespace DLNA+{++class
> > MediaRenderer+{+public:+    MediaRenderer(sout_stream_t *p_stream,
> > UpnpInstanceWrapper *upnp,+            std::string base_url,
> > std::string device_url)+        : parent(p_stream)+        ,
> > base_url(base_url)+        , device_url(device_url)+        ,
> > handle(upnp->handle())+    {+    }++    sout_stream_t
> > *parent;+    std::string base_url;+    std::string
> > device_url;+    UpnpClient_Handle handle;++    char
> > *getServiceURL(const char* type, const char*
> > service);+    IXML_Document *SendAction(const char* action_name,
> > const char
> > *service_type,+                    std::list<std::pair<const char*,
> > const char*>> arguments);++    int Play(const char *speed);+    int
> > Stop();+    int SetAVTransportURI(const char* uri);+};++}+#endif /*
> > DLNA_H */diff --git a/modules/stream_out/dlna/dlna_common.hpp
> > b/modules/stream_out/dlna/dlna_common.hppnew file mode 100644index
> > 0000000000..74d9ec7ea7--- /dev/null+++
> > b/modules/stream_out/dlna/dlna_common.hpp@@ -0,0 +1,61
> > @@+/***************************************************************
> > **************+ * dlna.hpp : DLNA/UPNP (renderer) sout module
> > header+
> > *******************************************************************
> > **********+ * Copyright (C) 2004-2018 VLC authors and VideoLAN+ *+
> > * Authors: William Ung <william1.ung at epitech.eu>+
> > *          Shaleen Jain <shaleen at jain.sh>+ *+ * This program is
> > free software; you can redistribute it and/or modify it+ * under
> > the terms of the GNU Lesser General Public License as published by+
> > * the Free Software Foundation; either version 2.1 of the License,
> > or+ * (at your option) any later version.+ *+ * This program is
> > distributed in the hope that it will be useful,+ * but WITHOUT ANY
> > WARRANTY; without even the implied warranty of+ * MERCHANTABILITY
> > or FITNESS FOR A PARTICULAR PURPOSE. See the+ * GNU Lesser General
> > Public License for more details.+ *+ * You should have received a
> > copy of the GNU Lesser General Public License+ * along with this
> > program; if not, write to the Free Software Foundation,+ * Inc., 51
> > Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.+
> > *******************************************************************
> > **********/++#ifndef DLNA_COMMON_H+#define DLNA_COMMON_H++#include
> > <list>++#include<vlc_common.h>+#include <vlc_fourcc.h>++#define
> > SOUT_CFG_PREFIX "sout-dlna-"++#define
> > HTTP_PORT         7070++#define HTTP_PORT_TEXT N_("HTTP
> > port")+#define HTTP_PORT_LONGTEXT N_("This sets the HTTP port of
> > the local server used to stream the media to the UPnP
> > Renderer.")+#define HAS_VIDEO_TEXT N_("Video")+#define
> > HAS_VIDEO_LONGTEXT N_("The UPnP Renderer can receive
> > video.")++#define IP_ADDR_TEXT N_("IP Address")+#define
> > IP_ADDR_LONGTEXT N_("IP Address of the UPnP Renderer.")+#define
> > PORT_TEXT N_("UPnP Renderer port")+#define PORT_LONGTEXT N_("The
> > port used to talk to the UPnP Renderer.")+#define BASE_URL_TEXT
> > N_("base URL")+#define BASE_URL_LONGTEXT N_("The base Url relative
> > to which all other UPnP operations must be called")+#define
> > URL_TEXT N_("description URL")+#define URL_LONGTEXT N_("The Url
> > used to get the xml descriptor of the UPnP Renderer")
> 
> Move these defines in the only file they are used.
> > ++static const vlc_fourcc_t DEFAULT_TRANSCODE_AUDIO =
> > VLC_CODEC_MP4A;+static const vlc_fourcc_t DEFAULT_TRANSCODE_VIDEO =
> > VLC_CODEC_H264;++namespace DLNA+{++/* module callbacks */+int
> > OpenSout(vlc_object_t *);+void CloseSout(vlc_object_t *);++}+#endif
> > /* DLNA_COMMON_H */--
> > 2.19.1_______________________________________________vlc-devel
> > mailing listTo unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> 
> _______________________________________________vlc-devel mailing
> listTo unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
-- 
Regards,
Shaleen Jain
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20181017/efa312d3/attachment.html>


More information about the vlc-devel mailing list