X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Finput%2Finput.c;h=25252d818583c538d3e8eec2c15b95eaade23c90;hb=d1296b32da7293d0f780cdb9b4782c84e39fb1da;hp=e69cab1d19e521e54e657ebc48c272ed3b4a9910;hpb=b8ff945d3ae771d67149726021c5045fda7a6adf;p=vlc diff --git a/src/input/input.c b/src/input/input.c index e69cab1d19..25252d8185 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -3,8 +3,8 @@ * Read an MPEG2 stream, demultiplex and parse it before sending it to * decoders. ***************************************************************************** - * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: input.c,v 1.159 2001/11/25 05:04:38 stef Exp $ + * Copyright (C) 1998-2002 VideoLAN + * $Id: input.c,v 1.215 2002/11/11 14:39:12 sam Exp $ * * Authors: Christophe Massiot * @@ -26,80 +26,36 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include "defs.h" - #include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -# include -#elif defined( _MSC_VER ) && defined( _WIN32 ) -# include -#endif -#include -#include +#include -#ifdef STRNCASECMP_IN_STRINGS_H -# include -#endif - -#ifdef WIN32 -# include -#elif !defined( SYS_BEOS ) && !defined( SYS_NTO ) -# include /* hostent ... */ -# include -# include -# ifdef HAVE_ARPA_INET_H -# include /* inet_ntoa(), inet_aton() */ -# endif -#endif +#include #ifdef HAVE_SYS_TIMES_H # include #endif -#include "config.h" -#include "common.h" -#include "threads.h" -#include "mtime.h" -#include "tests.h" #include "netutils.h" -#include "modules.h" - -#include "intf_msg.h" -#include "intf_playlist.h" +#include "vlc_playlist.h" #include "stream_control.h" #include "input_ext-intf.h" #include "input_ext-dec.h" #include "input_ext-plugins.h" -#include "interface.h" +#include "stream_output.h" -#include "main.h" +#include "interface.h" /***************************************************************************** * Local prototypes *****************************************************************************/ -static void RunThread ( input_thread_t *p_input ); +static int RunThread ( input_thread_t *p_input ); static int InitThread ( input_thread_t *p_input ); static void ErrorThread ( input_thread_t *p_input ); -static void CloseThread ( input_thread_t *p_input ); -static void DestroyThread ( input_thread_t *p_input ); static void EndThread ( input_thread_t *p_input ); -static void FileOpen ( input_thread_t *p_input ); -static void StdOpen ( input_thread_t *p_input ); -static void FileClose ( input_thread_t *p_input ); -#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) -static void NetworkOpen ( input_thread_t *p_input ); -static void HTTPOpen ( input_thread_t *p_input ); -static void NetworkClose ( input_thread_t *p_input ); -#endif - /***************************************************************************** * input_CreateThread: creates a new input thread ***************************************************************************** @@ -108,49 +64,68 @@ static void NetworkClose ( input_thread_t *p_input ); * If pi_status is NULL, then the function will block until the thread is ready. * If not, it will be updated using one of the THREAD_* constants. *****************************************************************************/ -input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) +input_thread_t *__input_CreateThread( vlc_object_t *p_parent, + playlist_item_t *p_item, int *pi_status ) { input_thread_t * p_input; /* thread descriptor */ - int i_status; /* thread status */ + input_info_category_t * p_info; /* Allocate descriptor */ - p_input = (input_thread_t *)malloc( sizeof(input_thread_t) ); + p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT ); if( p_input == NULL ) { - intf_ErrMsg( "input error: can't allocate input thread (%s)", - strerror(errno) ); - return( NULL ); + msg_Err( p_parent, "out of memory" ); + return NULL; } - /* Packets read once */ - p_input->i_read_once = INPUT_READ_ONCE; - /* Initialize thread properties */ - p_input->b_die = 0; - p_input->b_error = 0; - p_input->b_eof = 0; + p_input->b_eof = 0; /* Set target */ - p_input->p_source = p_item->psz_name; + p_input->psz_source = strdup( p_item->psz_name ); - /* I have never understood that stuff --Meuuh */ - p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status; - *p_input->pi_status = THREAD_CREATE; + /* Demux */ + p_input->p_demux = NULL; + + /* Access */ + p_input->p_access = NULL; + + p_input->i_bufsize = 0; + p_input->i_mtu = 0; + + /* Initialize statistics */ + p_input->c_loops = 0; + p_input->stream.c_packets_read = 0; + p_input->stream.c_packets_trashed = 0; + + /* Set locks. */ + vlc_mutex_init( p_input, &p_input->stream.stream_lock ); + vlc_cond_init( p_input, &p_input->stream.stream_wait ); + vlc_mutex_init( p_input, &p_input->stream.control.control_lock ); /* Initialize stream description */ + p_input->stream.b_changed = 0; p_input->stream.i_es_number = 0; p_input->stream.i_selected_es_number = 0; p_input->stream.i_pgrm_number = 0; p_input->stream.i_new_status = p_input->stream.i_new_rate = 0; p_input->stream.b_new_mute = MUTE_NO_CHANGE; p_input->stream.i_mux_rate = 0; + p_input->stream.b_seekable = 0; + p_input->stream.p_sout = NULL; + + /* no stream, no program, no area, no es */ + p_input->stream.p_new_program = NULL; - /* no stream, no area */ p_input->stream.i_area_nb = 0; p_input->stream.pp_areas = NULL; p_input->stream.p_selected_area = NULL; p_input->stream.p_new_area = NULL; + p_input->stream.pp_selected_es = NULL; + p_input->stream.p_removed_es = NULL; + p_input->stream.p_newly_selected_es = NULL; + /* By default there is one area in a stream */ input_AddArea( p_input ); p_input->stream.p_selected_area = p_input->stream.pp_areas[0]; @@ -159,69 +134,67 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) p_input->stream.control.i_status = PLAYING_S; p_input->stream.control.i_rate = DEFAULT_RATE; p_input->stream.control.b_mute = 0; - p_input->stream.control.b_grayscale = main_GetIntVariable( - VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT ); - p_input->stream.control.i_smp = main_GetIntVariable( - VDEC_SMP_VAR, VDEC_SMP_DEFAULT ); - - intf_WarnMsg( 1, "input: playlist item `%s'", p_input->p_source ); + p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale" ); - /* Create thread. */ - if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread, - (void *) p_input ) ) + /* Initialize input info */ + p_input->stream.p_info = malloc( sizeof( input_info_category_t ) ); + if( !p_input->stream.p_info ) { - intf_ErrMsg( "input error: can't create input thread (%s)", - strerror(errno) ); - free( p_input ); - return( NULL ); + msg_Err( p_input, "No memory!" ); + return NULL; } + p_input->stream.p_info->psz_name = strdup("General") ; + p_input->stream.p_info->p_info = NULL; + p_input->stream.p_info->p_next = NULL; - /* If status is NULL, wait until the thread is created */ - if( pi_status == NULL ) + msg_Info( p_input, "playlist item `%s'", p_input->psz_source ); + + p_info = input_InfoCategory( p_input, "General" ); + input_AddInfo( p_info, "playlist item", p_input->psz_source ); + vlc_object_attach( p_input, p_parent ); + + /* Create thread and wait for its readiness. */ + if( vlc_thread_create( p_input, "input", RunThread, + VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) ) { - do - { - msleep( THREAD_SLEEP ); - } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR) - && (i_status != THREAD_FATAL) ); - if( i_status != THREAD_READY ) - { - return( NULL ); - } + msg_Err( p_input, "cannot create input thread" ); + free( p_input ); + return NULL; } - return( p_input ); + + return p_input; } /***************************************************************************** - * input_DestroyThread: mark an input thread as zombie + * input_StopThread: mark an input thread as zombie ***************************************************************************** * This function should not return until the thread is effectively cancelled. *****************************************************************************/ -void input_DestroyThread( input_thread_t *p_input, int *pi_status ) +void input_StopThread( input_thread_t *p_input ) { - int i_status; /* thread status */ - - /* Set status */ - p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status; - *p_input->pi_status = THREAD_DESTROY; - + /* Make the thread exit from a possible vlc_cond_wait() */ + vlc_mutex_lock( &p_input->stream.stream_lock ); /* Request thread destruction */ p_input->b_die = 1; - /* Make the thread exit of an eventual vlc_cond_wait() */ - vlc_mutex_lock( &p_input->stream.stream_lock ); vlc_cond_signal( &p_input->stream.stream_wait ); vlc_mutex_unlock( &p_input->stream.stream_lock ); +} - /* If status is NULL, wait until thread has been destroyed */ - if( pi_status == NULL ) - { - do - { - msleep( THREAD_SLEEP ); - } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) - && (i_status != THREAD_FATAL) ); - } +/***************************************************************************** + * input_DestroyThread: mark an input thread as zombie + ***************************************************************************** + * This function should not return until the thread is effectively cancelled. + *****************************************************************************/ +void input_DestroyThread( input_thread_t *p_input ) +{ + /* Join the thread */ + vlc_thread_join( p_input ); + + /* Destroy Mutex locks */ + vlc_mutex_destroy( &p_input->stream.control.control_lock ); + vlc_cond_destroy( &p_input->stream.stream_wait ); + vlc_mutex_destroy( &p_input->stream.stream_lock ); } /***************************************************************************** @@ -229,55 +202,76 @@ void input_DestroyThread( input_thread_t *p_input, int *pi_status ) ***************************************************************************** * Thread in charge of processing the network packets and demultiplexing. *****************************************************************************/ -static void RunThread( input_thread_t *p_input ) +static int RunThread( input_thread_t *p_input ) { - int i_error, i; - data_packet_t ** pp_packets; + /* Signal right now, otherwise we'll get stuck in a peek */ + vlc_thread_ready( p_input ); if( InitThread( p_input ) ) { /* If we failed, wait before we are killed, and exit */ - *p_input->pi_status = THREAD_ERROR; p_input->b_error = 1; ErrorThread( p_input ); - DestroyThread( p_input ); - return; + p_input->b_dead = 1; + return 0; } - /* initialization is completed */ + /* initialization is complete */ vlc_mutex_lock( &p_input->stream.stream_lock ); p_input->stream.b_changed = 1; vlc_mutex_unlock( &p_input->stream.stream_lock ); - pp_packets = (data_packet_t **) malloc( p_input->i_read_once * - sizeof( data_packet_t * ) ); - if( pp_packets == NULL ) - { - intf_ErrMsg( "input error: out of memory" ); - free( pp_packets ); - p_input->b_error = 1; - } - while( !p_input->b_die && !p_input->b_error && !p_input->b_eof ) { + int i, i_count; + p_input->c_loops++; vlc_mutex_lock( &p_input->stream.stream_lock ); + if( p_input->stream.p_new_program ) + { + if( p_input->pf_set_program != NULL ) + { + + /* Reinitialize buffer manager. */ + input_AccessReinit( p_input ); + + p_input->pf_set_program( p_input, + p_input->stream.p_new_program ); + + /* Escape all decoders for the stream discontinuity they + * will encounter. */ + input_EscapeDiscontinuity( p_input ); + + for( i = 0; i < p_input->stream.i_pgrm_number; i++ ) + { + pgrm_descriptor_t * p_pgrm + = p_input->stream.pp_programs[i]; + + /* Reinitialize synchro. */ + p_pgrm->i_synchro_state = SYNCHRO_REINIT; + } + } + p_input->stream.p_new_program = NULL; + } + if( p_input->stream.p_new_area ) { if( p_input->stream.b_seekable && p_input->pf_set_area != NULL ) { + input_AccessReinit( p_input ); p_input->pf_set_area( p_input, p_input->stream.p_new_area ); + /* Escape all decoders for the stream discontinuity they + * will encounter. */ + input_EscapeDiscontinuity( p_input ); + for( i = 0; i < p_input->stream.i_pgrm_number; i++ ) { pgrm_descriptor_t * p_pgrm = p_input->stream.pp_programs[i]; - /* Escape all decoders for the stream discontinuity they - * will encounter. */ - input_EscapeDiscontinuity( p_input, p_pgrm ); /* Reinitialize synchro. */ p_pgrm->i_synchro_state = SYNCHRO_REINIT; @@ -288,18 +282,27 @@ static void RunThread( input_thread_t *p_input ) if( p_input->stream.p_selected_area->i_seek != NO_SEEK ) { - if( p_input->stream.b_seekable && p_input->pf_seek != NULL ) + if( p_input->stream.b_seekable + && p_input->pf_seek != NULL ) { - p_input->pf_seek( p_input, - p_input->stream.p_selected_area->i_seek ); + off_t i_new_pos; + + /* Reinitialize buffer manager. */ + input_AccessReinit( p_input ); + + i_new_pos = p_input->stream.p_selected_area->i_seek; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + p_input->pf_seek( p_input, i_new_pos ); + vlc_mutex_lock( &p_input->stream.stream_lock ); + + /* Escape all decoders for the stream discontinuity they + * will encounter. */ + input_EscapeDiscontinuity( p_input ); for( i = 0; i < p_input->stream.i_pgrm_number; i++ ) { pgrm_descriptor_t * p_pgrm = p_input->stream.pp_programs[i]; - /* Escape all decoders for the stream discontinuity they - * will encounter. */ - input_EscapeDiscontinuity( p_input, p_pgrm ); /* Reinitialize synchro. */ p_pgrm->i_synchro_state = SYNCHRO_REINIT; @@ -336,33 +339,22 @@ static void RunThread( input_thread_t *p_input ) vlc_mutex_unlock( &p_input->stream.stream_lock ); - i_error = p_input->pf_read( p_input, pp_packets ); + /* Read and demultiplex some data. */ + i_count = p_input->pf_demux( p_input ); - /* Demultiplex read packets. */ - for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ ) + if( i_count == 0 && p_input->stream.b_seekable ) { - p_input->stream.c_packets_read++; - p_input->pf_demux( p_input, pp_packets[i] ); + /* End of file - we do not set b_die because only the + * playlist is allowed to do so. */ + msg_Info( p_input, "EOF reached" ); + p_input->b_eof = 1; } - - if( i_error ) + else if( i_count < 0 ) { - if( i_error == 1 ) - { - /* End of file - we do not set b_die because only the - * interface is allowed to do so. */ - intf_WarnMsg( 3, "input: EOF reached" ); - p_input->b_eof = 1; - } - else - { - p_input->b_error = 1; - } + p_input->b_error = 1; } } - free( pp_packets ); - if( p_input->b_error || p_input->b_eof ) { ErrorThread( p_input ); @@ -370,9 +362,7 @@ static void RunThread( input_thread_t *p_input ) EndThread( p_input ); - DestroyThread( p_input ); - - intf_DbgMsg("input: Thread end"); + return 0; } /***************************************************************************** @@ -380,902 +370,210 @@ static void RunThread( input_thread_t *p_input ) *****************************************************************************/ static int InitThread( input_thread_t * p_input ) { + /* Parse source string. Syntax : [[][/]:][] */ + char * psz_parser = p_input->psz_source; - /* Initialize statistics */ - p_input->c_loops = 0; - p_input->stream.c_packets_read = 0; - p_input->stream.c_packets_trashed = 0; - p_input->p_stream = NULL; - - /* Set locks. */ - vlc_mutex_init( &p_input->stream.stream_lock ); - vlc_cond_init( &p_input->stream.stream_wait ); - vlc_mutex_init( &p_input->stream.control.control_lock ); - - /* Find appropriate module. */ - p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT, - (probedata_t *)p_input ); - - if( p_input->p_input_module == NULL ) + /* Skip the plug-in names */ + while( *psz_parser && *psz_parser != ':' ) { - intf_ErrMsg( "input error: no suitable input module for `%s'", - p_input->p_source ); - return( -1 ); + psz_parser++; } - -#define f p_input->p_input_module->p_functions->input.functions.input - p_input->pf_init = f.pf_init; - p_input->pf_end = f.pf_end; - p_input->pf_init_bit_stream= f.pf_init_bit_stream; - p_input->pf_read = f.pf_read; - p_input->pf_set_area = f.pf_set_area; - p_input->pf_demux = f.pf_demux; - p_input->pf_new_packet = f.pf_new_packet; - p_input->pf_new_pes = f.pf_new_pes; - p_input->pf_delete_packet = f.pf_delete_packet; - p_input->pf_delete_pes = f.pf_delete_pes; - p_input->pf_rewind = f.pf_rewind; - p_input->pf_seek = f.pf_seek; - -#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) - /* FIXME : this is waaaay too kludgy */ - if( ( strlen( p_input->p_source ) >= 10 - && !strncasecmp( p_input->p_source, "udpstream:", 10 ) ) - || ( strlen( p_input->p_source ) >= 4 - && !strncasecmp( p_input->p_source, "udp:", 4 ) ) ) +#if defined( WIN32 ) || defined( UNDER_CE ) + if( psz_parser - p_input->psz_source == 1 ) { - /* Network stream */ - NetworkOpen( p_input ); - p_input->stream.i_method = INPUT_METHOD_NETWORK; + msg_Warn( p_input, "drive letter %c: found in source string", + p_input->psz_source[0] ) ; + psz_parser = ""; } - else if( ( strlen( p_input->p_source ) > 5 ) - && !strncasecmp( p_input->p_source, "http:", 5 ) ) - { - /* HTTP stream */ - HTTPOpen( p_input ); - p_input->stream.i_method = INPUT_METHOD_NETWORK; - } - else #endif - if( ( ( strlen( p_input->p_source ) > 4 ) - && !strncasecmp( p_input->p_source, "dvd:", 4 ) ) - || TestMethod( INPUT_METHOD_VAR, "dvd" ) ) - { - /* DVD - this is THE kludge */ - f.pf_open( p_input ); - p_input->stream.i_method = INPUT_METHOD_DVD; - } - else if( ( ( strlen( p_input->p_source ) > 8 ) - && !strncasecmp( p_input->p_source, "dvdread:", 8 ) ) - || TestMethod( INPUT_METHOD_VAR, "dvdread" ) ) - { - /* DVDRead - this is THE kludge */ - f.pf_open( p_input ); - p_input->stream.i_method = INPUT_METHOD_DVD; - } - else if( ( strlen( p_input->p_source ) > 4 ) - && !strncasecmp( p_input->p_source, "vlc:", 4 ) ) - { - /* Dummy input - very kludgy */ - f.pf_open( p_input ); - } - else if( ( strlen( p_input->p_source ) == 1 ) - && *p_input->p_source == '-' ) - { - /* Stdin */ - StdOpen( p_input ); - } - else - { - /* File input */ - FileOpen( p_input ); - p_input->stream.i_method = INPUT_METHOD_FILE; - } -#undef f - if( p_input->b_error ) + if( !*psz_parser ) { - /* We barfed -- exit nicely */ - module_Unneed( p_input->p_input_module ); - return( -1 ); - } - - p_input->pf_init( p_input ); - - if( p_input->b_error ) - { - /* We barfed -- exit nicely */ - CloseThread( p_input ); - module_Unneed( p_input->p_input_module ); - return( -1 ); - } - - *p_input->pi_status = THREAD_READY; - - return( 0 ); -} - -/***************************************************************************** - * ErrorThread: RunThread() error loop - ***************************************************************************** - * This function is called when an error occured during thread main's loop. - *****************************************************************************/ -static void ErrorThread( input_thread_t *p_input ) -{ - while( !p_input->b_die ) - { - /* Sleep a while */ - msleep( INPUT_IDLE_SLEEP ); - } -} - -/***************************************************************************** - * EndThread: end the input thread - *****************************************************************************/ -static void EndThread( input_thread_t * p_input ) -{ - int * pi_status; /* thread status */ - - /* Store status */ - pi_status = p_input->pi_status; - *pi_status = THREAD_END; - - if( p_main->b_stats ) - { -#ifdef HAVE_SYS_TIMES_H - /* Display statistics */ - struct tms cpu_usage; - times( &cpu_usage ); - - intf_StatMsg( "input stats: %d loops consuming user: %d, system: %d", - p_input->c_loops, - cpu_usage.tms_utime, cpu_usage.tms_stime ); -#else - intf_StatMsg( "input stats: %d loops", p_input->c_loops ); -#endif - - input_DumpStream( p_input ); - } - - /* Free all ES and destroy all decoder threads */ - input_EndStream( p_input ); - - /* Free demultiplexer's data */ - p_input->pf_end( p_input ); - - /* Close the input method */ - CloseThread( p_input ); - - /* Release modules */ - module_Unneed( p_input->p_input_module ); -} - -/***************************************************************************** - * CloseThread: close the target - *****************************************************************************/ -static void CloseThread( input_thread_t * p_input ) -{ -#define f p_input->p_input_module->p_functions->input.functions.input - -#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) - /* Close stream */ - if( ( strlen( p_input->p_source ) > 10 - && !strncasecmp( p_input->p_source, "udpstream:", 10 ) ) - || ( strlen( p_input->p_source ) > 4 - && !strncasecmp( p_input->p_source, "udp:", 4 ) ) ) - { - NetworkClose( p_input ); - } - else if( ( strlen( p_input->p_source ) > 5 ) - && !strncasecmp( p_input->p_source, "http:", 5 ) ) - { - NetworkClose( p_input ); - } - else -#endif - if( ( ( strlen( p_input->p_source ) > 4 ) - && !strncasecmp( p_input->p_source, "dvd:", 4 ) ) - || TestMethod( INPUT_METHOD_VAR, "dvd" ) ) - { - f.pf_close( p_input ); - } - else if( ( strlen( p_input->p_source ) > 4 ) - && !strncasecmp( p_input->p_source, "vlc:", 4 ) ) - { - f.pf_close( p_input ); + p_input->psz_access = p_input->psz_demux = ""; + p_input->psz_name = p_input->psz_source; } else { - FileClose( p_input ); - } -#undef f -} - -/***************************************************************************** - * DestroyThread: destroy the input thread - *****************************************************************************/ -static void DestroyThread( input_thread_t * p_input ) -{ - int * pi_status; /* thread status */ - - /* Store status */ - pi_status = p_input->pi_status; - - /* Destroy Mutex locks */ - vlc_mutex_destroy( &p_input->stream.control.control_lock ); - vlc_mutex_destroy( &p_input->stream.stream_lock ); - - /* Free input structure */ - free( p_input ); - - /* Update status */ - *pi_status = THREAD_OVER; -} - -/***************************************************************************** - * StdOpen : open standard input - *****************************************************************************/ -static void StdOpen( input_thread_t * p_input ) -{ - vlc_mutex_lock( &p_input->stream.stream_lock ); - - /* Suppose we can control the pace - this won't work in some cases ! */ - p_input->stream.b_pace_control = 1; - - p_input->stream.b_seekable = 0; - p_input->stream.p_selected_area->i_size = 0; - p_input->stream.p_selected_area->i_tell = 0; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - intf_WarnMsg( 2, "input: opening stdin" ); - p_input->i_handle = 0; -} + *psz_parser++ = '\0'; -/***************************************************************************** - * FileOpen : open a file descriptor - *****************************************************************************/ -static void FileOpen( input_thread_t * p_input ) -{ - struct stat stat_info; - int i_stat; - - char *psz_name = p_input->p_source; - - if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) ) - { - int i_size = strlen( psz_name ); - - if( ( i_size > 8 ) - && !strncasecmp( psz_name, "dvdread:", 8 ) ) - { - /* get rid of the 'dvdread:' stuff and try again */ - psz_name += 8; - i_stat = stat( psz_name, &stat_info ); - } - else if( ( i_size > 4 ) - && !strncasecmp( psz_name, "dvd:", 4 ) ) - { - /* get rid of the 'dvd:' stuff and try again */ - psz_name += 4; - i_stat = stat( psz_name, &stat_info ); - } - else if( ( i_size > 4 ) - && !strncasecmp( psz_name, "vcd:", 4 ) ) - { - /* get rid of the 'vcd:' stuff and try again */ - psz_name += 4; - i_stat = stat( psz_name, &stat_info ); - } - else if( ( i_size > 5 ) - && !strncasecmp( psz_name, "file:", 5 ) ) + /* let's skip '//' */ + if( psz_parser[0] == '/' && psz_parser[1] == '/' ) { - /* get rid of the 'file:' stuff and try again */ - psz_name += 5; - i_stat = stat( psz_name, &stat_info ); - } - - if( i_stat == (-1) ) - { - intf_ErrMsg( "input error: cannot stat() file `%s' (%s)", - psz_name, strerror(errno)); - p_input->b_error = 1; - return; - } - } - - vlc_mutex_lock( &p_input->stream.stream_lock ); - - /* If we are here we can control the pace... */ - p_input->stream.b_pace_control = 1; - - if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode) - || S_ISBLK(stat_info.st_mode) ) - { - p_input->stream.b_seekable = 1; - p_input->stream.p_selected_area->i_size = stat_info.st_size; - } - else if( S_ISFIFO(stat_info.st_mode) -#if !defined( SYS_BEOS ) && !defined( WIN32 ) - || S_ISSOCK(stat_info.st_mode) -#endif - ) - { - p_input->stream.b_seekable = 0; - p_input->stream.p_selected_area->i_size = 0; - } - else - { - vlc_mutex_unlock( &p_input->stream.stream_lock ); - intf_ErrMsg( "input error: unknown file type for `%s'", - psz_name ); - p_input->b_error = 1; - return; - } + psz_parser += 2 ; + } - p_input->stream.p_selected_area->i_tell = 0; - vlc_mutex_unlock( &p_input->stream.stream_lock ); + p_input->psz_name = psz_parser ; - intf_WarnMsg( 2, "input: opening file `%s'", p_input->p_source ); - if( (p_input->i_handle = open( psz_name, - /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) ) - { - intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) ); - p_input->b_error = 1; - return; - } + /* Come back to parse the access and demux plug-ins */ + psz_parser = p_input->psz_source; -} - -/***************************************************************************** - * FileClose : close a file descriptor - *****************************************************************************/ -static void FileClose( input_thread_t * p_input ) -{ - intf_WarnMsg( 2, "input: closing file `%s'", p_input->p_source ); - - close( p_input->i_handle ); - - return; -} - -#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) -/***************************************************************************** - * NetworkOpen : open a network socket - *****************************************************************************/ -static void NetworkOpen( input_thread_t * p_input ) -{ - char *psz_server = NULL; - char *psz_bind = NULL; - int i_server_port = 0; - int i_bind_port = 0; - int i_opt; - int i_opt_size; - struct sockaddr_in sock; - - /* Get the remote server. Syntax is : - * udp[stream]:[/][/][serveraddr[:serverport]][@[bindaddr]:[bindport]] */ - if( p_input->p_source != NULL ) - { - char * psz_parser = p_input->p_source; - char * psz_server_port = NULL; - char * psz_bind_port = NULL; - - /* Skip the protocol name */ - while( *psz_parser && *psz_parser != ':' ) + if( !*psz_parser ) { - psz_parser++; + /* No access */ + p_input->psz_access = ""; } - - /* Skip the "://" part */ - while( *psz_parser && (*psz_parser == ':' || *psz_parser == '/') ) + else if( *psz_parser == '/' ) { + /* No access */ + p_input->psz_access = ""; psz_parser++; } - - if( *psz_parser && *psz_parser != '@' ) + else { - /* Found server */ - psz_server = psz_parser; + p_input->psz_access = psz_parser; - while( *psz_parser && *psz_parser != ':' && *psz_parser != '@' ) + while( *psz_parser && *psz_parser != '/' ) { psz_parser++; } - if( *psz_parser == ':' ) + if( *psz_parser == '/' ) { - /* Found server port */ - *psz_parser = '\0'; /* Terminate server name */ - psz_parser++; - psz_server_port = psz_parser; - - while( *psz_parser && *psz_parser != '@' ) - { - psz_parser++; - } + *psz_parser++ = '\0'; } } - if( *psz_parser == '@' ) + if( !*psz_parser ) { - /* Found bind address or bind port */ - *psz_parser = '\0'; /* Terminate server port or name if necessary */ - psz_parser++; - - if( *psz_parser && *psz_parser != ':' ) - { - /* Found bind address */ - psz_bind = psz_parser; - - while( *psz_parser && *psz_parser != ':' ) - { - psz_parser++; - } - } - - if( *psz_parser == ':' ) - { - /* Found bind port */ - *psz_parser = '\0'; /* Terminate bind address if necessary */ - psz_parser++; - - psz_bind_port = psz_parser; - } + /* No demux */ + p_input->psz_demux = ""; } - - /* Convert ports format */ - if( psz_server_port != NULL ) - { - i_server_port = strtol( psz_server_port, &psz_parser, 10 ); - if( *psz_parser ) - { - intf_ErrMsg( "input error: cannot parse server port near %s", - psz_parser ); - p_input->b_error = 1; - return; - } - } - - if( psz_bind_port != NULL ) + else { - i_bind_port = strtol( psz_bind_port, &psz_parser, 10 ); - if( *psz_parser ) - { - intf_ErrMsg( "input error: cannot parse bind port near %s", - psz_parser ); - p_input->b_error = 1; - return; - } + p_input->psz_demux = psz_parser; } } - else - { - /* This is required or NetworkClose will never be called */ - p_input->p_source = "ts: network input"; - } - /* Check that we got a valid port */ - if( i_bind_port == 0 ) - { - i_bind_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT ); - } - - intf_WarnMsg( 2, "input: server=%s:%d local=%s:%d", - psz_server, i_server_port, psz_bind, i_bind_port ); + msg_Dbg( p_input, "access `%s', demux `%s', name `%s'", + p_input->psz_access, p_input->psz_demux, p_input->psz_name ); - /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0) - * protocol */ - p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 ); - if( p_input->i_handle == -1 ) + if( input_AccessInit( p_input ) == -1 ) { - intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) ); - p_input->b_error = 1; - return; + return -1; } - /* We may want to reuse an already used socket */ - i_opt = 1; - if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR, - (void *) &i_opt, sizeof( i_opt ) ) == -1 ) - { - intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)", - strerror(errno)); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } + /* Find and open appropriate access module */ + p_input->p_access = module_Need( p_input, "access", + p_input->psz_access ); - /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid - * packet loss caused by scheduling problems */ - i_opt = 0x80000; - if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF, - (void *) &i_opt, sizeof( i_opt ) ) == -1 ) + if( p_input->p_access == NULL ) { - intf_WarnMsg( 1, "input warning: can't configure socket (SO_RCVBUF: %s)", - strerror(errno)); + msg_Err( p_input, "no suitable access module for `%s/%s://%s'", + p_input->psz_access, p_input->psz_demux, p_input->psz_name ); + return -1; } - /* Check if we really got what we have asked for, because Linux, etc. - * will silently limit the max buffer size to net.core.rmem_max which - * is typically only 65535 bytes */ - i_opt = 0; - i_opt_size = sizeof( i_opt ); - if( getsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF, - (void*) &i_opt, &i_opt_size ) == -1 ) + /* Waiting for stream. */ + if( p_input->i_mtu ) { - intf_WarnMsg( 1, "input warning: can't query socket (SO_RCVBUF: %s)", - strerror(errno)); + p_input->i_bufsize = p_input->i_mtu; } - else if( i_opt < 0x80000 ) - { - intf_WarnMsg( 1, "input warning: socket buffer size is 0x%x" - " instead of 0x%x", i_opt, 0x80000 ); - } - - /* Build the local socket */ - if ( network_BuildAddr( &sock, psz_bind, i_bind_port ) == -1 ) - { - intf_ErrMsg( "input error: can't build local address" ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } - - /* Bind it */ - if( bind( p_input->i_handle, (struct sockaddr *)&sock, - sizeof( sock ) ) < 0 ) + else { - intf_ErrMsg( "input error: can't bind socket (%s)", strerror(errno) ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; } - /* Allow broadcast reception if we bound on INADDR_ANY */ - if( psz_bind == NULL ) + if( p_input->p_current_data == NULL && p_input->pf_read != NULL ) { - i_opt = 1; - if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_BROADCAST, - (void*) &i_opt, sizeof( i_opt ) ) == -1 ) + while( !input_FillBuffer( p_input ) ) { - intf_WarnMsg( 1, "input warning: can't configure socket (SO_BROADCAST: %s)", - strerror(errno)); + if( p_input->b_die || p_input->b_error || p_input->b_eof ) + { + module_Unneed( p_input, p_input->p_access ); + return -1; + } } } - /* Join the multicast group if the socket is a multicast address */ -#ifndef IN_MULTICAST -# define IN_MULTICAST(a) IN_CLASSD(a) -#endif + /* Find and open appropriate demux module */ + p_input->p_demux = module_Need( p_input, "demux", + p_input->psz_demux ); - /* TODO : make this compile under Win32 */ - /* Enabled this so that windows people have a serious look at it :)) */ -//#ifndef WIN32 - if( IN_MULTICAST( ntohl(sock.sin_addr.s_addr) ) ) + if( p_input->p_demux== NULL ) { - struct ip_mreq imr; - - imr.imr_interface.s_addr = INADDR_ANY; - imr.imr_multiaddr.s_addr = sock.sin_addr.s_addr; - if( setsockopt( p_input->i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char*)&imr, sizeof(struct ip_mreq) ) == -1 ) - { - intf_ErrMsg( "input error: failed to join IP multicast group (%s)", - strerror(errno) ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } + msg_Err( p_input, "no suitable demux module for `%s/%s://%s'", + p_input->psz_access, p_input->psz_demux, p_input->psz_name ); + module_Unneed( p_input, p_input->p_access ); + return -1; } - - if( psz_server != NULL ) + + /* Initialize optional stream output. */ + psz_parser = config_GetPsz( p_input, "sout" ); + if ( psz_parser != NULL ) { - /* Build socket for remote connection */ - if ( network_BuildAddr( &sock, psz_server, i_server_port ) == -1 ) + if ( *psz_parser && + (p_input->stream.p_sout = sout_NewInstance( p_input, psz_parser )) + == NULL ) { - intf_ErrMsg( "input error: can't build remote address" ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; + msg_Err( p_input, "cannot start stream output instance, aborting" ); + free( psz_parser ); + module_Unneed( p_input, p_input->p_access ); + module_Unneed( p_input, p_input->p_demux ); + return -1; } - /* Connect the socket */ - if( connect( p_input->i_handle, (struct sockaddr *) &sock, - sizeof( sock ) ) == (-1) ) - { - intf_ErrMsg( "input error: can't connect socket (%s)", - strerror(errno) ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } + free( psz_parser ); } -//#endif - - p_input->stream.b_pace_control = 0; - p_input->stream.b_seekable = 0; - intf_WarnMsg( 3, "input: successfully opened network mode" ); - - return; + return 0; } /***************************************************************************** - * NetworkClose : close a network socket + * ErrorThread: RunThread() error loop + ***************************************************************************** + * This function is called when an error occured during thread main's loop. *****************************************************************************/ -static void NetworkClose( input_thread_t * p_input ) +static void ErrorThread( input_thread_t *p_input ) { - intf_WarnMsg( 2, "input: closing network target `%s'", p_input->p_source ); - - close( p_input->i_handle ); + while( !p_input->b_die ) + { + /* Sleep a while */ + msleep( INPUT_IDLE_SLEEP ); + } } /***************************************************************************** - * HTTPOpen : make an HTTP request + * EndThread: end the input thread *****************************************************************************/ -static void HTTPOpen( input_thread_t * p_input ) +static void EndThread( input_thread_t * p_input ) { - char *psz_server = NULL; - char *psz_path = NULL; - char *psz_proxy; - int i_port = 0; - int i_opt; - struct sockaddr_in sock; - char psz_buffer[256]; - - /* Get the remote server */ - if( p_input->p_source != NULL ) - { - psz_server = p_input->p_source; - - /* Skip the protocol name */ - while( *psz_server && *psz_server != ':' ) - { - psz_server++; - } - - /* Skip the "://" part */ - while( *psz_server && (*psz_server == ':' || *psz_server == '/') ) - { - psz_server++; - } - - /* Found a server name */ - if( *psz_server ) - { - char *psz_port = psz_server; - - /* Skip the hostname part */ - while( *psz_port && *psz_port != ':' && *psz_port != '/' ) - { - psz_port++; - } - - /* Found a port name */ - if( *psz_port ) - { - if( *psz_port == ':' ) - { - /* Replace ':' with '\0' */ - *psz_port = '\0'; - psz_port++; - } - - psz_path = psz_port; - while( *psz_path && *psz_path != '/' ) - { - psz_path++; - } - - if( *psz_path ) - { - *psz_path = '\0'; - psz_path++; - } - else - { - psz_path = NULL; - } - - if( *psz_port != '\0' ) - { - i_port = atoi( psz_port ); - } - } - } - else - { - psz_server = NULL; - } - } - - /* Check that we got a valid server */ - if( psz_server == NULL ) - { - intf_ErrMsg( "input error: No server given" ); - p_input->b_error = 1; - return; - } - - /* Check that we got a valid port */ - if( i_port == 0 ) - { - i_port = 80; /* FIXME */ - } - - intf_WarnMsg( 2, "input: server=%s port=%d path=%s", psz_server, - i_port, psz_path ); - - /* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0) - * * protocol */ - p_input->i_handle = socket( AF_INET, SOCK_STREAM, 0 ); - if( p_input->i_handle == -1 ) - { - intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) ); p_input->b_error = 1; - return; - } - - /* We may want to reuse an already used socket */ - i_opt = 1; - if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR, - (void *) &i_opt, sizeof( i_opt ) ) == -1 ) - { - intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)", - strerror(errno)); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } - - /* Check proxy */ - if( (psz_proxy = main_GetPszVariable( "http_proxy", NULL )) != NULL ) - { - /* http://myproxy.mydomain:myport/ */ - int i_proxy_port = 0; - - /* Skip the protocol name */ - while( *psz_proxy && *psz_proxy != ':' ) - { - psz_proxy++; - } - - /* Skip the "://" part */ - while( *psz_proxy && (*psz_proxy == ':' || *psz_proxy == '/') ) - { - psz_proxy++; - } - - /* Found a proxy name */ - if( *psz_proxy ) - { - char *psz_port = psz_proxy; - - /* Skip the hostname part */ - while( *psz_port && *psz_port != ':' && *psz_port != '/' ) - { - psz_port++; - } - - /* Found a port name */ - if( *psz_port ) - { - char * psz_junk; - - /* Replace ':' with '\0' */ - *psz_port = '\0'; - psz_port++; - - psz_junk = psz_port; - while( *psz_junk && *psz_junk != '/' ) - { - psz_junk++; - } +#ifdef HAVE_SYS_TIMES_H + /* Display statistics */ + struct tms cpu_usage; + times( &cpu_usage ); - if( *psz_junk ) - { - *psz_junk = '\0'; - } + msg_Dbg( p_input, "%d loops consuming user: %d, system: %d", + p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime ); +#else + msg_Dbg( p_input, "%d loops", p_input->c_loops ); +#endif - if( *psz_port != '\0' ) - { - i_proxy_port = atoi( psz_port ); - } - } - } - else - { - intf_ErrMsg( "input error: http_proxy environment variable is invalid !" ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } + /* Free info structures */ + msg_Dbg( p_input, "freeing info structures..."); + input_DelInfo( p_input ); + + input_DumpStream( p_input ); - /* Build socket for proxy connection */ - if ( network_BuildAddr( &sock, psz_proxy, i_proxy_port ) == -1 ) - { - intf_ErrMsg( "input error: can't build remote address" ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } - } - else - { - /* No proxy, direct connection */ - if ( network_BuildAddr( &sock, psz_server, i_port ) == -1 ) - { - intf_ErrMsg( "input error: can't build remote address" ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } - } + /* Free all ES and destroy all decoder threads */ + input_EndStream( p_input ); - /* Connect the socket */ - if( connect( p_input->i_handle, (struct sockaddr *) &sock, - sizeof( sock ) ) == (-1) ) + /* Close optional stream output instance */ + if ( p_input->stream.p_sout != NULL ) { - intf_ErrMsg( "input error: can't connect socket (%s)", - strerror(errno) ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; + sout_DeleteInstance( p_input->stream.p_sout ); } - p_input->stream.b_seekable = 0; - p_input->stream.b_pace_control = 1; /* TCP/IP... */ - -# define HTTP_USERAGENT "User-Agent: " COPYRIGHT_MESSAGE "\r\n" -# define HTTP_END "\r\n" - - /* Prepare GET ... */ - if( psz_proxy != NULL ) - { - snprintf( psz_buffer, sizeof(psz_buffer), - "GET http://%s:%d/%s HTTP/1.0\r\n" - HTTP_USERAGENT HTTP_END, - psz_server, i_port, psz_path ); - } - else - { - snprintf( psz_buffer, sizeof(psz_buffer), - "GET /%s HTTP/1.0\r\nHost: %s\r\n" - HTTP_USERAGENT HTTP_END, - psz_path, psz_server ); - } - psz_buffer[sizeof(psz_buffer) - 1] = '\0'; + /* Free demultiplexer's data */ + module_Unneed( p_input, p_input->p_demux ); - /* Send GET ... */ - if( write( p_input->i_handle, psz_buffer, strlen( psz_buffer ) ) == (-1) ) - { - intf_ErrMsg( "input error: can't send request (%s)", strerror(errno) ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } + /* Close the access plug-in */ + module_Unneed( p_input, p_input->p_access ); - /* Read HTTP header - this is gonna be fun with plug-ins which do not - * use p_input->p_stream :-( */ - if( (p_input->p_stream = fdopen( p_input->i_handle, "r+" )) == NULL ) - { - intf_ErrMsg( "input error: can't reopen socket (%s)", strerror(errno) ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } + input_AccessEnd( p_input ); - while( !feof( p_input->p_stream ) && !ferror( p_input->p_stream ) ) - { - if( fgets( psz_buffer, sizeof(psz_buffer), p_input->p_stream ) == NULL - || *psz_buffer == '\r' || *psz_buffer == '\0' ) - { - break; - } - /* FIXME : check Content-Type one day */ - } + free( p_input->psz_source ); - intf_WarnMsg( 3, "input: successfully opened HTTP mode" ); + /* Tell we're dead */ + p_input->b_dead = 1; } -#endif /* !defined( SYS_BEOS ) && !defined( SYS_NTO ) */ -