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

Thomas Guillem thomas at gllm.fr
Mon Nov 26 16:49:23 CET 2018


dlna out is not working for me on few devices I tested.
Here is the log: https://gist.github.com/tguillem/eb3bd59fa184e243463e8683c66adf70

On Mon, Nov 26, 2018, at 16:33, Thomas Guillem wrote:
> use-after-free when playing a file that failed to be transcoded: 
> https://gist.github.com/tguillem/33a8c0489972efa009291596fb794137
> 
> On Mon, Nov 26, 2018, at 15:48, 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 Renderers
> > > which implement the AVTransport service with the
> > > initial 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/NEWS
> > > index 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 support
> > > diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
> > > index 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 ES
> > > diff --git a/modules/services_discovery/Makefile.am b/modules/
> > > services_discovery/Makefile.am
> > > index 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/dlna_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.cpp
> > > index 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/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)
> > > +        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.
> > >  
> > >  /*
> > > diff --git a/modules/services_discovery/upnp.hpp b/modules/
> > > services_discovery/upnp.hpp
> > > index 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.cpp
> > > new file mode 100644
> > > index 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;
> > > +
> > > +private:
> > > +    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::string
> > > +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
> > 
> > > +
> > > +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);
> > > +        }
> > > +        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 );
> > > +                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_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.hpp
> > > new file mode 100644
> > > index 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.hpp
> > > new file mode 100644
> > > index 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_LOW,
> > > +    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 list
> > > To unsubscribe or modify your subscription options:
> > > https://mailman.videolan.org/listinfo/vlc-devel
> > 
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list