X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=09d4346c13d728912596f5049fe1b39d5a7a37f2;hb=ecbcf0b3126804a20cfc0d22f4a994cfc6cc6374;hp=1b225dd9d835a3bb852bd9e393fad99200262ef0;hpb=94d3d4d8be146d5a7ca5e77eb025820d26b9396d;p=vlc diff --git a/src/input/input.c b/src/input/input.c index 1b225dd9d8..09d4346c13 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -3,10 +3,11 @@ * Read an MPEG2 stream, demultiplex and parse it before sending it to * decoders. ***************************************************************************** - * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: input.c,v 1.115 2001/05/31 01:37:08 sam Exp $ + * Copyright (C) 1998-2001 VideoLAN + * $Id: input.c,v 1.191 2002/03/18 21:04:01 xav Exp $ * * Authors: Christophe Massiot + * Alexis Guillard * * 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 @@ -26,80 +27,75 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include "defs.h" - #include #include #include #include -#ifdef HAVE_UNISTD_H -#include -#elif defined( _MSC_VER ) && defined( _WIN32 ) -#include -#endif +#include #include -#ifdef STRNCASECMP_IN_STRINGS_H -# include -#endif #include -/* WinSock Includes */ - -#ifdef WIN32 -#include -#endif - - -/* Network functions */ - -#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 ) -#include /* hostent ... */ -#include -#include -#include -#include -#include -#endif - -#ifdef STATS +#ifdef HAVE_SYS_TIMES_H # include #endif -#include "config.h" -#include "common.h" -#include "threads.h" -#include "mtime.h" #include "netutils.h" -#include "modules.h" -#include "intf_msg.h" #include "intf_playlist.h" #include "stream_control.h" #include "input_ext-intf.h" #include "input_ext-dec.h" +#include "input_ext-plugins.h" -#include "input.h" #include "interface.h" -#include "main.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 FileClose ( input_thread_t *p_input ); -static void NetworkOpen ( input_thread_t *p_input ); -static void NetworkClose ( input_thread_t *p_input ); +/***************************************************************************** + * input_InitBank: initialize the input bank. + *****************************************************************************/ +void input_InitBank ( void ) +{ + p_input_bank->i_count = 0; + + /* XXX: Workaround for old interface modules */ + p_input_bank->pp_input[0] = NULL; + + vlc_mutex_init( &p_input_bank->lock ); +} + +/***************************************************************************** + * input_EndBank: empty the input bank. + ***************************************************************************** + * This function ends all unused inputs and empties the bank in + * case of success. + *****************************************************************************/ +void input_EndBank ( void ) +{ + int i_input; + + /* Ask all remaining video outputs to die */ + for( i_input = 0; i_input < p_input_bank->i_count; i_input++ ) + { + input_StopThread( + p_input_bank->pp_input[ i_input ], NULL ); + input_DestroyThread( + p_input_bank->pp_input[ i_input ] ); + } + + vlc_mutex_destroy( &p_input_bank->lock ); +} /***************************************************************************** * input_CreateThread: creates a new input thread @@ -112,7 +108,6 @@ static void NetworkClose ( input_thread_t *p_input ); input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) { input_thread_t * p_input; /* thread descriptor */ - int i_status; /* thread status */ /* Allocate descriptor */ p_input = (input_thread_t *)malloc( sizeof(input_thread_t) ); @@ -123,34 +118,68 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) 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_die = 0; + p_input->b_error = 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 ); + + /* Set status */ + p_input->i_status = THREAD_CREATE; + + /* Demux */ + p_input->p_demux_module = NULL; + p_input->pf_init = NULL; + p_input->pf_end = NULL; + p_input->pf_demux = NULL; + p_input->pf_rewind = NULL; + + /* Access */ + p_input->p_access_module = NULL; + p_input->pf_open = NULL; + p_input->pf_close = NULL; + p_input->pf_read = NULL; + p_input->pf_seek = NULL; + p_input->pf_set_area = NULL; + p_input->pf_set_program = NULL; + + p_input->i_bufsize = 0; + p_input->i_mtu = 0; - /* I have never understood that stuff --Meuuh */ - p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status; - *p_input->pi_status = THREAD_CREATE; + /* 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->stream.stream_lock ); + vlc_cond_init( &p_input->stream.stream_wait ); + vlc_mutex_init( &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; - /* no stream, no area */ + /* no stream, no program, no area, no es */ + p_input->stream.p_new_program = NULL; + 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; - /* By default there is one areas in a stream */ + + 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]; @@ -158,22 +187,14 @@ 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_bw = 0; - - /* Setup callbacks */ - p_input->pf_file_open = FileOpen; - p_input->pf_file_close = FileClose; -#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) - p_input->pf_network_open = NetworkOpen; - p_input->pf_network_close = NetworkClose; -#endif + p_input->stream.control.b_grayscale = config_GetIntVariable( "grayscale" ); + p_input->stream.control.i_smp = config_GetIntVariable( "vdec_smp" ); - /* Create thread and 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 ); - if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread, - (void *) p_input ) ) + intf_WarnMsg( 1, "input: playlist item `%s'", p_input->psz_source ); + + /* Create thread. */ + if( vlc_thread_create( &p_input->thread_id, "input", + (vlc_thread_func_t)RunThread, (void *) p_input ) ) { intf_ErrMsg( "input error: can't create input thread (%s)", strerror(errno) ); @@ -181,6 +202,7 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) return( NULL ); } +#if 0 /* If status is NULL, wait until the thread is created */ if( pi_status == NULL ) { @@ -189,36 +211,30 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) msleep( THREAD_SLEEP ); } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR) && (i_status != THREAD_FATAL) ); - if( i_status != THREAD_READY ) - { - return( NULL ); - } } +#endif + 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 *pi_status ) { - 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 0 if( pi_status == NULL ) { do @@ -227,6 +243,26 @@ void input_DestroyThread( input_thread_t *p_input, int *pi_status ) } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) && (i_status != THREAD_FATAL) ); } +#endif +} + +/***************************************************************************** + * 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->thread_id ); + + /* 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 ); + + /* Free input structure */ + free( p_input ); } /***************************************************************************** @@ -234,46 +270,77 @@ 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; - if( InitThread( p_input ) ) { - /* If we failed, wait before we are killed, and exit */ - *p_input->pi_status = THREAD_ERROR; + p_input->i_status = THREAD_ERROR; p_input->b_error = 1; ErrorThread( p_input ); DestroyThread( p_input ); - return; + return 0; } - /* initialization is completed */ + p_input->i_status = THREAD_READY; + + /* 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" ); - p_input->b_error = 1; - } - while( !p_input->b_die && !p_input->b_error && !p_input->b_eof ) { -#ifdef STATS + int i, i_count; + p_input->c_loops++; -#endif vlc_mutex_lock( &p_input->stream.stream_lock ); + if( p_input->stream.p_new_program ) + { + if( p_input->pf_set_program != NULL ) + { + + p_input->pf_set_program( p_input, + p_input->stream.p_new_program ); + + 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; + } + } + p_input->stream.p_new_program = NULL; + } + if( p_input->stream.p_new_area ) { - p_input->pf_set_area( p_input, p_input->stream.p_new_area ); + if( p_input->stream.b_seekable && p_input->pf_set_area != NULL ) + { + + p_input->pf_set_area( p_input, p_input->stream.p_new_area ); + + 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; + } + + input_AccessReinit( p_input ); + } p_input->stream.p_new_area = NULL; } @@ -281,8 +348,10 @@ static void RunThread( input_thread_t *p_input ) { 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 = 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 ); for( i = 0; i < p_input->stream.i_pgrm_number; i++ ) { @@ -295,6 +364,9 @@ static void RunThread( input_thread_t *p_input ) /* Reinitialize synchro. */ p_pgrm->i_synchro_state = SYNCHRO_REINIT; } + + /* Reinitialize buffer manager. */ + input_AccessReinit( p_input ); } p_input->stream.p_selected_area->i_seek = NO_SEEK; } @@ -311,34 +383,38 @@ static void RunThread( input_thread_t *p_input ) p_input->stream.p_newly_selected_es = NULL; } + if( p_input->stream.b_new_mute != MUTE_NO_CHANGE ) + { + if( p_input->stream.b_new_mute ) + { + input_EscapeAudioDiscontinuity( p_input ); + } + + vlc_mutex_lock( &p_input->stream.control.control_lock ); + p_input->stream.control.b_mute = p_input->stream.b_new_mute; + vlc_mutex_unlock( &p_input->stream.control.control_lock ); + + p_input->stream.b_new_mute = MUTE_NO_CHANGE; + } + 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->pf_demux( p_input, pp_packets[i] ); + /* 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; } - - 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 ); @@ -348,7 +424,7 @@ static void RunThread( input_thread_t *p_input ) DestroyThread( p_input ); - intf_DbgMsg("input: Thread end"); + return 0; } /***************************************************************************** @@ -356,72 +432,153 @@ 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; -#ifdef STATS - /* Initialize statistics */ - p_input->c_loops = 0; - p_input->c_bytes = 0; - p_input->c_payload_bytes = 0; - p_input->c_packets_read = 0; - p_input->c_packets_trashed = 0; + /* Skip the plug-in names */ + while( *psz_parser && *psz_parser != ':' ) + { + psz_parser++; + } +#ifdef WIN32 + if( psz_parser - p_input->psz_source == 1 ) + { + intf_WarnMsg( 2, "Drive letter %c: specified in source string", + p_input->psz_source ) ; + psz_parser = ""; + } #endif - /* Default, might get overwritten */ - p_input->pf_open = p_input->pf_file_open; - p_input->pf_close = p_input->pf_file_close; + if( !*psz_parser ) + { + p_input->psz_access = p_input->psz_demux = ""; + p_input->psz_name = p_input->psz_source; + } + else + { + *psz_parser++ = '\0'; - p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT, - (probedata_t *)p_input ); + /* let's skip '//' */ + if( psz_parser[0] == '/' && psz_parser[1] == '/' ) + { + psz_parser += 2 ; + } - if( p_input->p_input_module == NULL ) - { - intf_ErrMsg( "input error: no suitable input module for `%s'", - p_input->p_source ); - return( -1 ); + p_input->psz_name = psz_parser ; + + /* Come back to parse the access and demux plug-ins */ + psz_parser = p_input->psz_source; + + if( !*psz_parser ) + { + /* No access */ + p_input->psz_access = ""; + } + else if( *psz_parser == '/' ) + { + /* No access */ + p_input->psz_access = ""; + psz_parser++; + } + else + { + p_input->psz_access = psz_parser; + + while( *psz_parser && *psz_parser != '/' ) + { + psz_parser++; + } + + if( *psz_parser == '/' ) + { + *psz_parser++ = '\0'; + } + } + + if( !*psz_parser ) + { + /* No demux */ + p_input->psz_demux = ""; + } + else + { + p_input->psz_demux = psz_parser; + } } -#define f p_input->p_input_module->p_functions->input.functions.input - p_input->pf_init = f.pf_init; - if( f.pf_open != NULL ) + intf_WarnMsg( 2, "input: access `%s', demux `%s', name `%s'", + p_input->psz_access, p_input->psz_demux, + p_input->psz_name ); + + if( input_AccessInit( p_input ) == -1 ) { - p_input->pf_open = f.pf_open; + return( -1 ); } - if( f.pf_close != NULL ) + + /* Find and open appropriate access plug-in. */ + p_input->p_access_module = module_Need( MODULE_CAPABILITY_ACCESS, + p_input->psz_access, + (void *)p_input ); + + if( p_input->p_access_module == NULL ) { - p_input->pf_close = f.pf_close; + intf_ErrMsg( "input error: no suitable access plug-in for `%s/%s:%s'", + p_input->psz_access, p_input->psz_demux, + p_input->psz_name ); + return( -1 ); } - p_input->pf_end = f.pf_end; + +#define f p_input->p_access_module->p_functions->access.functions.access + p_input->pf_open = f.pf_open; + p_input->pf_close = f.pf_close; 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_set_program = f.pf_set_program; p_input->pf_seek = f.pf_seek; #undef f - p_input->pf_open( p_input ); - if( p_input->b_error ) + /* Waiting for stream. */ + if( p_input->i_mtu ) { - /* We barfed -- exit nicely */ - p_input->pf_close( p_input ); - module_Unneed( p_input->p_input_module ); - return( -1 ); + p_input->i_bufsize = p_input->i_mtu; + } + else + { + p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; + } + + if( p_input->p_current_data == NULL && p_input->pf_read != NULL ) + { + while( !input_FillBuffer( p_input ) ) + { + if( p_input->b_die || p_input->b_error ) + { + module_Unneed( p_input->p_access_module ); + return( -1 ); + } + } } - p_input->pf_init( p_input ); + /* Find and open appropriate demux plug-in. */ + p_input->p_demux_module = module_Need( MODULE_CAPABILITY_DEMUX, + p_input->psz_demux, + (void *)p_input ); - if( p_input->b_error ) + if( p_input->p_demux_module == NULL ) { - /* We barfed -- exit nicely */ - p_input->pf_close( p_input ); - module_Unneed( p_input->p_input_module ); + intf_ErrMsg( "input error: no suitable demux plug-in for `%s/%s:%s'", + p_input->psz_access, p_input->psz_demux, + p_input->psz_name ); + module_Unneed( p_input->p_access_module ); return( -1 ); } - *p_input->pi_status = THREAD_READY; +#define f p_input->p_demux_module->p_functions->demux.functions.demux + p_input->pf_init = f.pf_init; + p_input->pf_end = f.pf_end; + p_input->pf_demux = f.pf_demux; + p_input->pf_rewind = f.pf_rewind; +#undef f return( 0 ); } @@ -445,375 +602,56 @@ static void ErrorThread( input_thread_t *p_input ) *****************************************************************************/ 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; + p_input->i_status = THREAD_END; -#ifdef STATS + if( p_main->b_stats ) { - struct tms cpu_usage; +#ifdef HAVE_SYS_TIMES_H + /* Display statistics */ + struct tms cpu_usage; times( &cpu_usage ); - intf_Msg("input stats: cpu usage (user: %d, system: %d)", - cpu_usage.tms_utime, cpu_usage.tms_stime); - } + 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 ); + module_Unneed( p_input->p_demux_module ); - /* Close stream */ - p_input->pf_close( p_input ); - - /* Release modules */ - module_Unneed( p_input->p_input_module ); - + /* Close the access plug-in */ + CloseThread( p_input ); } /***************************************************************************** - * DestroyThread: destroy the input thread + * CloseThread: close the target *****************************************************************************/ -static void DestroyThread( input_thread_t * p_input ) +static void CloseThread( 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; -} - -/***************************************************************************** - * 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; - - /* FIXME: this code ought to be in the plugin so that code can - * be shared with the *_Probe function */ - if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) ) - { - int i_size = strlen( psz_name ); - - 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 > 5 ) - && !strncasecmp( psz_name, "file:", 5 ) ) - { - /* 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; - } - - p_input->stream.p_selected_area->i_tell = 0; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - intf_WarnMsg( 1, "input: opening file `%s'", p_input->p_source ); -#ifndef WIN32 - if( (p_input->i_handle = open( psz_name, - /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) ) -#else - if( (p_input->i_handle = open( psz_name, O_BINARY - /*O_NONBLOCK | O_LARGEFILE*/ )) == (-1) ) -#endif - { - intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) ); - p_input->b_error = 1; - return; - } - -} - -/***************************************************************************** - * FileClose : close a file descriptor - *****************************************************************************/ -static void FileClose( input_thread_t * p_input ) -{ - intf_WarnMsg( 1, "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_broadcast = NULL; - int i_port = 0; - int i_opt; - struct sockaddr_in sock; - -#ifdef WIN32 - /* WinSock Library Init. */ - WSADATA Data; - int i_err = WSAStartup( MAKEWORD( 1, 1 ), &Data ); - - if( i_err ) - { - intf_ErrMsg( "input: can't initiate WinSocks, error %i", i_err ); - return ; - } -#endif - - /* 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++; - } - - /* Found a port name */ - if( *psz_port ) - { - /* Replace ':' with '\0' */ - *psz_port = '\0'; - psz_port++; - - psz_broadcast = psz_port; - while( *psz_broadcast && *psz_broadcast != ':' ) - { - psz_broadcast++; - } - - if( *psz_broadcast ) - { - *psz_broadcast = '\0'; - psz_broadcast++; - while( *psz_broadcast && *psz_broadcast == ':' ) - { - psz_broadcast++; - } - } - else - { - psz_broadcast = NULL; - } - - /* port before broadcast address */ - if( *psz_port != ':' ) - { - i_port = atoi( psz_port ); - } - } - } - else - { - psz_server = NULL; - } - } - - /* Check that we got a valid server */ - if( psz_server == NULL ) - { - psz_server = main_GetPszVariable( INPUT_SERVER_VAR, - INPUT_SERVER_DEFAULT ); - } - - /* Check that we got a valid port */ - if( i_port == 0 ) - { - i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT ); - } - - if( psz_broadcast == NULL ) - { - /* Are we broadcasting ? */ - if( main_GetIntVariable( INPUT_BROADCAST_VAR, - INPUT_BROADCAST_DEFAULT ) ) - { - psz_broadcast = main_GetPszVariable( INPUT_BCAST_ADDR_VAR, - INPUT_BCAST_ADDR_DEFAULT ); - } - else - { - psz_broadcast = NULL; - } - } - - intf_WarnMsg( 2, "input: server: %s port: %d broadcast: %s", - psz_server, i_port, psz_broadcast ); - - /* 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 ) - { - 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; - } - - /* 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 ) - { - intf_ErrMsg( "input error: can't configure socket (SO_RCVBUF: %s)", - strerror(errno)); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } - - /* Build the local socket */ - if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) == -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 ) - { - intf_ErrMsg("input error: can't bind socket (%s)", strerror(errno)); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } - - /* Build socket for remote connection */ - if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 ) - { - intf_ErrMsg( "input error: can't build remote address" ); - close( p_input->i_handle ); - p_input->b_error = 1; - return; - } - - /* And connect it ... should we really connect ? */ - 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; - } + p_input->pf_close( p_input ); + module_Unneed( p_input->p_access_module ); - /* We can't pace control, but FIXME : bug in meuuh's code to sync PCR - * with the server. */ - p_input->stream.b_pace_control = 0; - p_input->stream.b_seekable = 0; + input_AccessEnd( p_input ); - intf_WarnMsg( 3, "input: successfully opened network mode" ); - - return; + free( p_input->psz_source ); } /***************************************************************************** - * NetworkClose : close a network socket + * DestroyThread: destroy the input thread *****************************************************************************/ -static void NetworkClose( input_thread_t * p_input ) +static void DestroyThread( input_thread_t * p_input ) { - close( p_input->i_handle ); - -#ifdef WIN32 - WSACleanup(); -#endif - + /* Update status */ + p_input->i_status = THREAD_OVER; } -#endif