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

Shaleen Jain shaleen at jain.sh
Mon Nov 26 16:15:38 CET 2018


On Mon, 2018-11-26 at 15:48 +0100, Thomas Guillem wrote:
> Hello Shaleen,Sorry for the very late review.
> On Tue, Oct 23, 2018, at 07:51, 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     |  54 ++
> > modules/services_discovery/upnp.hpp     |   1 +
> > modules/stream_out/dlna/dlna.cpp        | 886 ++++++++++++++++++++++++
> > modules/stream_out/dlna/dlna.hpp        |  60 ++
> > modules/stream_out/dlna/dlna_common.hpp |  56 ++ 8 files changed, 1063 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+		
> > 	    services_discovery/upnp-wrapper.cpp \+			    stream_out/dlna/dln
> > a_common.hpp \+			    stream_out/dlna/dlna.hpp \+			
> >     stream_out/dlna/dlna.cpp libupnp_plugin_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..bf025a6393 100644---
> > a/modules/services_discovery/upnp.cpp+++ b/modules/services_discovery/upnp.cpp@@ -54,6
> > +54,40 @@ const char* SATIP_SERVER_DEVICE_TYPE = "urn:ses-com:device:SatIPServer:1";
> > #define UPNP_SEARCH_TIMEOUT_SECONDS 15 #define SATIP_CHANNEL_LIST N_("SAT>IP channel
> > list") #define SATIP_CHANNEL_LIST_URL N_("Custom SAT>IP channel list URL")++#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 PERF_TEXT N_(
> > "Performance warning" )+#define PERF_LONGTEXT N_( "Display a performance warning when
> > transcoding" )+#define CONVERSION_QUALITY_TEXT N_( "Conversion quality" )+#define
> > CONVERSION_QUALITY_LONGTEXT N_( "Change this option to increase conversion speed or
> > quality." )++#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")++#if
> > defined (__ANDROID__) || defined (__arm__) || (defined (TARGET_OS_IPHONE) &&
> > TARGET_OS_IPHONE)+# define CONVERSION_QUALITY_DEFAULT CONVERSION_QUALITY_LOW+#else+#
> > define CONVERSION_QUALITY_DEFAULT CONVERSION_QUALITY_MEDIUM+#endif+static const char
> > *const conversion_quality_list_text[] = {+    N_( "High (high quality and high
> > bandwidth)" ),+    N_( "Medium (medium quality and medium bandwidth)" ),+    N_( "Low
> > (low quality and low bandwidth)" ),+    N_( "Low CPU (low quality but high bandwidth)"
> > ),+};+ static const char *const ppsz_satip_channel_lists[] = {     "Auto",
> > "ASTRA_19_2E", "ASTRA_28_2E", "ASTRA_23_5E", "MasterList", "ServerList", "CustomList"
> > };@@ -147,6 +181,26 @@ vlc_module_begin()      VLC_RD_PROBE_SUBMODULE
> > +    add_submodule()+        set_shortname("dlna")+        set_description(N_("UPnP/DLN
> > A 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)+        add_integer(SOUT_CFG_PREFIX "show-perf-warning", 1, PERF_TEXT,
> > PERF_LONGTEXT, true )+            change_private()+        add_integer(SOUT_CFG_PREFIX
> > "conversion-quality",
> > CONVERSION_QUALITY_DEFAULT,+                    CONVERSION_QUALITY_TEXT,
> > CONVERSION_QUALITY_LONGTEXT, false
> > );+            change_integer_list(conversion_quality_list,
> > conversion_quality_list_text) vlc_module_end()
> 
> These options could be merged with  the chromecast.

Do you mean by having the same prefix as that of the chromecast ones?
> >   /*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..e0c266d8e3---
> > /dev/null+++ b/modules/stream_out/dlna/dlna.cpp@@ -0,0 +1,886
> > @@+/*****************************************************************************+ *
> > 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_dialog.h>+#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_stream_id_sys_t  *p_sub_
> > id;+};++struct sout_stream_sys_t+{+    sout_stream_sys_t(int http_port, bool
> > supports_video)+        : p_out( NULL )+        , es_changed( true )+        ,
> > b_supports_video( supports_video )+        , perf_warning_shown( false )+        ,
> > venc_opt_idx ( -1 )+        , 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                           
> >      es_changed;+    bool                                b_supports_video;+    bool    
> >                             perf_warning_shown;+    int                                
> >  venc_opt_idx;+    int                                 http_port;+    std::vector<sout_
> > stream_id_sys_t*>  streams;+    std::vector<sout_stream_id_sys_t*>  out_streams;++priva
> > te:+    std::string GetVencOption( sout_stream_t *, vlc_fourcc_t
> > *,+                               const video_format_t *, int );+    std::string
> > GetAcodecOption( sout_stream_t *, vlc_fourcc_t *, const audio_format_t *, int
> > );+    std::string GetVcodecOption( sout_stream_t *, vlc_fourcc_t *, const
> > video_format_t *, int );+    int UpdateOutput( sout_stream_t *p_stream );++};++char
> > *getServerIPAddress() {+    char *ip = NULL;+#ifdef UPNP_ENABLE_IPV6+#ifdef
> > _WIN32+    IP_ADAPTER_UNICAST_ADDRESS *p_best_ip = NULL;+    wchar_t
> > psz_uri[32];+    DWORD strSize;+    IP_ADAPTER_ADDRESSES *p_adapter,
> > *addresses;++    addresses = ListAdapters();+    if (addresses == NULL)+        return
> > NULL;++    p_adapter = addresses;+    while (p_adapter != NULL)+    {+        if
> > (isAdapterSuitable(p_adapter, false))+        {+            IP_ADAPTER_UNICAST_ADDRESS
> > *p_unicast = p_adapter-
> > > FirstUnicastAddress;
> > +            while (p_unicast != NULL)+            {+                strSize = sizeof(
> > psz_uri ) / sizeof( wchar_t );+                if( WSAAddressToString( p_unicast-
> > >Address.lpSockaddr,+                                        p_unicast-
> > > Address.iSockaddrLength,
> > +                                        NULL, psz_uri, &strSize ) == 0
> > )+                {+                    if ( p_best_ip == NULL
> > ||+                         p_best_ip->ValidLifetime > p_unicast-
> > > ValidLifetime )
> > +                    {+                        p_best_ip =
> > p_unicast;+                    }+                }+                p_unicast =
> > p_unicast->Next;+            }+        }+        p_adapter = p_adapter-
> > >Next;+    }++    if (p_best_ip != NULL)+    {+        strSize = sizeof( psz_uri ) /
> > sizeof( wchar_t );+        WSAAddressToString( p_best_ip-
> > >Address.lpSockaddr,+                            p_best_ip-
> > >Address.iSockaddrLength,+                            NULL, psz_uri, &strSize
> > );+        free(addresses);+        return FromWide( psz_uri
> > );+    }+    free(addresses);+    return NULL;+#endif /* _WIN32 */+#else /*
> > UPNP_ENABLE_IPV6 */+    ip = getIpv4ForMulticast();+#endif /* UPNP_ENABLE_IPV6
> > */+    if (ip == NULL)+    {+        ip = UpnpGetServerIpAddress();+    }+    return
> > ip;+}++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;+}++static std::string GetVencQSVH264Option(
> > sout_stream_t * /* p_stream */,+                                         const
> > video_format_t * /* p_vid */,+                                         int i_quality
> > )+{+    std::stringstream ssout;+    static const char video_target_usage_quality[]  =
> > "quality";+    static const char video_target_usage_balanced[] = "balanced";+    static
> > const char video_target_usage_speed[]    = "speed";+    static const char
> > video_bitrate_high[] = "vb=8000000";+    static const char video_bitrate_low[]  =
> > "vb=3000000";+    const char *psz_video_target_usage;+    const char
> > *psz_video_bitrate;++    switch ( i_quality )+    {+        case
> > CONVERSION_QUALITY_HIGH:+            psz_video_target_usage =
> > video_target_usage_quality;+            psz_video_bitrate =
> > video_bitrate_high;+            break;+        case
> > CONVERSION_QUALITY_MEDIUM:+            psz_video_target_usage =
> > video_target_usage_balanced;+            psz_video_bitrate =
> > video_bitrate_high;+            break;+        case
> > CONVERSION_QUALITY_LOW:+            psz_video_target_usage =
> > video_target_usage_balanced;+            psz_video_bitrate =
> > video_bitrate_low;+            break;+        default:+        case
> > CONVERSION_QUALITY_LOWCPU:+            psz_video_target_usage =
> > video_target_usage_speed;+            psz_video_bitrate =
> > video_bitrate_low;+            break;+    }++    ssout << "venc=qsv{target-usage=" <<
> > psz_video_target_usage <<+             "}," << psz_video_bitrate;+    return
> > ssout.str();+}++static std::string GetVencX264Option( sout_stream_t * /* p_stream
> > */,+                                      const video_format_t
> > *p_vid,+                                      int i_quality )+{+    std::stringstream
> > ssout;+    static const char video_x264_preset_veryfast[] = "veryfast";+    static
> > const char video_x264_preset_ultrafast[] = "ultrafast";+    const char
> > *psz_video_x264_preset;+    unsigned i_video_x264_crf_hd,
> > i_video_x264_crf_720p;++    switch ( i_quality )+    {+        case
> > CONVERSION_QUALITY_HIGH:+            i_video_x264_crf_hd = i_video_x264_crf_720p =
> > 21;+            psz_video_x264_preset =
> > video_x264_preset_veryfast;+            break;+        case
> > CONVERSION_QUALITY_MEDIUM:+            i_video_x264_crf_hd =
> > 23;+            i_video_x264_crf_720p = 21;+            psz_video_x264_preset =
> > video_x264_preset_veryfast;+            break;+        case
> > CONVERSION_QUALITY_LOW:+            i_video_x264_crf_hd = i_video_x264_crf_720p =
> > 23;+            psz_video_x264_preset =
> > video_x264_preset_veryfast;+            break;+        default:+        case
> > CONVERSION_QUALITY_LOWCPU:+            i_video_x264_crf_hd = i_video_x264_crf_720p =
> > 23;+            psz_video_x264_preset =
> > video_x264_preset_ultrafast;+            break;+    }++    const bool b_hdres = p_vid-
> > >i_height == 0 || p_vid->i_height >= 800;+    unsigned i_video_x264_crf = b_hdres ?
> > i_video_x264_crf_hd : i_video_x264_crf_720p;++    ssout << "venc=x264{preset=" <<
> > psz_video_x264_preset+          << ",crf=" << i_video_x264_crf << "}";+    return
> > ssout.str();+}++#ifdef __APPLE__+static std::string GetVencAvcodecVTOption(
> > sout_stream_t * /* p_stream */,+                                           const
> > video_format_t * p_vid,+                                           int i_quality
> > )+{+    std::stringstream ssout;+    ssout <<
> > "venc=avcodec{codec=h264_videotoolbox,options{realtime=1}}";+    switch( i_quality
> > )+    {+        /* Here, performances issues won't come from videotoolbox but
> > from+         * some old chromecast devices */++        case
> > CONVERSION_QUALITY_HIGH:+            break;+        case
> > CONVERSION_QUALITY_MEDIUM:+            ssout <<
> > ",vb=8000000";+            break;+        case CONVERSION_QUALITY_LOW:+        case
> > CONVERSION_QUALITY_LOWCPU:+            ssout <<
> > ",vb=3000000";+            break;+    }++    return ssout.str();+}+#endif++static
> > struct+{+    vlc_fourcc_t fcc;+    std::string (*get_opt)( sout_stream_t *, const
> > video_format_t *, int);+} venc_opt_list[] = {+#ifdef __APPLE__+    { .fcc =
> > VLC_CODEC_H264, .get_opt = GetVencAvcodecVTOption },+#endif+    { .fcc =
> > VLC_CODEC_H264, .get_opt = GetVencQSVH264Option },+    { .fcc = VLC_CODEC_H264,
> > .get_opt = GetVencX264Option },+    { .fcc = VLC_CODEC_H264, .get_opt = NULL
> > },+};++std::string+sout_stream_sys_t::GetVencOption( sout_stream_t *p_stream,
> > vlc_fourcc_t *p_codec_video,+                                  const video_format_t
> > *p_vid, int i_quality )+{+    for( size_t i = (venc_opt_idx == -1 ? 0 :
> > venc_opt_idx);+         i < ARRAY_SIZE(venc_opt_list); ++i
> > )+    {+        std::stringstream ssout, ssvenc;+        char fourcc[5];+        ssvenc
> > << "vcodec=";+        vlc_fourcc_to_char( venc_opt_list[i].fcc, fourcc
> > );+        fourcc[4] = '\0';+        ssvenc << fourcc << ',';++        if(
> > venc_opt_list[i].get_opt != NULL )+            ssvenc << venc_opt_list[i].get_opt(
> > p_stream, p_vid, i_quality ) << ',';++        if( venc_opt_list[i].get_opt ==
> > NULL+         || ( venc_opt_idx != -1 && (unsigned) venc_opt_idx == i)
> > )+        {+            venc_opt_idx = i;+            *p_codec_video =
> > venc_opt_list[i].fcc;+            return ssvenc.str();+        }++        /* Test if a
> > module can encode with the specified options / fmt_video. */+        ssout <<
> > "transcode{" << ssvenc.str() << "}:dummy";++        sout_stream_t *p_sout_test
> > =+            sout_StreamChainNew( p_stream->p_sout, ssout.str().c_str(), NULL, NULL
> > );++        if( p_sout_test != NULL )+        {+            p_sout_test->obj.flags |=
> > OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT;++            es_format_t
> > fmt;+            es_format_InitFromVideo( &fmt, p_vid );+            fmt.i_codec =
> > fmt.video.i_chroma = VLC_CODEC_I420;++            /* Test the maximum size/fps we will
> > encode */+            fmt.video.i_visible_width = fmt.video.i_width =
> > 1920;+            fmt.video.i_visible_height = fmt.video.i_height =
> > 1080;+            fmt.video.i_frame_rate = 30;+            fmt.video.i_frame_rate_base
> > = 1;++            void *id = sout_StreamIdAdd( p_sout_test, &fmt
> > );++            es_format_Clean( &fmt );+            const bool success = id !=
> > NULL;++            if( id )+                sout_StreamIdDel( p_sout_test, id
> > );+            sout_StreamChainDelete( p_sout_test, NULL );++            if( success
> > )+            {+                venc_opt_idx = i;+                *p_codec_video =
> > venc_opt_list[i].fcc;+                return
> > ssvenc.str();+            }+        }+    }+    vlc_assert_unreachable();+}++std::strin
> > g+sout_stream_sys_t::GetVcodecOption( sout_stream_t *p_stream, vlc_fourcc_t
> > *p_codec_video,+                                    const video_format_t *p_vid, int
> > i_quality )+{+    std::stringstream ssout;+    static const char video_maxres_hd[] =
> > "maxwidth=1920,maxheight=1080";+    static const char video_maxres_720p[] =
> > "maxwidth=1280,maxheight=720";++    ssout << GetVencOption( p_stream, p_codec_video,
> > p_vid, i_quality );++    switch ( i_quality )+    {+        case
> > CONVERSION_QUALITY_HIGH:+        case CONVERSION_QUALITY_MEDIUM:+            ssout << (
> > ( p_vid->i_width > 1920 ) ? "width=1920," : "" ) << video_maxres_hd <<
> > ',';+            break;+        default:+            ssout << ( ( p_vid->i_width > 1280
> > ) ? "width=1280," : "" ) << video_maxres_720p << ',';+    }++    if( p_vid-
> > >i_frame_rate == 0 || p_vid->i_frame_rate_base == 0+     || ( p_vid->i_frame_rate /
> > p_vid->i_frame_rate_base ) > 30 )+    {+        /* Even force 24fps if the frame rate
> > is unknown */+        msg_Warn( p_stream, "lowering frame rate to 24fps"
> > );+        ssout << "fps=24,";+    }++    msg_Dbg( p_stream, "Converting video to
> > %.4s", (const char*)p_codec_video );++    return ssout.str();+}
> 
> GetVencOption() and hardware specific encoder functions are the same than the chromecast
> ones, right ?They should be factorized. I'm afraid we'll forget to check for upnp when we
> do a fix on the chromecast sout (or vice-versa).
> The functions could be moved on a separate file, like stream_out/renderer_common.c/.h

There is a slight difference, only H264 encoders are used and the VP8 encoder option is
removed.
Maybe only refactor the individual encoder option functions and have different
GetVencOption()or maybe just the venc_opt_list struct.
> > ++std::string+sout_stream_sys_t::GetAcodecOption( sout_stream_t *p_stream, vlc_fourcc_t
> > *p_codec_audio,+                                    const audio_format_t *p_aud, int
> > i_quality )+{+    VLC_UNUSED(p_aud);+    VLC_UNUSED(i_quality);+    std::stringstream
> > ssout;++    msg_Dbg( p_stream, "Converting audio to %.4s", (const char*)p_codec_audio
> > );++    ssout << "acodec=";+    char fourcc[5];+    vlc_fourcc_to_char( *p_codec_audio,
> > fourcc );+    fourcc[4] = '\0';+    ssout << fourcc << ',';++    return
> > ssout.str();+}++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;+    // To keep track
> > of which stream needs transcoding if at all.+    vlc_fourcc_t i_codec_video = 0,
> > i_codec_audio = 0;+    const es_format_t *p_original_audio = NULL;+    const
> > es_format_t *p_original_video = NULL;+    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
> > );+                p_original_audio = p_es;+                canRemux =
> > false;+            }+            else if (i_codec_audio ==
> > 0)+            {+                i_codec_audio = p_es-
> > >i_codec;+            }+            new_streams.push_back(stream);+        }+        el
> > se 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 );+                p_original_video =
> > p_es;+                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 )+    {+        if ( !perf_warning_shown && i_codec_video ==
> > 0 && p_original_video+          && var_InheritInteger( p_stream, SOUT_CFG_PREFIX "show-
> > perf-warning" ) )+        {+            int res = vlc_dialog_wait_question(
> > p_stream,+                          VLC_DIALOG_QUESTION_WARNING,+                      
> >    _("Cancel"), _("OK"), _("Ok, Don't warn me
> > again"),+                         _("Performance
> > warning"),+                         _("Casting this video requires conversion.
> > "+                           "This conversion can use all the available power and
> > "+                           "could quickly drain your battery." ) );+            if (
> > res <= 0 )+                 return false;+            perf_warning_shown =
> > true;+            if ( res == 2 )+                config_PutInt(SOUT_CFG_PREFIX "show-
> > perf-warning", 0 );+        }++        const int i_quality = var_InheritInteger(
> > p_stream, SOUT_CFG_PREFIX "conversion-quality" );++        /* TODO: provide audio
> > samplerate and channels */+        ssout << "transcode{";+        if ( i_codec_audio ==
> > 0 && p_original_audio )+        {+            i_codec_audio =
> > VLC_CODEC_MP4A;+            ssout << GetAcodecOption( p_stream,
> > &i_codec_audio,+                                      &p_original_audio->audio,
> > i_quality );+        }+        if ( i_codec_video == 0 && p_original_video
> > )+        {+            i_codec_video = VLC_CODEC_H264;+            ssout <<
> > GetVcodecOption( p_stream,
> > &i_codec_video,+                                      &p_original_video->video,
> > i_quality );+        }+        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" << "}}";++    char *ip =
> > getServerIPAddress();+    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;+    }++    if ( !startSoutChain( p_stream, new_streams,
> > ssout.str() ) )+        return VLC_EGENERIC;++    msg_Dbg(p_stream, "AVTransportURI:
> > %s", uri);+    renderer->Stop();+    renderer->SetAVTransportURI(uri);+    renderer-
> > >Play("1");++    free(uri);+    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_SERVIC
> > E_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..a09283255e--- /dev/null+++
> > b/modules/stream_out/dlna/dlna_common.hpp@@ -0,0 +1,56
> > @@+/*****************************************************************************+ *
> > 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>++enum {+    CONVERSION_QUALITY_HIGH = 0,+    CONVERSION_QUALITY_MEDIUM =
> > 1,+    CONVERSION_QUALITY_LOW = 2,+    CONVERSION_QUALITY_LOWCPU = 3,+};++static const
> > int conversion_quality_list[] =
> > {+    CONVERSION_QUALITY_HIGH,+    CONVERSION_QUALITY_MEDIUM,+    CONVERSION_QUALITY_LO
> > W,+    CONVERSION_QUALITY_LOWCPU,+};++#define SOUT_CFG_PREFIX "sout-dlna-"++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/20181126/030c3b84/attachment-0001.html>


More information about the vlc-devel mailing list