X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=802b19c2454b0da759e0bd68aa212eba1aa2bcd8;hb=a0c1805bd992c0ae1fa018156358d831fbaf8f93;hp=cfca95f8deaa248bb55c54da250f5555e5273769;hpb=1c518776d347426d5c926cdf7afe9f18e765ca47;p=vlc diff --git a/src/input/input.c b/src/input/input.c index cfca95f8de..802b19c245 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -4,9 +4,9 @@ * decoders. ***************************************************************************** * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: input.c,v 1.74 2001/02/07 17:44:52 massiot Exp $ + * $Id: input.c,v 1.93 2001/03/15 01:42:20 sam Exp $ * - * Authors: + * Authors: Christophe Massiot * * 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 @@ -36,6 +36,17 @@ #include #include +/* Network functions */ + +#ifndef SYS_BEOS +#include /* hostent ... */ +#include +#include +#include +#include +#include +#endif + #ifdef STATS # include #endif @@ -44,25 +55,32 @@ #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.h" +#include "interface.h" + +#include "main.h" + + /* #include */ + /***************************************************************************** * Local prototypes *****************************************************************************/ -static void RunThread ( input_thread_t *p_input ); -static void InitThread ( input_thread_t *p_input ); -static void ErrorThread ( input_thread_t *p_input ); -static void EndThread ( input_thread_t *p_input ); -static void NetworkOpen ( input_thread_t *p_input ); -static void FileOpen ( input_thread_t *p_input ); -static void DvdOpen ( input_thread_t *p_input ); +static void RunThread ( input_thread_t *p_input ); +static int InitThread ( input_thread_t *p_input ); +static void ErrorThread ( input_thread_t *p_input ); +static void DestroyThread ( input_thread_t *p_input ); +static void EndThread ( input_thread_t *p_input ); /***************************************************************************** * input_CreateThread: creates a new input thread @@ -72,7 +90,7 @@ static void DvdOpen ( 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 ( input_config_t * p_config, int *pi_status ) +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 */ @@ -83,24 +101,37 @@ input_thread_t *input_CreateThread ( input_config_t * p_config, int *pi_status ) { intf_ErrMsg( "input error: can't allocate input thread (%s)", strerror(errno) ); - free( p_config ); 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; + + /* Set target */ + p_input->p_source = 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; - p_input->p_config = p_config; /* Initialize stream description */ 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.i_seek = 0; + p_input->stream.i_mux_rate = 0; + + p_input->stream.i_area_nb = 0; + p_input->stream.pp_areas = NULL; + /* By default there is one areas in a stream */ + input_AddArea( p_input ); + p_input->stream.p_selected_area = p_input->stream.pp_areas[0]; + p_input->stream.p_selected_area->i_seek = NO_SEEK; /* Initialize stream control properties. */ p_input->stream.control.i_status = PLAYING_S; @@ -108,8 +139,13 @@ input_thread_t *input_CreateThread ( input_config_t * p_config, int *pi_status ) p_input->stream.control.b_mute = 0; p_input->stream.control.b_bw = 0; + /* Initialize default settings for spawned decoders */ + p_input->p_default_aout = p_main->p_aout; + p_input->p_default_vout = p_main->p_vout; + /* 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 ) ) @@ -117,7 +153,6 @@ input_thread_t *input_CreateThread ( input_config_t * p_config, int *pi_status ) intf_ErrMsg( "input error: can't create input thread (%s)", strerror(errno) ); free( p_input ); - free( p_config ); return( NULL ); } @@ -153,6 +188,11 @@ void input_DestroyThread( input_thread_t *p_input, int *pi_status ) /* 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 ) { @@ -171,65 +211,92 @@ void input_DestroyThread( input_thread_t *p_input, int *pi_status ) *****************************************************************************/ static void RunThread( input_thread_t *p_input ) { - data_packet_t * pp_packets[INPUT_READ_ONCE]; int i_error, i; - InitThread( 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; + } - while( !p_input->b_die && !p_input->b_error ) + while( !p_input->b_die && !p_input->b_error && !p_input->b_eof ) { + data_packet_t * pp_packets[p_input->i_read_once]; + #ifdef STATS p_input->c_loops++; #endif - vlc_mutex_lock( &p_input->stream.control.control_lock ); - if( p_input->stream.control.i_status == BACKWARD_S - && p_input->p_plugin->pf_rewind != NULL ) + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( p_input->stream.p_selected_area->i_seek != NO_SEEK ) { - p_input->p_plugin->pf_rewind( p_input ); - /* FIXME: probably don't do it every loop, but when ? */ + 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 ); + + 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_selected_area->i_seek = NO_SEEK; } - vlc_mutex_unlock( &p_input->stream.control.control_lock ); + vlc_mutex_unlock( &p_input->stream.stream_lock ); - i_error = p_input->p_plugin->pf_read( p_input, pp_packets ); + i_error = p_input->pf_read( p_input, pp_packets ); /* Demultiplex read packets. */ - for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ ) + for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ ) { - p_input->p_plugin->pf_demux( p_input, pp_packets[i] ); + p_input->pf_demux( p_input, pp_packets[i] ); } if( i_error ) { if( i_error == 1 ) { - /* End of file */ + /* End of file - we do not set b_die because only the + * interface is allowed to do so. */ intf_WarnMsg( 1, "End of file reached" ); - /* FIXME: don't treat that as an error */ + p_input->b_eof = 1; + } + else + { + p_input->b_error = 1; } - p_input->b_error = 1; } } - if( p_input->b_error ) + if( p_input->b_error || p_input->b_eof ) { ErrorThread( p_input ); } EndThread( p_input ); + + DestroyThread( p_input ); + intf_DbgMsg("Thread end"); } /***************************************************************************** - * InitThread: init the input thread + * InitThread: init the input Thread *****************************************************************************/ -input_capabilities_t * PSKludge( void ); -input_capabilities_t * DVDKludge( void ); -static void InitThread( input_thread_t * p_input ) +static int InitThread( input_thread_t * p_input ) { - /* Initialize default settings for spawned decoders */ - p_input->p_default_aout = p_input->p_config->p_default_aout; - p_input->p_default_vout = p_input->p_config->p_default_vout; #ifdef STATS /* Initialize statistics */ @@ -240,50 +307,47 @@ static void InitThread( input_thread_t * p_input ) p_input->c_packets_trashed = 0; #endif - /* Use the appropriate input method */ - switch( p_input->p_config->i_method ) + p_input->p_input_module = module_Need( p_main->p_bank, + MODULE_CAPABILITY_INPUT, + (probedata_t *)p_input ); + + if( p_input->p_input_module == NULL ) { - case INPUT_METHOD_FILE: /* file methods */ - FileOpen( p_input ); - /* Probe plugin (FIXME: load plugins before & write this) */ - p_input->p_plugin = PSKludge(); - break; - case INPUT_METHOD_DVD: /* DVD method */ - DvdOpen( p_input ); - /* DVD plugin */ - p_input->p_plugin = DVDKludge(); - break; - case INPUT_METHOD_VLAN_BCAST: /* vlan network method */ -/* if( !p_main->b_vlans ) - { - intf_ErrMsg("input error: vlans are not activated"); - free( p_input ); - return( NULL ); - } */ /* la-lala */ - /* ... pass through */ - case INPUT_METHOD_UCAST: /* network methods */ - case INPUT_METHOD_MCAST: - case INPUT_METHOD_BCAST: - NetworkOpen( p_input ); - break; -#ifdef DEBUG - default: - intf_ErrMsg( "input error: unknow method 0x%.4x", - p_input->p_config->i_method ); - free( p_input->p_config ); - p_input->b_error = 1; - break; -#endif + intf_ErrMsg( "input error: no suitable input module for `%s'", + p_input->p_source ); + return( -1 ); } - free( p_input->p_config ); +#define f p_input->p_input_module->p_functions->input.functions.input + p_input->pf_init = f.pf_init; + p_input->pf_open = f.pf_open; + p_input->pf_close = f.pf_close; + p_input->pf_end = f.pf_end; + 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; +#undef f + p_input->pf_open( p_input ); - if( !p_input->b_error ) + if( p_input->b_error ) { - p_input->p_plugin->pf_init( p_input ); + /* We barfed -- exit nicely */ + p_input->pf_close( p_input ); + module_Unneed( p_main->p_bank, p_input->p_input_module ); + return( -1 ); } + p_input->pf_init( p_input ); + *p_input->pi_status = THREAD_READY; + + return( 0 ); } /***************************************************************************** @@ -325,8 +389,25 @@ static void EndThread( input_thread_t * p_input ) input_EndStream( p_input ); /* Free demultiplexer's data */ - p_input->p_plugin->pf_end( p_input ); - free( p_input->p_plugin ); + p_input->pf_end( p_input ); + + /* Close stream */ + p_input->pf_close( p_input ); + + /* Release modules */ + module_Unneed( p_main->p_bank, p_input->p_input_module ); + +} + +/***************************************************************************** + * 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 ); @@ -340,33 +421,43 @@ static void EndThread( input_thread_t * p_input ) } /***************************************************************************** - * NetworkOpen : open a network socket descriptor + * input_FileOpen : open a file descriptor *****************************************************************************/ -static void NetworkOpen( input_thread_t * p_input ) -{ - /* straight copy & paste of input_network.c of input-I */ - - /* We cannot rewind nor lseek() */ - p_input->stream.b_seekable = 0; - /* We cannot control the pace */ - p_input->stream.b_pace_control = 0; -} - -/***************************************************************************** - * FileOpen : open a file descriptor - *****************************************************************************/ -static void FileOpen( input_thread_t * p_input ) +void input_FileOpen( input_thread_t * p_input ) { struct stat stat_info; + int i_stat; -#define p_config p_input->p_config + char *psz_name = p_input->p_source; - if( stat( p_config->p_source, &stat_info ) == (-1) ) + /* 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) ) { - intf_ErrMsg( "input error: cannot stat() file `%s' (%s)", - p_config->p_source, strerror(errno)); - p_input->b_error = 1; - return; + 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 ); @@ -378,27 +469,31 @@ static void FileOpen( input_thread_t * p_input ) || S_ISBLK(stat_info.st_mode) ) { p_input->stream.b_seekable = 1; - p_input->stream.i_size = stat_info.st_size; + p_input->stream.p_selected_area->i_size = stat_info.st_size; } - else if( S_ISFIFO(stat_info.st_mode) || S_ISSOCK(stat_info.st_mode) ) + else if( S_ISFIFO(stat_info.st_mode) +#ifndef SYS_BEOS + || S_ISSOCK(stat_info.st_mode) +#endif + ) { p_input->stream.b_seekable = 0; - p_input->stream.i_size = 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'", - p_config->p_source ); + psz_name ); p_input->b_error = 1; return; } - p_input->stream.i_tell = 0; + p_input->stream.p_selected_area->i_tell = 0; vlc_mutex_unlock( &p_input->stream.stream_lock ); - intf_Msg( "input: opening file %s", p_config->p_source ); - if( (p_input->i_handle = open( p_config->p_source, + intf_Msg( "input: opening %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) ); @@ -406,29 +501,131 @@ static void FileOpen( input_thread_t * p_input ) return; } -#undef p_config } /***************************************************************************** - * DvdOpen : open the dvd device + * input_FileClose : close a file descriptor *****************************************************************************/ -static void DvdOpen( input_thread_t * p_input ) +void input_FileClose( input_thread_t * p_input ) { - intf_Msg( "input: opening DVD %s", p_input->p_config->p_source ); - if( (p_input->i_handle = open( p_input->p_config->p_source, - O_RDONLY| O_NONBLOCK |O_LARGEFILE )) == (-1) ) + close( p_input->i_handle ); + + return; +} + + +#ifndef SYS_BEOS +/***************************************************************************** + * input_NetworkOpen : open a network socket + *****************************************************************************/ +void input_NetworkOpen( input_thread_t * p_input ) +{ + + int i_option_value, i_port; + struct sockaddr_in s_socket; + boolean_t b_broadcast; + + /* FIXME : we don't handle channels for the moment */ + + /* Get the remote server */ + if( p_input->p_source == NULL ) + { + p_input->p_source = main_GetPszVariable( INPUT_SERVER_VAR, + INPUT_SERVER_DEFAULT ); + } + + /* 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: cannot open device (%s)", strerror(errno) ); + intf_ErrMsg("NetworkOpen : can't create socket : %s", strerror(errno)); p_input->b_error = 1; return; } - vlc_mutex_lock( &p_input->stream.stream_lock ); + /* We may want to reuse an already used socket */ + i_option_value = 1; + if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR, + &i_option_value,sizeof( i_option_value ) ) == -1 ) + { + intf_ErrMsg("NetworkOpen : 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_option_value = 524288; + if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF, &i_option_value, + sizeof( i_option_value ) ) == -1 ) + { + intf_ErrMsg("NetworkOpen : can't configure socket (SO_RCVBUF: %s)", + strerror(errno)); + close( p_input->i_handle ); + p_input->b_error = 1; + return; + } + + /* Get details about what we are supposed to do */ + b_broadcast = (boolean_t)main_GetIntVariable( INPUT_BROADCAST_VAR, 0 ); + i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT ); + + /* TODO : here deal with channel stufs */ + + /* Build the local socket */ + if ( network_BuildLocalAddr( &s_socket, i_port, b_broadcast ) + == -1 ) + { + close( p_input->i_handle ); + p_input->b_error = 1; + return; + } + + /* Bind it */ + if( bind( p_input->i_handle, (struct sockaddr *)&s_socket, + sizeof( s_socket ) ) < 0 ) + { + intf_ErrMsg("NetworkOpen: 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( &s_socket, p_input->p_source ) + == -1 ) + { + 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 *) &s_socket, + sizeof( s_socket ) ) == (-1) ) + { + intf_ErrMsg("NetworkOpen: can't connect socket" ); + close( p_input->i_handle ); + p_input->b_error = 1; + return; + } + + /* We can't pace control, but FIXME : bug in meuuh's code to sync PCR + * with the server. */ p_input->stream.b_pace_control = 1; - p_input->stream.b_seekable = 1; - p_input->stream.i_size = 0; - p_input->stream.i_tell = 0; + + return; +} - vlc_mutex_unlock( &p_input->stream.stream_lock ); +/***************************************************************************** + * input_NetworkClose : close a network socket + *****************************************************************************/ +void input_NetworkClose( input_thread_t * p_input ) +{ + close( p_input->i_handle ); + /* FIXME: deal with channels */ } +#endif