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

Shaleen Jain shaleen at jain.sh
Mon Oct 15 16:53:55 CEST 2018


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.

Ah yes. I'll account for that.
> > +    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 ?

Okay.
> > ++    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.

Done.
> > ++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/20181015/cec76320/attachment-0001.html>


More information about the vlc-devel mailing list