From 667f188961341ded83b0b17527a71961701e945f Mon Sep 17 00:00:00 2001 From: Antoine Cellerier Date: Sat, 29 Oct 2005 14:27:18 +0000 Subject: [PATCH] changesets r12782 and r12804 from 0.8.5-zorglub branch concerning podcast service discovery and demux modules. --- configure.ac | 2 +- modules/demux/playlist/Modules.am | 3 +- modules/demux/playlist/playlist.c | 5 + modules/demux/playlist/playlist.h | 3 + modules/demux/playlist/podcast.c | 493 ++++++++++++++++++++++++++ modules/services_discovery/Modules.am | 1 + modules/services_discovery/podcast.c | 229 ++++++++++++ 7 files changed, 734 insertions(+), 2 deletions(-) create mode 100644 modules/demux/playlist/podcast.c create mode 100644 modules/services_discovery/podcast.c diff --git a/configure.ac b/configure.ac index a749f66abe..527299af77 100644 --- a/configure.ac +++ b/configure.ac @@ -1014,7 +1014,7 @@ VLC_ADD_PLUGINS([packetizer_mpeg4video packetizer_mpeg4audio]) if test "${SYS}" != "mingwce"; then dnl VLC_ADD_PLUGINS([externrun]) VLC_ADD_PLUGINS([access_fake access_filter_timeshift access_filter_record]) - VLC_ADD_PLUGINS([gestures rc telnet hotkeys netsync showintf time marq shout sap fake]) + VLC_ADD_PLUGINS([gestures rc telnet hotkeys netsync showintf time marq podcast shout sap fake]) VLC_ADD_PLUGINS([rss mosaic wall motiondetect clone crop]) VLC_ADD_PLUGINS([i420_yuy2 i422_yuy2 i420_ymga]) VLC_ADD_PLUGINS([aout_file linear_resampler bandlimited_resampler]) diff --git a/modules/demux/playlist/Modules.am b/modules/demux/playlist/Modules.am index 794fed6d91..8b730dfa47 100644 --- a/modules/demux/playlist/Modules.am +++ b/modules/demux/playlist/Modules.am @@ -4,4 +4,5 @@ SOURCES_playlist = playlist.c \ m3u.c \ b4s.c \ pls.c \ - dvb.c + dvb.c \ + podcast.c diff --git a/modules/demux/playlist/playlist.c b/modules/demux/playlist/playlist.c index c9c915dd64..a2b8503f5e 100644 --- a/modules/demux/playlist/playlist.c +++ b/modules/demux/playlist/playlist.c @@ -79,6 +79,11 @@ vlc_module_begin(); add_shortcut( "dvb-open" ); set_capability( "demux2", 10 ); set_callbacks( E_(Import_DVB), E_(Close_DVB) ); + add_submodule(); + set_description( _("Podcast playlist import") ); + add_shortcut( "podcast" ); + set_capability( "demux2", 10 ); + set_callbacks( E_(Import_podcast), E_(Close_podcast) ); vlc_module_end(); diff --git a/modules/demux/playlist/playlist.h b/modules/demux/playlist/playlist.h index 1c7b60a216..251826e2ba 100644 --- a/modules/demux/playlist/playlist.h +++ b/modules/demux/playlist/playlist.h @@ -42,3 +42,6 @@ void E_(Close_B4S) ( vlc_object_t * ); int E_(Import_DVB) ( vlc_object_t * ); void E_(Close_DVB) ( vlc_object_t * ); + +int E_(Import_podcast) ( vlc_object_t * ); +void E_(Close_podcast) ( vlc_object_t * ); diff --git a/modules/demux/playlist/podcast.c b/modules/demux/playlist/podcast.c new file mode 100644 index 0000000000..7f6545d798 --- /dev/null +++ b/modules/demux/playlist/podcast.c @@ -0,0 +1,493 @@ +/***************************************************************************** + * podcast.c : podcast playlist imports + ***************************************************************************** + * Copyright (C) 2005 the VideoLAN team + * $Id$ + * + * Authors: Antoine Cellerier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include /* malloc(), free() */ +#include /* isspace() */ + +#include +#include +#include + +#include /* ENOMEM */ +#include "playlist.h" +#include "vlc_xml.h" + +struct demux_sys_t +{ + char *psz_prefix; + playlist_t *p_playlist; + xml_t *p_xml; + xml_reader_t *p_xml_reader; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static int Demux( demux_t *p_demux); +static int Control( demux_t *p_demux, int i_query, va_list args ); + +/***************************************************************************** + * Import_podcast: main import function + *****************************************************************************/ +int E_(Import_podcast)( vlc_object_t *p_this ) +{ + demux_t *p_demux = (demux_t *)p_this; + demux_sys_t *p_sys; + + char *psz_ext; + + psz_ext = strrchr ( p_demux->psz_path, '.' ); + + if( p_demux->psz_demux && !strcmp(p_demux->psz_demux, "podcast") ) + { + ; + } + else + { + return VLC_EGENERIC; + } + msg_Dbg( p_demux, "using podcast playlist import"); + + p_demux->pf_control = Control; + p_demux->pf_demux = Demux; + p_demux->p_sys = p_sys = malloc( sizeof(demux_sys_t) ); + if( p_sys == NULL ) + { + msg_Err( p_demux, "Out of memory" ); + return VLC_ENOMEM; + } + p_sys->psz_prefix = E_(FindPrefix)( p_demux ); + p_sys->p_playlist = NULL; + p_sys->p_xml = NULL; + p_sys->p_xml_reader = NULL; + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Deactivate: frees unused data + *****************************************************************************/ +void E_(Close_podcast)( vlc_object_t *p_this ) +{ + demux_t *p_demux = (demux_t *)p_this; + demux_sys_t *p_sys = p_demux->p_sys; + + if( p_sys->psz_prefix ) free( p_sys->psz_prefix ); + if( p_sys->p_playlist ) vlc_object_release( p_sys->p_playlist ); + if( p_sys->p_xml_reader ) xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader ); + if( p_sys->p_xml ) xml_Delete( p_sys->p_xml ); + free( p_sys ); +} + +/* "specs" : http://phobos.apple.com/static/iTunesRSS.html */ +static int Demux( demux_t *p_demux ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + playlist_t *p_playlist; + playlist_item_t *p_item, *p_current; + + vlc_bool_t b_play; + vlc_bool_t b_item = VLC_FALSE; + vlc_bool_t b_image = VLC_FALSE; + int i_ret; + + xml_t *p_xml; + xml_reader_t *p_xml_reader; + char *psz_elname = NULL; + char *psz_item_mrl = NULL; + char *psz_item_size = NULL; + char *psz_item_type = NULL; + char *psz_item_name = NULL; + char *psz_item_date = NULL; + char *psz_item_author = NULL; + char *psz_item_category = NULL; + char *psz_item_duration = NULL; + char *psz_item_keywords = NULL; + char *psz_item_subtitle = NULL; + char *psz_item_summary = NULL; + int i_type; + + p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST, + FIND_PARENT ); + if( !p_playlist ) + { + msg_Err( p_demux, "can't find playlist" ); + return -1; + } + p_sys->p_playlist = p_playlist; + + b_play = E_(FindItem)( p_demux, p_playlist, &p_current ); + + playlist_ItemToNode( p_playlist, p_current ); + p_current->input.i_type = ITEM_TYPE_PLAYLIST; + + p_xml = p_sys->p_xml = xml_Create( p_demux ); + if( !p_xml ) return -1; + + psz_elname = stream_ReadLine( p_demux->s ); + if( psz_elname ) free( psz_elname ); + psz_elname = 0; + + p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s ); + if( !p_xml_reader ) return -1; + p_sys->p_xml_reader = p_xml_reader; + + /* xml */ + /* check root node */ + if( xml_ReaderRead( p_xml_reader ) != 1 ) + { + msg_Err( p_demux, "invalid file (no root node)" ); + return -1; + } + if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM || + ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL || + strcmp( psz_elname, "rss" ) ) + { + msg_Err( p_demux, "invalid root node %i, %s", + xml_ReaderNodeType( p_xml_reader ), psz_elname ); + if( psz_elname ) free( psz_elname ); + return -1; + } + free( psz_elname ); psz_elname = NULL; + + while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 ) + { + // Get the node type + i_type = xml_ReaderNodeType( p_xml_reader ); + switch( i_type ) + { + // Error + case -1: + return -1; + break; + + case XML_READER_STARTELEM: + { + // Read the element name + if( psz_elname ) free( psz_elname ); + psz_elname = xml_ReaderName( p_xml_reader ); + if( !psz_elname ) return -1; + + if( !strcmp( psz_elname, "item" ) ) + { + b_item = VLC_TRUE; + } + else if( !strcmp( psz_elname, "image" ) ) + { + b_item = VLC_TRUE; + } + + // Read the attributes + while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) + { + char *psz_name = xml_ReaderName( p_xml_reader ); + char *psz_value = xml_ReaderValue( p_xml_reader ); + if( !psz_name || !psz_value ) return -1; + if( !strcmp( psz_elname, "enclosure" ) && + !strcmp( psz_name, "url" ) ) + { + psz_item_mrl = strdup( psz_value ); + } + else if( !strcmp( psz_elname, "enclosure" ) && + !strcmp( psz_name, "length" ) ) + { + psz_item_size = strdup( psz_value ); + } + else if( !strcmp( psz_elname, "enclosure" ) && + !strcmp( psz_name, "type" ) ) + { + psz_item_type = strdup( psz_value ); + } + else + { + msg_Dbg( p_demux,"unhandled attribure %s in element %s", + psz_name, psz_elname ); + } + free( psz_name ); + free( psz_value ); + } + break; + } + case XML_READER_TEXT: + { + char *psz_text = xml_ReaderValue( p_xml_reader ); + /* item specific meta data */ + if( b_item == VLC_TRUE && !strcmp( psz_elname, "title" ) ) + { + psz_item_name = strdup( psz_text ); + } + else if( b_item == VLC_TRUE + && !strcmp( psz_elname, "pubDate" ) ) + { + psz_item_date = strdup( psz_text ); + } + else if( b_item == VLC_TRUE + && ( !strcmp( psz_elname, "itunes:author" ) + ||!strcmp( psz_elname, "author" ) ) ) + { /* isn't standard iTunes podcast stuff */ + psz_item_author = strdup( psz_text ); + } + else if( b_item == VLC_TRUE + && !strcmp( psz_elname, "itunes:category" ) ) + { + psz_item_category = strdup( psz_text ); + } + else if( b_item == VLC_TRUE + && !strcmp( psz_elname, "itunes:duration" ) ) + { + psz_item_duration = strdup( psz_text ); + } + else if( b_item == VLC_TRUE + && !strcmp( psz_elname, "itunes:keywords" ) ) + { + psz_item_keywords = strdup( psz_text ); + } + else if( b_item == VLC_TRUE + && !strcmp( psz_elname, "itunes:subtitle" ) ) + { + psz_item_subtitle = strdup( psz_text ); + } + else if( b_item == VLC_TRUE + && ( !strcmp( psz_elname, "itunes:summary" ) + ||!strcmp( psz_elname, "description" ) ) ) + { /* isn't standard iTunes podcast stuff */ + psz_item_summary = strdup( psz_text ); + } + /* toplevel meta data */ + else if( b_item == VLC_FALSE && b_image == VLC_FALSE + && !strcmp( psz_elname, "title" ) ) + { + playlist_ItemSetName( p_current, psz_text ); + } + else if( b_item == VLC_FALSE && b_image == VLC_FALSE + && !strcmp( psz_elname, "link" ) ) + { + vlc_input_item_AddInfo( &(p_current->input), + _("Meta-information"), + _( "Podcast Link" ), + "%s", + psz_text ); + } + else if( b_item == VLC_FALSE && b_image == VLC_FALSE + && !strcmp( psz_elname, "copyright" ) ) + { + vlc_input_item_AddInfo( &(p_current->input), + _("Meta-information"), + _( "Podcast Copyright" ), + "%s", + psz_text ); + } + else if( b_item == VLC_FALSE && b_image == VLC_FALSE + && !strcmp( psz_elname, "itunes:category" ) ) + { + vlc_input_item_AddInfo( &(p_current->input), + _("Meta-information"), + _( "Podcast Category" ), + "%s", + psz_text ); + } + else if( b_item == VLC_FALSE && b_image == VLC_FALSE + && !strcmp( psz_elname, "itunes:keywords" ) ) + { + vlc_input_item_AddInfo( &(p_current->input), + _("Meta-information"), + _( "Podcast Keywords" ), + "%s", + psz_text ); + } + else if( b_item == VLC_FALSE && b_image == VLC_FALSE + && !strcmp( psz_elname, "itunes:subtitle" ) ) + { + vlc_input_item_AddInfo( &(p_current->input), + _("Meta-information"), + _( "Podcast Subtitle" ), + "%s", + psz_text ); + } + else if( b_item == VLC_FALSE && b_image == VLC_FALSE + && ( !strcmp( psz_elname, "itunes:summary" ) + ||!strcmp( psz_elname, "description" ) ) ) + { /* isn't standard iTunes podcast stuff */ + vlc_input_item_AddInfo( &(p_current->input), + _("Meta-information"), + _( "Podcast Summary" ), + "%s", + psz_text ); + } + else + { + msg_Dbg( p_demux, "unhandled text in element '%s'", + psz_elname ); + } + free( psz_text ); + break; + } + // End element + case XML_READER_ENDELEM: + { + // Read the element name + free( psz_elname ); + psz_elname = xml_ReaderName( p_xml_reader ); + if( !psz_elname ) return -1; + if( !strcmp( psz_elname, "item" ) ) + { + p_item = playlist_ItemNew( p_playlist, psz_item_mrl, + psz_item_name ); + if( p_item == NULL ) break; + playlist_NodeAddItem( p_playlist, p_item, + p_current->pp_parents[0]->i_view, + p_current, PLAYLIST_APPEND, + PLAYLIST_END ); + + /* We need to declare the parents of the node as the + * * same of the parent's ones */ + playlist_CopyParents( p_current, p_item ); + + if( psz_item_date ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Publication Date" ), + "%s", + psz_item_date ); + } + if( psz_item_author ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Author" ), + "%s", + psz_item_author ); + } + if( psz_item_category ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Subcategory" ), + "%s", + psz_item_category ); + } + if( psz_item_duration ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Duration" ), + "%s", + psz_item_duration ); + } + if( psz_item_keywords ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Keywords" ), + "%s", + psz_item_keywords ); + } + if( psz_item_subtitle ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Subtitle" ), + "%s", + psz_item_subtitle ); + } + if( psz_item_summary ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Summary" ), + "%s", + psz_item_summary ); + } + if( psz_item_size ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Size" ), + "%s bytes", + psz_item_size ); + } + if( psz_item_type ) + { + vlc_input_item_AddInfo( &p_item->input, + _("Meta-information"), + _( "Podcast Type" ), + "%s", + psz_item_type ); + } + +#define FREE(a) if( a ) free( a ); a = NULL; + FREE( psz_item_name ); + FREE( psz_item_mrl ); + FREE( psz_item_size ); + FREE( psz_item_type ); + FREE( psz_item_date ); + FREE( psz_item_author ); + FREE( psz_item_category ); + FREE( psz_item_duration ); + FREE( psz_item_keywords ); + FREE( psz_item_subtitle ); + FREE( psz_item_summary ); +#undef FREE + + b_item = VLC_FALSE; + } + else if( !strcmp( psz_elname, "image" ) ) + { + b_image = VLC_FALSE; + } + free( psz_elname ); + psz_elname = strdup(""); + + break; + } + } + } + + if( i_ret != 0 ) + { + msg_Warn( p_demux, "error while parsing data" ); + } + + /* Go back and play the playlist */ + if( b_play && p_playlist->status.p_item && + p_playlist->status.p_item->i_children > 0 ) + { + playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, + p_playlist->status.i_view, + p_playlist->status.p_item, + p_playlist->status.p_item->pp_children[0] ); + } + + vlc_object_release( p_playlist ); + p_sys->p_playlist = NULL; + return VLC_SUCCESS; +} + +static int Control( demux_t *p_demux, int i_query, va_list args ) +{ + return VLC_EGENERIC; +} diff --git a/modules/services_discovery/Modules.am b/modules/services_discovery/Modules.am index 172e2f2b96..b0f59c4d4b 100644 --- a/modules/services_discovery/Modules.am +++ b/modules/services_discovery/Modules.am @@ -4,3 +4,4 @@ SOURCES_daap = daap.c SOURCES_shout = shout.c SOURCES_upnp = upnp.cpp SOURCES_bonjour = bonjour.c +SOURCES_podcast = podcast.c diff --git a/modules/services_discovery/podcast.c b/modules/services_discovery/podcast.c new file mode 100644 index 0000000000..06674f9bb9 --- /dev/null +++ b/modules/services_discovery/podcast.c @@ -0,0 +1,229 @@ +/***************************************************************************** + * podcast.c: Podcast services discovery module + ***************************************************************************** + * Copyright (C) 2005 the VideoLAN team + * $Id$ + * + * Authors: Antoine Cellerier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Includes + *****************************************************************************/ +#include /* malloc(), free() */ + +#include +#include + +#include + +#include "network.h" + +#include /* ENOMEM */ + +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif + +/************************************************************************ + * Macros and definitions + ************************************************************************/ + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ + +/* Callbacks */ + static int Open ( vlc_object_t * ); + static void Close( vlc_object_t * ); + +#define URLS_TEXT N_("Podcast URLs list") +#define URLS_LONGTEXT N_("Podcast '|' (pipe) seperated URLs list") + +vlc_module_begin(); + set_shortname( "Podcast"); + set_description( _("Podcast Service Discovery") ); + set_category( CAT_PLAYLIST ); + set_subcategory( SUBCAT_PLAYLIST_SD ); + + add_string( "podcast-urls", NULL, NULL, + URLS_TEXT, URLS_LONGTEXT, VLC_FALSE ); + + set_capability( "services_discovery", 0 ); + set_callbacks( Open, Close ); + +vlc_module_end(); + + +/***************************************************************************** + * Local structures + *****************************************************************************/ + +struct services_discovery_sys_t +{ + /* playlist node */ + playlist_item_t *p_node; + input_thread_t *p_input; + + char **ppsz_urls; + int i_urls; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ + +/* Main functions */ + static void Run ( services_discovery_t *p_intf ); + +/***************************************************************************** + * Open: initialize and create stuff + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + services_discovery_t *p_sd = ( services_discovery_t* )p_this; + services_discovery_sys_t *p_sys = malloc( + sizeof( services_discovery_sys_t ) ); + + vlc_value_t val; + playlist_t *p_playlist; + playlist_view_t *p_view; + playlist_item_t *p_item; + + int i, j; + char *psz_buf; + char *psz_tmp = psz_buf = var_CreateGetString( p_sd, "podcast-urls" ); + + i = 0; + p_sys->i_urls = 1; + while( psz_buf[i] != 0 ) + if( psz_buf[i++] == '|' ) + p_sys->i_urls++; + + p_sys->ppsz_urls = (char **)malloc( p_sys->i_urls * sizeof( char * ) ); + + i = 0; + j = 0; + while( psz_buf[i] != 0 ) + { + if( psz_buf[i] == '|' ) + { + psz_buf[i] = 0; + p_sys->ppsz_urls[j] = strdup( psz_tmp ); + i++; + j++; + psz_tmp = psz_buf+i; + } + else + i++; + } + p_sys->ppsz_urls[j] = strdup( psz_tmp ); + free( psz_buf ); + + p_sd->pf_run = Run; + p_sd->p_sys = p_sys; + + /* Create our playlist node */ + p_playlist = (playlist_t *)vlc_object_find( p_sd, VLC_OBJECT_PLAYLIST, + FIND_ANYWHERE ); + if( !p_playlist ) + { + msg_Warn( p_sd, "unable to find playlist, cancelling"); + return VLC_EGENERIC; + } + + p_view = playlist_ViewFind( p_playlist, VIEW_CATEGORY ); + p_sys->p_node = playlist_NodeCreate( p_playlist, VIEW_CATEGORY, + _("Podcast"), p_view->p_root ); + for( i = 0; i < p_sys->i_urls; i++ ) + { + asprintf( &psz_buf, "%s", p_sys->ppsz_urls[i] ); + p_item = playlist_ItemNew( p_playlist, psz_buf, + p_sys->ppsz_urls[i] ); + free( psz_buf ); + playlist_ItemAddOption( p_item, "demux=podcast" ); + playlist_NodeAddItem( p_playlist, p_item, + p_sys->p_node->pp_parents[0]->i_view, + p_sys->p_node, PLAYLIST_APPEND, + PLAYLIST_END ); + + /* We need to declare the parents of the node as the same of the + * parent's ones */ + playlist_CopyParents( p_sys->p_node, p_item ); + p_sys->p_input = input_CreateThread( p_playlist, &p_item->input ); + } + + + p_sys->p_node->i_flags |= PLAYLIST_RO_FLAG; + val.b_bool = VLC_TRUE; + var_Set( p_playlist, "intf-change", val ); + + vlc_object_release( p_playlist ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: + *****************************************************************************/ +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; + playlist_t *p_playlist = (playlist_t *) vlc_object_find( p_sd, + VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); + int i; + if( p_sd->p_sys->p_input ) + { + input_StopThread( p_sd->p_sys->p_input ); + input_DestroyThread( p_sd->p_sys->p_input ); + vlc_object_detach( p_sd->p_sys->p_input ); + vlc_object_destroy( p_sd->p_sys->p_input ); + p_sd->p_sys->p_input = NULL; + } + if( p_playlist ) + { + playlist_NodeDelete( p_playlist, p_sys->p_node, VLC_TRUE, VLC_TRUE ); + vlc_object_release( p_playlist ); + } + for( i = 0; i < p_sys->i_urls; i++ ) free( p_sys->ppsz_urls[i] ); + free( p_sys->ppsz_urls ); + free( p_sys ); +} + +/***************************************************************************** + * Run: main thread + *****************************************************************************/ +static void Run( services_discovery_t *p_sd ) +{ + while( !p_sd->b_die ) + { + if( p_sd->p_sys->p_input && + ( p_sd->p_sys->p_input->b_eof || p_sd->p_sys->p_input->b_error ) ) + { + input_StopThread( p_sd->p_sys->p_input ); + input_DestroyThread( p_sd->p_sys->p_input ); + vlc_object_detach( p_sd->p_sys->p_input ); + vlc_object_destroy( p_sd->p_sys->p_input ); + p_sd->p_sys->p_input = NULL; + } + msleep( 100000 ); + } +} -- 2.39.2