[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