diff --git a/0001-Fix-leaking-AvahiServiceResolver-in-the-error-paths.patch b/0001-Fix-leaking-AvahiServiceResolver-in-the-error-paths.patch new file mode 100644 index 0000000..7788084 --- /dev/null +++ b/0001-Fix-leaking-AvahiServiceResolver-in-the-error-paths.patch @@ -0,0 +1,55 @@ +From 5ae7c3aa2847b44f188704049724424b5eb3cdaf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Stefan=20Br=C3=BCns?= +Date: Tue, 25 Dec 2018 03:46:59 +0100 +Subject: [PATCH 1/2] Fix leaking AvahiServiceResolver in the error paths + +--- + modules/services_discovery/avahi.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/modules/services_discovery/avahi.c b/modules/services_discovery/avahi.c +index 1d71cc82d3..aa58c7f673 100644 +--- a/modules/services_discovery/avahi.c ++++ b/modules/services_discovery/avahi.c +@@ -148,7 +148,10 @@ static void resolve_callback( + avahi_address_snprint(a, (sizeof(a)/sizeof(a[0]))-1, address); + if( protocol == AVAHI_PROTO_INET6 ) + if( asprintf( &psz_addr, "[%s]", a ) == -1 ) ++ { ++ avahi_service_resolver_free( r ); + return; ++ } + + const char *psz_protocol = NULL; + for( unsigned int i = 0; i < NB_PROTOCOLS; i++ ) +@@ -157,7 +160,11 @@ static void resolve_callback( + psz_protocol = protocols[i].psz_protocol; + } + if( psz_protocol == NULL ) ++ { ++ free( psz_addr ); ++ avahi_service_resolver_free( r ); + return; ++ } + + if( txt != NULL ) + asl = avahi_string_list_find( txt, "path" ); +@@ -175,6 +182,7 @@ static void resolve_callback( + port, value ) == -1 ) + { + free( psz_addr ); ++ avahi_service_resolver_free( r ); + return; + } + } +@@ -190,6 +198,7 @@ static void resolve_callback( + psz_addr != NULL ? psz_addr : a, port ) == -1 ) + { + free( psz_addr ); ++ avahi_service_resolver_free( r ); + return; + } + } +-- +2.20.1 + diff --git a/0002-Add-Avahi-implementation-for-chromecast-renderer-dis.patch b/0002-Add-Avahi-implementation-for-chromecast-renderer-dis.patch new file mode 100644 index 0000000..19b97bb --- /dev/null +++ b/0002-Add-Avahi-implementation-for-chromecast-renderer-dis.patch @@ -0,0 +1,434 @@ +From c3e38bce3b30c6e0974ec5da47e22260ed5b7ea8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Stefan=20Br=C3=BCns?= +Date: Tue, 25 Dec 2018 03:48:15 +0100 +Subject: [PATCH 2/2] Add Avahi implementation for chromecast renderer + discovery + +--- + modules/services_discovery/avahi.c | 246 ++++++++++++++++++++++++----- + 1 file changed, 209 insertions(+), 37 deletions(-) + +diff --git a/modules/services_discovery/avahi.c b/modules/services_discovery/avahi.c +index aa58c7f673..527e08a2e9 100644 +--- a/modules/services_discovery/avahi.c ++++ b/modules/services_discovery/avahi.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -48,8 +49,11 @@ + /* Callbacks */ + static int Open ( vlc_object_t * ); + static void Close( vlc_object_t * ); ++static int OpenRD ( vlc_object_t * ); ++static void CloseRD( vlc_object_t * ); + + VLC_SD_PROBE_HELPER("avahi", N_("Zeroconf network services"), SD_CAT_LAN) ++VLC_RD_PROBE_HELPER( "avahi_renderer", "Avahi Zeroconf renderer Discovery" ) + + vlc_module_begin () + set_shortname( "Avahi" ) +@@ -61,45 +65,153 @@ vlc_module_begin () + add_shortcut( "mdns", "avahi" ) + + VLC_SD_PROBE_SUBMODULE ++ add_submodule() \ ++ set_description( N_( "Avahi Renderer Discovery" ) ) ++ set_category( CAT_SOUT ) ++ set_subcategory( SUBCAT_SOUT_RENDERER ) ++ set_capability( "renderer_discovery", 0 ) ++ set_callbacks( OpenRD, CloseRD ) ++ add_shortcut( "mdns_renderer", "avahi_renderer" ) ++ VLC_RD_PROBE_SUBMODULE + vlc_module_end () + + /***************************************************************************** + * Local structures + *****************************************************************************/ + +-struct services_discovery_sys_t ++typedef ++struct + { + AvahiThreadedPoll *poll; + AvahiClient *client; + vlc_dictionary_t services_name_to_input_item; +-}; ++ vlc_object_t *parent; ++ bool renderer; ++} discovery_sys_t; ++ ++struct vlc_renderer_discovery_sys ++{ ++ discovery_sys_t s; ++}; ++ ++struct services_discovery_sys_t ++{ ++ discovery_sys_t s; ++}; + + static const struct + { + const char *psz_protocol; + const char *psz_service_name; ++ bool b_renderer; + } protocols[] = { +- { "ftp", "_ftp._tcp" }, +- { "smb", "_smb._tcp" }, +- { "nfs", "_nfs._tcp" }, +- { "sftp", "_sftp-ssh._tcp" }, +- { "rtsp", "_rtsp._tcp" }, ++ { "ftp", "_ftp._tcp", false }, ++ { "smb", "_smb._tcp", false }, ++ { "nfs", "_nfs._tcp", false }, ++ { "sftp", "_sftp-ssh._tcp", false }, ++ { "rtsp", "_rtsp._tcp", false }, ++ { "chromecast", "_googlecast._tcp", true }, + }; + #define NB_PROTOCOLS (sizeof(protocols) / sizeof(*protocols)) + ++/***************************************************************************** ++ * helpers ++ *****************************************************************************/ ++static void add_renderer( const char *psz_protocol, const char *psz_name, ++ const char *psz_addr, uint16_t i_port, ++ AvahiStringList *txt, discovery_sys_t *p_sys ) ++{ ++ vlc_renderer_discovery_t *p_rd = ( vlc_renderer_discovery_t* )(p_sys->parent); ++ AvahiStringList *asl = NULL; ++ if ( !strcmp( "chromecast", psz_protocol ) ) { ++ int renderer_flags = 0; ++ ++ /* Friendly name */ ++ asl = avahi_string_list_find( txt, "fn" ); ++ if( asl != NULL ) ++ { ++ char *key = NULL; ++ char *value = NULL; ++ if( avahi_string_list_get_pair( asl, &key, &value, NULL ) == 0 && ++ value != NULL ) ++ { ++ ++ } ++ msg_Info( p_rd, "key: '%s' value: '%s'", key, value ); ++ ++ if( key != NULL ) ++ avahi_free( (void *)key ); ++ if( value != NULL ) ++ avahi_free( (void *)value ); ++ } ++ ++ /* capabilities */ ++ asl = avahi_string_list_find( txt, "ca" ); ++ if( asl != NULL ) { ++ char *key = NULL; ++ char *value = NULL; ++ if( avahi_string_list_get_pair( asl, &key, &value, NULL ) == 0 && ++ value != NULL ) ++ { ++ int ca = atoi( value ); ++ ++ if ( ( ca & 0x01 ) != 0 ) ++ renderer_flags |= VLC_RENDERER_CAN_VIDEO; ++ if ( ( ca & 0x04 ) != 0 ) ++ renderer_flags |= VLC_RENDERER_CAN_AUDIO; ++ } ++ msg_Info( p_rd, "key: '%s' value: '%s'", key, value ); ++ ++ if( key != NULL ) ++ avahi_free( (void *)key ); ++ if( value != NULL ) ++ avahi_free( (void *)value ); ++ } ++ /* ++ * "md": model ++ * "id": uuid ++ * "ic": icon URL, relative to http://:8008/ ++ */ ++ ++ const char *extra_uri = renderer_flags & VLC_RENDERER_CAN_VIDEO ? NULL : "no-video"; ++ char *uri = NULL; ++ char *icon_uri = NULL; ++ if( asprintf( &uri, "%s://%s:%u", psz_protocol, psz_addr, i_port ) < 0 ) ++ return; ++ if( asprintf( &icon_uri, "http://%s:8008/setup/icon.png", psz_addr) < 0 ) ++ { ++ free( uri ); ++ return; ++ } ++ ++ vlc_renderer_item_t *p_renderer_item = ++ vlc_renderer_item_new( "chromecast", psz_name, uri, extra_uri, ++ "cc_demux", icon_uri, renderer_flags ); ++ if( p_renderer_item == NULL ) { ++ free( uri ); ++ free( icon_uri ); ++ return; ++ } ++ ++ vlc_dictionary_insert( &p_sys->services_name_to_input_item, ++ psz_name, p_renderer_item); ++ vlc_rd_add_item( p_rd, p_renderer_item ); ++ vlc_renderer_item_release( p_renderer_item ); ++ } ++} ++ + /***************************************************************************** + * client_callback + *****************************************************************************/ + static void client_callback( AvahiClient *c, AvahiClientState state, + void * userdata ) + { +- services_discovery_t *p_sd = ( services_discovery_t* )userdata; +- services_discovery_sys_t *p_sys = p_sd->p_sys; ++ discovery_sys_t *p_sys = userdata; + + if( state == AVAHI_CLIENT_FAILURE && + (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) ) + { +- msg_Err( p_sd, "avahi client disconnected" ); ++ msg_Err( p_sys->parent, "avahi client disconnected" ); + avahi_threaded_poll_quit( p_sys->poll ); + } + } +@@ -122,15 +234,14 @@ static void resolve_callback( + AvahiLookupResultFlags flags, + void* userdata ) + { +- services_discovery_t *p_sd = ( services_discovery_t* )userdata; +- services_discovery_sys_t *p_sys = p_sd->p_sys; ++ discovery_sys_t *p_sys = userdata; + + VLC_UNUSED(interface); VLC_UNUSED(host_name); + VLC_UNUSED(flags); + + if( event == AVAHI_RESOLVER_FAILURE ) + { +- msg_Err( p_sd, ++ msg_Err( p_sys->parent, + "failed to resolve service '%s' of type '%s' in domain '%s'", + name, type, domain ); + } +@@ -142,7 +253,7 @@ static void resolve_callback( + AvahiStringList *asl = NULL; + input_item_t *p_input = NULL; + +- msg_Info( p_sd, "service '%s' of type '%s' in domain '%s' port %i", ++ msg_Info( p_sys->parent, "service '%s' of type '%s' in domain '%s' port %i", + name, type, domain, port ); + + avahi_address_snprint(a, (sizeof(a)/sizeof(a[0]))-1, address); +@@ -154,10 +265,15 @@ static void resolve_callback( + } + + const char *psz_protocol = NULL; ++ bool is_renderer = false; + for( unsigned int i = 0; i < NB_PROTOCOLS; i++ ) + { + if( !strcmp(type, protocols[i].psz_service_name) ) ++ { + psz_protocol = protocols[i].psz_protocol; ++ is_renderer = protocols[i].b_renderer; ++ break; ++ } + } + if( psz_protocol == NULL ) + { +@@ -166,6 +282,15 @@ static void resolve_callback( + return; + } + ++ if( txt != NULL && is_renderer ) ++ { ++ const char* addr_v4v6 = psz_addr != NULL ? psz_addr : a; ++ add_renderer( psz_protocol, name, addr_v4v6, port, txt, p_sys ); ++ free( psz_addr ); ++ avahi_service_resolver_free( r ); ++ return; ++ } ++ + if( txt != NULL ) + asl = avahi_string_list_find( txt, "path" ); + if( asl != NULL ) +@@ -212,6 +337,7 @@ static void resolve_callback( + } + if( p_input != NULL ) + { ++ services_discovery_t *p_sd = ( services_discovery_t* )(p_sys->parent); + vlc_dictionary_insert( &p_sys->services_name_to_input_item, + name, p_input ); + services_discovery_AddItem( p_sd, p_input ); +@@ -238,8 +364,8 @@ static void browse_callback( + { + VLC_UNUSED(b); + VLC_UNUSED(flags); +- services_discovery_t *p_sd = ( services_discovery_t* )userdata; +- services_discovery_sys_t *p_sys = p_sd->p_sys; ++ discovery_sys_t *p_sys = userdata; ++ msg_Info( p_sys->parent, "browse_callback - event: %d, name: %s, type: %s", event, name, type); + if( event == AVAHI_BROWSER_NEW ) + { + if( avahi_service_resolver_new( p_sys->client, interface, protocol, +@@ -247,22 +373,32 @@ static void browse_callback( + 0, + resolve_callback, userdata ) == NULL ) + { +- msg_Err( p_sd, "failed to resolve service '%s': %s", name, ++ msg_Err( p_sys->parent, "failed to resolve service '%s': %s", name, + avahi_strerror( avahi_client_errno( p_sys->client ) ) ); + } + } + else if( name ) + { + /** \todo Store the input id and search it, rather than searching the items */ +- input_item_t *p_item; ++ void *p_item; + p_item = vlc_dictionary_value_for_key( + &p_sys->services_name_to_input_item, + name ); + if( !p_item ) +- msg_Err( p_sd, "failed to find service '%s' in playlist", name ); ++ msg_Err( p_sys->parent, "failed to find service '%s' in playlist", name ); + else + { +- services_discovery_RemoveItem( p_sd, p_item ); ++ if( p_sys->renderer ) ++ { ++ vlc_renderer_discovery_t *p_rd = ( vlc_renderer_discovery_t* )(p_sys->parent); ++ vlc_rd_remove_item( p_rd, p_item ); ++ } ++ else ++ { ++ //input_item_t *p_item; ++ services_discovery_t *p_sd = ( services_discovery_t* )(p_sys->parent); ++ services_discovery_RemoveItem( p_sd, p_item ); ++ } + vlc_dictionary_remove_value_for_key( + &p_sys->services_name_to_input_item, + name, NULL, NULL ); +@@ -273,46 +409,41 @@ static void browse_callback( + /***************************************************************************** + * Open: initialize and create stuff + *****************************************************************************/ +-static int Open( vlc_object_t *p_this ) ++static int OpenCommon( discovery_sys_t *p_sys ) + { +- services_discovery_t *p_sd = ( services_discovery_t* )p_this; +- services_discovery_sys_t *p_sys; + int err; + +- p_sd->p_sys = p_sys = calloc( 1, sizeof( services_discovery_sys_t ) ); +- if( !p_sys ) +- return VLC_ENOMEM; +- +- p_sd->description = _("Zeroconf network services"); +- + vlc_dictionary_init( &p_sys->services_name_to_input_item, 1 ); + + p_sys->poll = avahi_threaded_poll_new(); + if( p_sys->poll == NULL ) + { +- msg_Err( p_sd, "failed to create Avahi threaded poll" ); ++ msg_Err( p_sys->parent, "failed to create Avahi threaded poll" ); + goto error; + } + + p_sys->client = avahi_client_new( avahi_threaded_poll_get(p_sys->poll), +- 0, client_callback, p_sd, &err ); ++ 0, client_callback, p_sys, &err ); + if( p_sys->client == NULL ) + { +- msg_Err( p_sd, "failed to create avahi client: %s", ++ msg_Err( p_sys->parent, "failed to create avahi client: %s", + avahi_strerror( err ) ); + goto error; + } + + for( unsigned i = 0; i < NB_PROTOCOLS; i++ ) + { ++ if ( protocols[i].b_renderer != p_sys->renderer ) ++ continue; ++ + AvahiServiceBrowser *sb; + sb = avahi_service_browser_new( p_sys->client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + protocols[i].psz_service_name, NULL, +- 0, browse_callback, p_sd ); ++ 0, browse_callback, p_sys ); + if( sb == NULL ) + { +- msg_Err( p_sd, "failed to create avahi service browser %s", avahi_strerror( avahi_client_errno(p_sys->client) ) ); ++ msg_Err( p_sys->parent, "failed to create avahi service browser %s", avahi_strerror( avahi_client_errno(p_sys->client) ) ); + goto error; + } + } +@@ -333,13 +464,39 @@ error: + return VLC_EGENERIC; + } + ++static int Open( vlc_object_t *p_this ) ++{ ++ services_discovery_t *p_sd = ( services_discovery_t* )p_this; ++ p_sd->description = _("Zeroconf network services"); ++ ++ p_sd->p_sys = calloc( 1, sizeof( services_discovery_sys_t ) ); ++ if( !p_sd->p_sys ) ++ return VLC_ENOMEM; ++ p_sd->p_sys->s.parent = p_this; ++ p_sd->p_sys->s.renderer = false; ++ ++ return OpenCommon( &p_sd->p_sys->s ); ++} ++ ++static int OpenRD( vlc_object_t *p_this ) ++{ ++ vlc_renderer_discovery_t *p_rd = (vlc_renderer_discovery_t *)p_this; ++ ++ p_rd->p_sys = calloc( 1, sizeof( vlc_renderer_discovery_sys ) ); ++ if( !p_rd->p_sys ) ++ return VLC_ENOMEM; ++ p_rd->p_sys->s.parent = p_this; ++ p_rd->p_sys->s.renderer = true; ++ ++ msg_Info( p_this, "Opening Avahi Renderer SD"); ++ return OpenCommon( &p_rd->p_sys->s ); ++} ++ + /***************************************************************************** + * Close: cleanup + *****************************************************************************/ +-static void Close( vlc_object_t *p_this ) ++static void CloseCommon( discovery_sys_t *p_sys ) + { +- services_discovery_t *p_sd = ( services_discovery_t* )p_this; +- services_discovery_sys_t *p_sys = p_sd->p_sys; + avahi_threaded_poll_stop( p_sys->poll ); + + avahi_client_free( p_sys->client ); +@@ -348,3 +505,18 @@ static void Close( vlc_object_t *p_this ) + vlc_dictionary_clear( &p_sys->services_name_to_input_item, NULL, NULL ); + free( p_sys ); + } ++ ++static void Close( vlc_object_t *p_this ) ++{ ++ services_discovery_t *p_sd = ( services_discovery_t* )p_this; ++ services_discovery_sys_t *p_sys = p_sd->p_sys; ++ CloseCommon( &p_sys->s ); ++} ++ ++static void CloseRD( vlc_object_t *p_this ) ++{ ++ msg_Info( p_this, "Closing Avahi Renderer SD"); ++ vlc_renderer_discovery_t *p_rd = (vlc_renderer_discovery_t *)p_this; ++ vlc_renderer_discovery_sys *p_sys = p_rd->p_sys; ++ CloseCommon( &p_sys->s ); ++} +-- +2.20.1 + diff --git a/vlc.changes b/vlc.changes index d479aa4..78618e7 100644 --- a/vlc.changes +++ b/vlc.changes @@ -8,6 +8,16 @@ Thu Jan 10 20:48:42 UTC 2019 - seanlew@opensuse.org * Add support for 12 bits decoding of AV1 * Fix HDR support in AV1 when the container provides the metadata +------------------------------------------------------------------- +Thu Jan 3 18:38:26 UTC 2019 - Stefan BrĂ¼ns + +- Add support for Chromecast discovery with Avahi. The current upstream + implementation uses microdns, which is not available in openSUSE, and + would also cause problems (2 mDNS implemenations running concurrently). + * Add 0001-Fix-leaking-AvahiServiceResolver-in-the-error-paths.patch + * Add 0002-Add-Avahi-implementation-for-chromecast-renderer-dis.patch +- Spec file cleanup, remove obsolete suse_version checks + ------------------------------------------------------------------- Sat Dec 29 02:42:11 UTC 2018 - sean@suspend.net diff --git a/vlc.spec b/vlc.spec index 7d0aa6a..162a61d 100644 --- a/vlc.spec +++ b/vlc.spec @@ -49,6 +49,10 @@ Patch1: vlc-allow-deprecated-fribidi.patch Patch2: vlc-lua-5.3.patch # PATCH-FEATURE-OPENSUSE vlc-projectM-qt5.patch -- Build against projectM-qt5; openSUSE provides projectM as -qt and -qt5 variant Patch100: vlc-projectM-qt5.patch +# PATCH-FIX-UPSTREAM 0001-Fix-leaking-AvahiServiceResolver-in-the-error-paths.patch -- Fix some memleaks +Patch101: 0001-Fix-leaking-AvahiServiceResolver-in-the-error-paths.patch +# PATCH-FIX-UPSTREAM 0002-Add-Avahi-implementation-for-chromecast-renderer-dis.patch -- Use Avahi for discovery, microdns is not available +Patch102: 0002-Add-Avahi-implementation-for-chromecast-renderer-dis.patch BuildRequires: Mesa-devel BuildRequires: SDL-devel >= 1.2.10 BuildRequires: aalib-devel @@ -323,8 +327,8 @@ This package adds jack support to vlc via plugins. %package codecs Summary: Additional codecs for the VLC media player Group: Productivity/Multimedia/Video/Players -Requires: %(rpm --qf "%%{name}" -qf $(readlink -f %{_libdir}/libavcodec.so))(unrestricted) # We require the unrestricted libavcodec - same ABI version we linked +Requires: %(rpm --qf "%%{name}" -qf $(readlink -f %{_libdir}/libavcodec.so))(unrestricted) Requires: %{name}-noX = %{version} # We need the noX package first, as it contains vlc-cache-gen Requires(post): %{name}-noX @@ -337,8 +341,8 @@ codecs that are not available in the stock openSUSE distribution. %package vdpau Summary: Additional vdpau codecs for the VLC media player Group: Productivity/Multimedia/Video/Players -Requires: %(rpm --qf "%%{name}" -qf $(readlink -f %{_libdir}/libavcodec.so))(unrestricted) # We require the unrestricted libavcodec - same ABI version we linked +Requires: %(rpm --qf "%%{name}" -qf $(readlink -f %{_libdir}/libavcodec.so))(unrestricted) Requires: %{name}-codecs = %{version} Requires: %{name}-noX = %{version} # We need the noX package first, as it contains vlc-cache-gen @@ -358,11 +362,7 @@ Requires: %{name}-noX = %{version}-%{release} # We need the noX package first, as it contains vlc-cache-gen Requires(post): %{name}-noX Conflicts: %{conflicts}-qt -%if 0%{?suse_version} >= 1310 Supplements: packageand(%{name}-noX:libqt5) -%else -Supplements: packageand(%{name}-noX:libqt4) -%endif %description qt This subpackage provides a Qt interface for VLC and selects it by @@ -375,6 +375,8 @@ default when `vlc` is invoked from an X session. %if 0%{?suse_version} > 1320 %patch100 -p1 %endif +%patch101 -p1 +%patch102 -p1 ### And LUA 5.3.1 has some more API changes if pkg-config --atleast-version 5.3.1 lua; then @@ -596,7 +598,7 @@ done %endif %{_libdir}/vlc/plugins/text_renderer/libfreetype_plugin.so %{_libdir}/vlc/plugins/text_renderer/libsvg_plugin.so -%if 0%{?suse_version} >= 1140 && 0%{?suse_version} != 1315 || 0%{?BUILD_ORIG} +%if 0%{?suse_version} != 1315 || 0%{?BUILD_ORIG} %{_libdir}/vlc/plugins/video_chroma/libswscale_plugin.so %endif %if 0%{?is_opensuse}