X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=2d51bfa59fb1806e877ca566e2c39e2b6d8f2c82;hb=e01eb15e2a09e0dcb42b2145770b7ae2d2e42436;hp=87c1ada0227460c842060134ec309ae6e36e8009;hpb=d1bc2bc33724e0354c439cc20f17b2ec142102f0;p=vlc diff --git a/src/input/input.c b/src/input/input.c index 87c1ada022..2d51bfa59f 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-2001 VideoLAN - * $Id: input.c,v 1.195 2002/05/14 21:23:44 massiot Exp $ + * Copyright (C) 1998-2002 VideoLAN + * $Id: input.c,v 1.231 2003/06/24 13:33:48 sam Exp $ * * Authors: Christophe Massiot * @@ -12,7 +12,7 @@ * 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 @@ -27,29 +27,26 @@ * Preamble *****************************************************************************/ #include -#include -#include -#include -#include +#include #include -#include #ifdef HAVE_SYS_TIMES_H # include #endif -#include "netutils.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 + +#include "vlc_interface.h" /***************************************************************************** * Local prototypes @@ -57,95 +54,43 @@ 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 ); -/***************************************************************************** - * 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 ***************************************************************************** * This function creates a new input, and returns a pointer * to its description. On error, it returns NULL. - * 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 ) { input_thread_t * p_input; /* thread descriptor */ + 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; } /* Initialize thread properties */ - p_input->b_die = 0; - p_input->b_error = 0; p_input->b_eof = 0; /* Set target */ - p_input->psz_source = strdup( p_item->psz_name ); - - /* Set status */ - p_input->i_status = THREAD_CREATE; + p_input->psz_source = strdup( p_item->psz_uri ); /* 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; + p_input->p_demux = 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->p_access = NULL; + p_input->i_bufsize = 0; p_input->i_mtu = 0; + p_input->i_pts_delay = DEFAULT_PTS_DELAY; /* Initialize statistics */ p_input->c_loops = 0; @@ -153,9 +98,9 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) 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 ); + 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; @@ -165,6 +110,8 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) 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; @@ -179,41 +126,42 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) p_input->stream.p_newly_selected_es = NULL; /* By default there is one area in a stream */ - input_AddArea( p_input ); + input_AddArea( p_input, 0, 1 ); p_input->stream.p_selected_area = p_input->stream.pp_areas[0]; /* Initialize stream control properties. */ 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 = config_GetIntVariable( "grayscale" ); - p_input->stream.control.i_smp = config_GetIntVariable( "vdec-smp" ); - - intf_WarnMsg( 1, "input: playlist item `%s'", p_input->psz_source ); + p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale" ); - /* Create thread. */ - if( vlc_thread_create( &p_input->thread_id, "input", - (vlc_thread_func_t)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; + + msg_Info( p_input, "playlist item `%s'", p_input->psz_source ); -#if 0 - /* If status is NULL, wait until the thread is created */ - if( pi_status == NULL ) + 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) ); + msg_Err( p_input, "cannot create input thread" ); + free( p_input ); + return NULL; } -#endif - return( p_input ); + return p_input; } /***************************************************************************** @@ -221,28 +169,15 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) ***************************************************************************** * This function should not return until the thread is effectively cancelled. *****************************************************************************/ -void input_StopThread( input_thread_t *p_input, int *pi_status ) +void input_StopThread( input_thread_t *p_input ) { /* 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; 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 - { - msleep( THREAD_SLEEP ); - } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR) - && (i_status != THREAD_FATAL) ); - } -#endif } /***************************************************************************** @@ -253,15 +188,12 @@ void input_StopThread( input_thread_t *p_input, int *pi_status ) void input_DestroyThread( input_thread_t *p_input ) { /* Join the thread */ - vlc_thread_join( p_input->thread_id ); + 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 ); - - /* Free input structure */ - free( p_input ); } /***************************************************************************** @@ -271,18 +203,18 @@ void input_DestroyThread( input_thread_t *p_input ) *****************************************************************************/ static int RunThread( input_thread_t *p_input ) { + /* 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->i_status = THREAD_ERROR; p_input->b_error = 1; ErrorThread( p_input ); - DestroyThread( p_input ); + p_input->b_dead = 1; return 0; } - p_input->i_status = THREAD_READY; - /* initialization is complete */ vlc_mutex_lock( &p_input->stream.stream_lock ); p_input->stream.b_changed = 1; @@ -290,7 +222,7 @@ static int RunThread( input_thread_t *p_input ) while( !p_input->b_die && !p_input->b_error && !p_input->b_eof ) { - int i, i_count; + unsigned int i, i_count; p_input->c_loops++; @@ -303,9 +235,9 @@ static int RunThread( input_thread_t *p_input ) /* Reinitialize buffer manager. */ input_AccessReinit( p_input ); - - p_input->pf_set_program( p_input, - p_input->stream.p_new_program ); + + p_input->pf_set_program( p_input, + p_input->stream.p_new_program ); /* Escape all decoders for the stream discontinuity they * will encounter. */ @@ -322,7 +254,7 @@ static int RunThread( input_thread_t *p_input ) } 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 ) @@ -349,7 +281,8 @@ static int 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 ) { off_t i_new_pos; @@ -408,11 +341,11 @@ static int RunThread( input_thread_t *p_input ) /* Read and demultiplex some data. */ i_count = p_input->pf_demux( p_input ); - if( i_count == 0 && p_input->stream.b_seekable ) + if( i_count == 0 ) { /* End of file - we do not set b_die because only the - * interface is allowed to do so. */ - intf_WarnMsg( 3, "input: EOF reached" ); + * playlist is allowed to do so. */ + msg_Info( p_input, "EOF reached" ); p_input->b_eof = 1; } else if( i_count < 0 ) @@ -428,8 +361,6 @@ static int RunThread( input_thread_t *p_input ) EndThread( p_input ); - DestroyThread( p_input ); - return 0; } @@ -439,18 +370,18 @@ static int 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; + char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source); /* Skip the plug-in names */ while( *psz_parser && *psz_parser != ':' ) { psz_parser++; } -#ifdef WIN32 - if( psz_parser - p_input->psz_source == 1 ) +#if defined( WIN32 ) || defined( UNDER_CE ) + if( psz_parser - p_input->psz_dupsource == 1 ) { - intf_WarnMsg( 2, "Drive letter %c: specified in source string", - p_input->psz_source ) ; + msg_Warn( p_input, "drive letter %c: found in source string", + p_input->psz_dupsource[0] ) ; psz_parser = ""; } #endif @@ -459,6 +390,8 @@ static int InitThread( input_thread_t * p_input ) { p_input->psz_access = p_input->psz_demux = ""; p_input->psz_name = p_input->psz_source; + free( p_input->psz_dupsource ); + p_input->psz_dupsource = NULL; } else { @@ -468,12 +401,12 @@ static int InitThread( input_thread_t * p_input ) if( psz_parser[0] == '/' && psz_parser[1] == '/' ) { psz_parser += 2 ; - } + } p_input->psz_name = psz_parser ; /* Come back to parse the access and demux plug-ins */ - psz_parser = p_input->psz_source; + psz_parser = p_input->psz_dupsource; if( !*psz_parser ) { @@ -512,36 +445,38 @@ static int InitThread( input_thread_t * p_input ) } } - intf_WarnMsg( 2, "input: access `%s', demux `%s', name `%s'", - p_input->psz_access, p_input->psz_demux, - p_input->psz_name ); + msg_Dbg( p_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 ) { - return( -1 ); + return -1; } - /* Find and open appropriate access plug-in. */ - p_input->p_access_module = module_Need( MODULE_CAPABILITY_ACCESS, - p_input->psz_access, - (void *)p_input ); + /* Find and open appropriate access module */ + p_input->p_access = module_Need( p_input, "access", + p_input->psz_access ); - if( p_input->p_access_module == NULL ) + if ( p_input->p_access == NULL + && (*p_input->psz_demux || *p_input->psz_access) ) { - 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 ); + /* Maybe we got something like : + * /Volumes/toto:titi/gabu.mpg */ + p_input->psz_access = p_input->psz_demux = ""; + p_input->psz_name = p_input->psz_source; + free( p_input->psz_dupsource); + p_input->psz_dupsource = NULL; + + p_input->p_access = module_Need( p_input, "access", + p_input->psz_access ); } -#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_set_program = f.pf_set_program; - p_input->pf_seek = f.pf_seek; -#undef f + if( p_input->p_access == NULL ) + { + 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; + } /* Waiting for stream. */ if( p_input->i_mtu ) @@ -553,40 +488,54 @@ static int InitThread( input_thread_t * p_input ) p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE; } + /* If the desynchronisation requested by the user is < 0, we need to + * cache more data. */ + if( p_input->p_vlc->i_desync < 0 ) + p_input->i_pts_delay -= p_input->p_vlc->i_desync; + 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 ) + if( p_input->b_die || p_input->b_error || p_input->b_eof ) { - module_Unneed( p_input->p_access_module ); - return( -1 ); + module_Unneed( p_input, p_input->p_access ); + return -1; } } } - /* Find and open appropriate demux plug-in. */ - p_input->p_demux_module = module_Need( MODULE_CAPABILITY_DEMUX, - p_input->psz_demux, - (void *)p_input ); + /* Find and open appropriate demux module */ + p_input->p_demux = module_Need( p_input, "demux", + p_input->psz_demux ); - if( p_input->p_demux_module == NULL ) + if( p_input->p_demux == NULL ) { - 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 ); + 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; } -#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 + /* Initialize optional stream output. */ + psz_parser = config_GetPsz( p_input, "sout" ); + if ( psz_parser != NULL ) + { + if ( *psz_parser && + (p_input->stream.p_sout = sout_NewInstance( p_input, psz_parser )) + == NULL ) + { + 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; + } - return( 0 ); + free( psz_parser ); + } + + return 0; } /***************************************************************************** @@ -608,56 +557,56 @@ static void ErrorThread( input_thread_t *p_input ) *****************************************************************************/ static void EndThread( input_thread_t * p_input ) { - /* Store status */ - p_input->i_status = THREAD_END; + vlc_object_t *p_object; - if( p_main->b_stats ) - { #ifdef HAVE_SYS_TIMES_H - /* Display statistics */ - struct tms cpu_usage; - times( &cpu_usage ); + /* 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 ); + msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld", + p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime ); #else - intf_StatMsg( "input stats: %d loops", p_input->c_loops ); + msg_Dbg( p_input, "%ld loops", p_input->c_loops ); #endif - input_DumpStream( p_input ); - } + /* Free info structures */ + msg_Dbg( p_input, "freeing info structures..."); + input_DelInfo( p_input ); + + input_DumpStream( p_input ); /* Free all ES and destroy all decoder threads */ input_EndStream( p_input ); + /* Close optional stream output instance */ + if ( p_input->stream.p_sout != NULL ) + { + sout_DeleteInstance( p_input->stream.p_sout ); + } + /* Free demultiplexer's data */ - p_input->pf_end( p_input ); - module_Unneed( p_input->p_demux_module ); + module_Unneed( p_input, p_input->p_demux ); /* Close the access plug-in */ - CloseThread( p_input ); -} - -/***************************************************************************** - * CloseThread: close the target - *****************************************************************************/ -static void CloseThread( input_thread_t * p_input ) -{ - p_input->pf_close( p_input ); - module_Unneed( p_input->p_access_module ); + module_Unneed( p_input, p_input->p_access ); input_AccessEnd( p_input ); + /* Close the video output that should have been re-attached + * to our object */ + p_object = vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD ); + if( p_object ) + { + vlc_object_detach( p_object ); + vlc_object_release( p_object ); + vout_Destroy( (vout_thread_t *)p_object ); + } + free( p_input->psz_source ); -} + if ( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource ); -/***************************************************************************** - * DestroyThread: destroy the input thread - *****************************************************************************/ -static void DestroyThread( input_thread_t * p_input ) -{ - /* Update status */ - p_input->i_status = THREAD_OVER; + /* Tell we're dead */ + p_input->b_dead = 1; }