X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=23ee04166f12a551ec49c4931d7cc92e797500e7;hb=4455e6d2935a498e02ac3c6ac144f0525d2e01f0;hp=63a148029d21448996035d65d0fa8ac81deb1ba4;hpb=fc3d65f7ba6c167dad776f1d5136a22e1db39563;p=vlc diff --git a/src/input/input.c b/src/input/input.c index 63a148029d..23ee04166f 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -1,25 +1,25 @@ /***************************************************************************** * input.c: input thread ***************************************************************************** - * Copyright (C) 1998-2007 the VideoLAN team + * Copyright (C) 1998-2007 VLC authors and VideoLAN * $Id$ * * Authors: Christophe Massiot * Laurent Aimar * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "input_internal.h" #include "event.h" @@ -46,8 +48,6 @@ #include "resource.h" #include -#include "../stream_output/stream_output.h" - #include #include #include @@ -55,16 +55,12 @@ #include #include -#ifdef HAVE_SYS_STAT_H -# include -#endif - /***************************************************************************** * Local prototypes *****************************************************************************/ static void Destructor( input_thread_t * p_input ); -static void *Run ( vlc_object_t *p_this ); +static void *Run ( void * ); static input_thread_t * Create ( vlc_object_t *, input_item_t *, const char *, bool, input_resource_t * ); @@ -72,20 +68,16 @@ static int Init ( input_thread_t *p_input ); static void End ( input_thread_t *p_input ); static void MainLoop( input_thread_t *p_input, bool b_interactive ); -static void ObjectKillChildrens( input_thread_t *, vlc_object_t * ); - static inline int ControlPop( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline, bool b_postpone_seek ); static void ControlRelease( int i_type, vlc_value_t val ); static bool ControlIsSeekRequest( int i_type ); static bool Control( input_thread_t *, int, vlc_value_t ); -static int UpdateTitleSeekpointFromAccess( input_thread_t * ); -static void UpdateGenericFromAccess( input_thread_t * ); - static int UpdateTitleSeekpointFromDemux( input_thread_t * ); static void UpdateGenericFromDemux( input_thread_t * ); +static void UpdateTitleListfromDemux( input_thread_t * ); -static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *); +static void MRLSections( const char *, int *, int *, int *, int *); static input_source_t *InputSourceNew( input_thread_t *); static int InputSourceInit( input_thread_t *, input_source_t *, @@ -96,25 +88,26 @@ static void InputSourceMeta( input_thread_t *, input_source_t *, vlc_meta_t * ); /* TODO */ //static void InputGetAttachments( input_thread_t *, input_source_t * ); -static void SlaveDemux( input_thread_t *p_input, bool *pb_demux_polled ); +static void SlaveDemux( input_thread_t *p_input ); static void SlaveSeek( input_thread_t *p_input ); static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta ); -static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta ); +static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux ); static void InputGetExtraFiles( input_thread_t *p_input, int *pi_list, char ***pppsz_list, const char *psz_access, const char *psz_path ); -static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment, - int i_new, input_attachment_t **pp_new ); +static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment, demux_t ***ppp_attachment_demux, + int i_new, input_attachment_t **pp_new, demux_t *p_demux ); enum { SUB_NOFLAG = 0x00, SUB_FORCED = 0x01, SUB_CANFAIL = 0x02, }; -static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, unsigned i_flags ); +static void input_SubtitleAdd( input_thread_t *, const char *, unsigned ); +static void input_SubtitleFileAdd( input_thread_t *, char *, unsigned ); static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO fix name */ #undef input_Create @@ -199,8 +192,20 @@ int input_Preparse( vlc_object_t *p_parent, input_item_t *p_item ) if( !p_input ) return VLC_EGENERIC; - if( !Init( p_input ) ) + if( !Init( p_input ) ) { + /* if the demux is a playlist, call Mainloop that will call + * demux_Demux in order to fetch sub items */ + bool b_is_playlist = false; + + if ( input_item_ShouldPreparseSubItems( p_item ) + && demux_Control( p_input->p->input.p_demux, + DEMUX_IS_PLAYLIST, + &b_is_playlist ) ) + b_is_playlist = false; + if( b_is_playlist ) + MainLoop( p_input, false ); End( p_input ); + } vlc_object_release( p_input ); @@ -217,7 +222,9 @@ int input_Preparse( vlc_object_t *p_parent, input_item_t *p_item ) int input_Start( input_thread_t *p_input ) { /* Create thread and wait for its readiness. */ - if( vlc_thread_create( p_input, Run, VLC_THREAD_PRIORITY_INPUT ) ) + p_input->p->is_running = !vlc_clone( &p_input->p->thread, + Run, p_input, VLC_THREAD_PRIORITY_INPUT ); + if( !p_input->p->is_running ) { input_ChangeState( p_input, ERROR_S ); msg_Err( p_input, "cannot create input thread" ); @@ -229,25 +236,37 @@ int input_Start( input_thread_t *p_input ) /** * Request a running input thread to stop and die * - * b_abort must be true when a user stop is requested and not because you have - * detected an error or an eof. It will be used to properly send the - * INPUT_EVENT_ABORT event. - * * \param p_input the input thread to stop - * \param b_abort true if the input has been aborted by a user request */ -void input_Stop( input_thread_t *p_input, bool b_abort ) +void input_Stop( input_thread_t *p_input ) { /* Set die for input and ALL of this childrens (even (grand-)grand-childrens) * It is needed here even if it is done in INPUT_CONTROL_SET_DIE handler to * unlock the control loop */ - ObjectKillChildrens( p_input, VLC_OBJECT(p_input) ); + ObjectKillChildrens( VLC_OBJECT(p_input) ); + input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL ); +} - vlc_mutex_lock( &p_input->p->lock_control ); - p_input->p->b_abort |= b_abort; - vlc_mutex_unlock( &p_input->p->lock_control ); +void input_Join( input_thread_t *p_input ) +{ + if( p_input->p->is_running ) + vlc_join( p_input->p->thread, NULL ); +} - input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL ); +void input_Release( input_thread_t *p_input ) +{ + vlc_object_release( p_input ); +} + +/** + * Close an input + * + * It does not call input_Stop itself. + */ +void input_Close( input_thread_t *p_input ) +{ + input_Join( p_input ); + input_Release( p_input ); } /** @@ -262,29 +281,6 @@ input_item_t *input_GetItem( input_thread_t *p_input ) return p_input->p->p_item; } -/***************************************************************************** - * ObjectKillChildrens - *****************************************************************************/ -static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj ) -{ - vlc_list_t *p_list; - int i; - - /* FIXME ObjectKillChildrens seems a very bad idea in fact */ - i = vlc_internals( p_obj )->i_object_type; - if( i == VLC_OBJECT_VOUT ||i == VLC_OBJECT_AOUT || - p_obj == VLC_OBJECT(p_input->p->p_sout) || - i == VLC_OBJECT_DECODER ) - return; - - vlc_object_kill( p_obj ); - - p_list = vlc_list_children( p_obj ); - for( i = 0; i < p_list->i_count; i++ ) - ObjectKillChildrens( p_input, p_list->p_values[i].p_object ); - vlc_list_release( p_list ); -} - /***************************************************************************** * This function creates a new input, and returns a pointer * to its description. On error, it returns NULL. @@ -295,18 +291,14 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, const char *psz_header, bool b_quick, input_resource_t *p_resource ) { - static const char input_name[] = "input"; input_thread_t *p_input = NULL; /* thread descriptor */ int i; /* Allocate descriptor */ - p_input = vlc_custom_create( p_parent, sizeof( *p_input ), - VLC_OBJECT_INPUT, input_name ); + p_input = vlc_custom_create( p_parent, sizeof( *p_input ), "input" ); if( p_input == NULL ) return NULL; - vlc_object_attach( p_input, p_parent ); - /* Construct a nice name for the input timer */ char psz_timer_name[255]; char * psz_name = input_item_GetName( p_item ); @@ -317,14 +309,12 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, free( psz_name ); - /* Start a timer to mesure how long it takes - * to launch an input */ - stats_TimerStart( p_input, psz_timer_name, - STATS_TIMER_INPUT_LAUNCHING ); - p_input->p = calloc( 1, sizeof( input_thread_private_t ) ); if( !p_input->p ) + { + vlc_object_release( p_input ); return NULL; + } /* Parse input options */ vlc_mutex_lock( &p_item->lock ); @@ -348,17 +338,12 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, p_input->p->title = NULL; p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0; p_input->p->i_state = INIT_S; - double f_rate = var_InheritFloat( p_input, "rate" ); - if( f_rate <= 0. ) - { - msg_Warn( p_input, "Negative or zero rate values are forbidden" ); - f_rate = 1.; - } - p_input->p->i_rate = INPUT_RATE_DEFAULT / f_rate; + p_input->p->i_rate = INPUT_RATE_DEFAULT; p_input->p->b_recording = false; memset( &p_input->p->bookmark, 0, sizeof(p_input->p->bookmark) ); TAB_INIT( p_input->p->i_bookmark, p_input->p->pp_bookmark ); TAB_INIT( p_input->p->i_attachment, p_input->p->attachment ); + p_input->p->attachment_demux = NULL; p_input->p->p_sout = NULL; p_input->p->b_out_pace_control = false; @@ -366,8 +351,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, p_input->p->p_item = p_item; /* Init Input fields */ - p_input->p->input.p_access = NULL; - p_input->p->input.p_stream = NULL; p_input->p->input.p_demux = NULL; p_input->p->input.b_title_demux = false; p_input->p->input.i_title = 0; @@ -382,6 +365,26 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, if( !p_item->p_stats ) p_item->p_stats = stats_NewInputStats( p_input ); + + /* setup the preparse depth of the item + * if we are preparsing, use the i_preparse_depth of the parent item */ + if( !p_input->b_preparsing ) + { + char *psz_rec = var_InheritString( p_parent, "recursive" ); + + if( psz_rec != NULL ) + { + if ( !strcasecmp( psz_rec, "none" ) ) + p_item->i_preparse_depth = 0; + else if ( !strcasecmp( psz_rec, "collapse" ) ) + p_item->i_preparse_depth = 1; + else + p_item->i_preparse_depth = -1; /* default is expand */ + free (psz_rec); + } else + p_item->i_preparse_depth = -1; + } + vlc_mutex_unlock( &p_item->lock ); /* No slave */ @@ -405,7 +408,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, vlc_mutex_init( &p_input->p->lock_control ); vlc_cond_init( &p_input->p->wait_control ); p_input->p->i_control = 0; - p_input->p->b_abort = false; + p_input->p->is_running = false; /* Create Object Variables for private use only */ input_ConfigVarInit( p_input ); @@ -449,7 +452,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, else if( !strncmp( psz_start, "time=", 5 ) ) { p_seekpoint->i_time_offset = atoll(psz_start + 5) * - 1000000; + CLOCK_FREQ; } psz_start = psz_end + 1; } @@ -466,6 +469,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, /* Remove 'Now playing' info as it is probably outdated */ input_item_SetNowPlaying( p_item, NULL ); + input_item_SetESNowPlaying( p_item, NULL ); input_SendEventMeta( p_input ); /* */ @@ -500,9 +504,6 @@ static void Destructor( input_thread_t * p_input ) free( psz_name ); #endif - stats_TimerDump( p_input, STATS_TIMER_INPUT_LAUNCHING ); - stats_TimerClean( p_input, STATS_TIMER_INPUT_LAUNCHING ); - if( p_input->p->p_es_out_display ) es_out_Delete( p_input->p->p_es_out_display ); @@ -531,27 +532,19 @@ static void Destructor( input_thread_t * p_input ) * This is the "normal" thread that spawns the input processing chain, * reads the stream, cleans up and waits *****************************************************************************/ -static void *Run( vlc_object_t *p_this ) +static void *Run( void *obj ) { - input_thread_t *p_input = (input_thread_t *)p_this; + input_thread_t *p_input = (input_thread_t *)obj; const int canc = vlc_savecancel(); - if( Init( p_input ) ) - goto exit; - - MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */ - - /* Clean up */ - End( p_input ); + if( !Init( p_input ) ) + { + MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */ -exit: - /* Tell we're dead */ - vlc_mutex_lock( &p_input->p->lock_control ); - const bool b_abort = p_input->p->b_abort; - vlc_mutex_unlock( &p_input->p->lock_control ); + /* Clean up */ + End( p_input ); + } - if( b_abort ) - input_SendEventAbort( p_input ); input_SendEventDead( p_input ); vlc_restorecancel( canc ); @@ -566,12 +559,11 @@ exit: * MainLoopDemux * It asks the demuxer to demux some data */ -static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, bool *pb_demux_polled, mtime_t i_start_mdate ) +static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, mtime_t i_start_mdate ) { int i_ret; *pb_changed = false; - *pb_demux_polled = p_input->p->input.p_demux->pf_demux != NULL; if( ( p_input->p->i_stop > 0 && p_input->p->i_time >= p_input->p->i_stop ) || ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) ) @@ -583,6 +575,11 @@ static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, bool *pb_d { if( p_input->p->input.p_demux->info.i_update ) { + if( p_input->p->input.p_demux->info.i_update & INPUT_UPDATE_TITLE_LIST ) + { + UpdateTitleListfromDemux( p_input ); + p_input->p->input.p_demux->info.i_update &= ~INPUT_UPDATE_TITLE_LIST; + } if( p_input->p->input.b_title_demux ) { i_ret = UpdateTitleSeekpointFromDemux( p_input ); @@ -590,22 +587,13 @@ static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, bool *pb_d } UpdateGenericFromDemux( p_input ); } - else if( p_input->p->input.p_access && - p_input->p->input.p_access->info.i_update ) - { - if( !p_input->p->input.b_title_demux ) - { - i_ret = UpdateTitleSeekpointFromAccess( p_input ); - *pb_changed = true; - } - UpdateGenericFromAccess( p_input ); - } } if( i_ret == 0 ) /* EOF */ { msg_Dbg( p_input, "EOF reached" ); p_input->p->input.b_eof = true; + es_out_Eos(p_input->p->p_es_out); } else if( i_ret < 0 ) { @@ -613,12 +601,7 @@ static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, bool *pb_d } if( i_ret > 0 && p_input->p->i_slave > 0 ) - { - bool b_demux_polled; - SlaveDemux( p_input, &b_demux_polled ); - - *pb_demux_polled |= b_demux_polled; - } + SlaveDemux( p_input ); } static int MainLoopTryRepeat( input_thread_t *p_input, mtime_t *pi_start_mdate ) @@ -658,7 +641,7 @@ static int MainLoopTryRepeat( input_thread_t *p_input, mtime_t *pi_start_mdate ) } else { - val.f_float = 0.0; + val.f_float = 0.f; input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val ); } @@ -668,10 +651,9 @@ static int MainLoopTryRepeat( input_thread_t *p_input, mtime_t *pi_start_mdate ) } /** - * MainLoopInterface - * It update the variables used by the interfaces + * Update timing infos and statistics. */ -static void MainLoopInterface( input_thread_t *p_input ) +static void MainLoopStatistics( input_thread_t *p_input ) { double f_position = 0.0; mtime_t i_time = 0; @@ -696,17 +678,9 @@ static void MainLoopInterface( input_thread_t *p_input ) /* update current bookmark */ vlc_mutex_lock( &p_input->p->p_item->lock ); p_input->p->bookmark.i_time_offset = i_time; - if( p_input->p->input.p_stream ) - p_input->p->bookmark.i_byte_offset = stream_Tell( p_input->p->input.p_stream ); + p_input->p->bookmark.i_byte_offset = -1; vlc_mutex_unlock( &p_input->p->p_item->lock ); -} -/** - * MainLoopStatistic - * It updates the globals statics - */ -static void MainLoopStatistic( input_thread_t *p_input ) -{ stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats ); input_SendEventStatistics( p_input ); } @@ -719,40 +693,31 @@ static void MainLoop( input_thread_t *p_input, bool b_interactive ) { mtime_t i_start_mdate = mdate(); mtime_t i_intf_update = 0; - mtime_t i_statistic_update = 0; mtime_t i_last_seek_mdate = 0; bool b_pause_after_eof = b_interactive && var_CreateGetBool( p_input, "play-and-pause" ); - /* Start the timer */ - stats_TimerStop( p_input, STATS_TIMER_INPUT_LAUNCHING ); - while( vlc_object_alive( p_input ) && !p_input->b_error ) { - bool b_force_update; - vlc_value_t val; - mtime_t i_current; - mtime_t i_wakeup; - bool b_paused; - bool b_demux_polled; - - /* Demux data */ - b_force_update = false; - i_wakeup = 0; + mtime_t i_wakeup = -1; + bool b_paused = p_input->p->i_state == PAUSE_S; /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux * is paused -> this may cause problem with some of them * The same problem can be seen when seeking while paused */ - b_paused = p_input->p->i_state == PAUSE_S && - ( !es_out_GetBuffering( p_input->p->p_es_out ) || p_input->p->input.b_eof ); + if( b_paused ) + b_paused = !es_out_GetBuffering( p_input->p->p_es_out ) || p_input->p->input.b_eof; - b_demux_polled = true; if( !b_paused ) { if( !p_input->p->input.b_eof ) { - MainLoopDemux( p_input, &b_force_update, &b_demux_polled, i_start_mdate ); + bool b_force_update = false; + MainLoopDemux( p_input, &b_force_update, i_start_mdate ); i_wakeup = es_out_GetWakeup( p_input->p->p_es_out ); + + if( b_force_update ) + i_intf_update = 0; } else if( !es_out_GetEmpty( p_input->p->p_es_out ) ) { @@ -763,8 +728,9 @@ static void MainLoop( input_thread_t *p_input, bool b_interactive ) * This way we won't trigger timeshifting for nothing */ else if( b_pause_after_eof && p_input->p->b_can_pause ) { + vlc_value_t val = { .i_int = PAUSE_S }; + msg_Dbg( p_input, "pausing at EOF (pause after each)"); - val.i_int = PAUSE_S; Control( p_input, INPUT_CONTROL_SET_STATE, val ); b_paused = true; @@ -775,70 +741,61 @@ static void MainLoop( input_thread_t *p_input, bool b_interactive ) break; b_pause_after_eof = var_GetBool( p_input, "play-and-pause" ); } + + /* Update interface and statistics */ + mtime_t now = mdate(); + if( now >= i_intf_update ) + { + MainLoopStatistics( p_input ); + i_intf_update = now + INT64_C(250000); + } } - /* */ - do { + /* Handle control */ + for( ;; ) + { mtime_t i_deadline = i_wakeup; - if( b_paused || !b_demux_polled ) - i_deadline = __MIN( i_intf_update, i_statistic_update ); - /* Handle control */ - for( ;; ) + /* Postpone seeking until ES buffering is complete or at most + * 125 ms. */ + bool b_postpone = es_out_GetBuffering( p_input->p->p_es_out ) + && !p_input->p->input.b_eof; + if( b_postpone ) { - mtime_t i_limit = i_deadline; - - /* We will postpone the execution of a seek until we have - * finished the ES bufferisation (postpone is limited to - * 125ms) */ - bool b_buffering = es_out_GetBuffering( p_input->p->p_es_out ) && - !p_input->p->input.b_eof; - if( b_buffering ) - { - /* When postpone is in order, check the ES level every 20ms */ - mtime_t i_current = mdate(); - if( i_last_seek_mdate + INT64_C(125000) >= i_current ) - i_limit = __MIN( i_deadline, i_current + INT64_C(20000) ); - } - - int i_type; - if( ControlPop( p_input, &i_type, &val, i_limit, b_buffering ) ) - { - if( b_buffering && i_limit < i_deadline ) - continue; - break; - } - -#ifndef NDEBUG - msg_Dbg( p_input, "control type=%d", i_type ); -#endif + mtime_t now = mdate(); - if( Control( p_input, i_type, val ) ) - { - if( ControlIsSeekRequest( i_type ) ) - i_last_seek_mdate = mdate(); - b_force_update = true; - } + /* Recheck ES buffer level every 20 ms when seeking */ + if( now < i_last_seek_mdate + INT64_C(125000) + && (i_deadline < 0 || i_deadline > now + INT64_C(20000)) ) + i_deadline = now + INT64_C(20000); + else + b_postpone = false; } - /* Update interface and statistics */ - i_current = mdate(); - if( i_intf_update < i_current || b_force_update ) + int i_type; + vlc_value_t val; + + if( ControlPop( p_input, &i_type, &val, i_deadline, b_postpone ) ) { - MainLoopInterface( p_input ); - i_intf_update = i_current + INT64_C(250000); - b_force_update = false; + if( b_postpone ) + continue; + break; /* Wake-up time reached */ } - if( i_statistic_update < i_current ) + +#ifndef NDEBUG + msg_Dbg( p_input, "control type=%d", i_type ); +#endif + if( Control( p_input, i_type, val ) ) { - MainLoopStatistic( p_input ); - i_statistic_update = i_current + INT64_C(1000000); + if( ControlIsSeekRequest( i_type ) ) + i_last_seek_mdate = mdate(); + i_intf_update = 0; } /* Update the wakeup time */ if( i_wakeup != 0 ) i_wakeup = es_out_GetWakeup( p_input->p->p_es_out ); - } while( i_current < i_wakeup ); + } } if( !p_input->b_error ) @@ -850,31 +807,27 @@ static void InitStatistics( input_thread_t * p_input ) if( p_input->b_preparsing ) return; /* Prepare statistics */ -#define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \ - stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute); +#define INIT_COUNTER( c, compute ) p_input->p->counters.p_##c = \ + stats_CounterCreate( STATS_##compute); if( libvlc_stats( p_input ) ) { - INIT_COUNTER( read_bytes, INTEGER, COUNTER ); - INIT_COUNTER( read_packets, INTEGER, COUNTER ); - INIT_COUNTER( demux_read, INTEGER, COUNTER ); - INIT_COUNTER( input_bitrate, FLOAT, DERIVATIVE ); - INIT_COUNTER( demux_bitrate, FLOAT, DERIVATIVE ); - INIT_COUNTER( demux_corrupted, INTEGER, COUNTER ); - INIT_COUNTER( demux_discontinuity, INTEGER, COUNTER ); - INIT_COUNTER( played_abuffers, INTEGER, COUNTER ); - INIT_COUNTER( lost_abuffers, INTEGER, COUNTER ); - INIT_COUNTER( displayed_pictures, INTEGER, COUNTER ); - INIT_COUNTER( lost_pictures, INTEGER, COUNTER ); - INIT_COUNTER( decoded_audio, INTEGER, COUNTER ); - INIT_COUNTER( decoded_video, INTEGER, COUNTER ); - INIT_COUNTER( decoded_sub, INTEGER, COUNTER ); + INIT_COUNTER( read_bytes, COUNTER ); + INIT_COUNTER( read_packets, COUNTER ); + INIT_COUNTER( demux_read, COUNTER ); + INIT_COUNTER( input_bitrate, DERIVATIVE ); + INIT_COUNTER( demux_bitrate, DERIVATIVE ); + INIT_COUNTER( demux_corrupted, COUNTER ); + INIT_COUNTER( demux_discontinuity, COUNTER ); + INIT_COUNTER( played_abuffers, COUNTER ); + INIT_COUNTER( lost_abuffers, COUNTER ); + INIT_COUNTER( displayed_pictures, COUNTER ); + INIT_COUNTER( lost_pictures, COUNTER ); + INIT_COUNTER( decoded_audio, COUNTER ); + INIT_COUNTER( decoded_video, COUNTER ); + INIT_COUNTER( decoded_sub, COUNTER ); p_input->p->counters.p_sout_send_bitrate = NULL; p_input->p->counters.p_sout_sent_packets = NULL; p_input->p->counters.p_sout_sent_bytes = NULL; - if( p_input->p->counters.p_demux_bitrate ) - p_input->p->counters.p_demux_bitrate->update_interval = 1000000; - if( p_input->p->counters.p_input_bitrate ) - p_input->p->counters.p_input_bitrate->update_interval = 1000000; } } @@ -899,12 +852,9 @@ static int InitSout( input_thread_t * p_input ) } if( libvlc_stats( p_input ) ) { - INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER ); - INIT_COUNTER( sout_sent_bytes, INTEGER, COUNTER ); - INIT_COUNTER( sout_send_bitrate, FLOAT, DERIVATIVE ); - if( p_input->p->counters.p_sout_send_bitrate ) - p_input->p->counters.p_sout_send_bitrate->update_interval = - 1000000; + INIT_COUNTER( sout_sent_packets, COUNTER ); + INIT_COUNTER( sout_sent_bytes, COUNTER ); + INIT_COUNTER( sout_send_bitrate, DERIVATIVE ); } } else @@ -924,6 +874,7 @@ static void InitTitle( input_thread_t * p_input ) if( p_input->b_preparsing ) return; + vlc_mutex_lock( &p_input->p->p_item->lock ); /* Create global title (from master) */ p_input->p->i_title = p_master->i_title; p_input->p->title = p_master->title; @@ -940,6 +891,7 @@ static void InitTitle( input_thread_t * p_input ) p_input->p->b_can_pace_control = p_master->b_can_pace_control; p_input->p->b_can_pause = p_master->b_can_pause; p_input->p->b_can_rate_control = p_master->b_can_rate_control; + vlc_mutex_unlock( &p_input->p->p_item->lock ); } static void StartTitle( input_thread_t * p_input ) @@ -958,11 +910,11 @@ static void StartTitle( input_thread_t * p_input ) input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val ); /* Start/stop/run time */ - p_input->p->i_start = (int64_t)(1000000.0 + p_input->p->i_start = llroundf(1000000.f * var_GetFloat( p_input, "start-time" )); - p_input->p->i_stop = (int64_t)(1000000.0 + p_input->p->i_stop = llroundf(1000000.f * var_GetFloat( p_input, "stop-time" )); - p_input->p->i_run = (int64_t)(1000000.0 + p_input->p->i_run = llroundf(1000000.f * var_GetFloat( p_input, "run-time" )); if( p_input->p->i_run < 0 ) { @@ -975,7 +927,7 @@ static void StartTitle( input_thread_t * p_input ) vlc_value_t s; msg_Dbg( p_input, "starting at time: %ds", - (int)( p_input->p->i_start / INT64_C(1000000) ) ); + (int)( p_input->p->i_start / CLOCK_FREQ ) ); s.i_time = p_input->p->i_start; input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s ); @@ -992,15 +944,13 @@ static void LoadSubtitles( input_thread_t *p_input ) { /* Load subtitles */ /* Get fps and set it if not already set */ - const double f_fps = p_input->p->f_fps; - if( f_fps > 1.0 ) + const float f_fps = p_input->p->f_fps; + if( f_fps > 1.f ) { - float f_requested_fps; - var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT ); var_SetFloat( p_input, "sub-original-fps", f_fps ); - f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" ); + float f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" ); if( f_requested_fps != f_fps ) { var_Create( p_input, "sub-fps", VLC_VAR_FLOAT| @@ -1020,7 +970,7 @@ static void LoadSubtitles( input_thread_t *p_input ) if( psz_subtitle != NULL ) { msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle ); - SubtitleAdd( p_input, psz_subtitle, i_flags ); + input_SubtitleFileAdd( p_input, psz_subtitle, i_flags ); i_flags = SUB_NOFLAG; } @@ -1036,7 +986,7 @@ static void LoadSubtitles( input_thread_t *p_input ) if( !psz_subtitle || strcmp( psz_subtitle, ppsz_subs[i] ) ) { i_flags |= SUB_CANFAIL; - SubtitleAdd( p_input, ppsz_subs[i], i_flags ); + input_SubtitleFileAdd( p_input, ppsz_subs[i], i_flags ); i_flags = SUB_NOFLAG; } @@ -1074,7 +1024,7 @@ static void LoadSubtitles( input_thread_t *p_input ) { var_SetString( p_input, "sub-description", a->psz_description ? a->psz_description : ""); - SubtitleAdd( p_input, psz_mrl, i_flags ); + input_SubtitleAdd( p_input, psz_mrl, i_flags ); i_flags = SUB_NOFLAG; free( psz_mrl ); @@ -1105,7 +1055,8 @@ static void LoadSlaves( input_thread_t *p_input ) if( *psz == 0 ) break; - char *uri = make_URI( psz, NULL ); + char *uri = strstr(psz, "://") + ? strdup( psz ) : vlc_path2uri( psz, NULL ); psz = psz_delim; if( uri == NULL ) continue; @@ -1163,11 +1114,6 @@ static void InitPrograms( input_thread_t * p_input ) { char *prgms; - if( var_GetBool( p_input, "sout-all" ) ) - { - i_es_out_mode = ES_OUT_MODE_ALL; - } - else if( (prgms = var_GetNonEmptyString( p_input, "programs" )) != NULL ) { char *buf; @@ -1187,6 +1133,10 @@ static void InitPrograms( input_thread_t * p_input ) free( prgms ); } + else if( var_GetBool( p_input, "sout-all" ) ) + { + i_es_out_mode = ES_OUT_MODE_ALL; + } } es_out_SetMode( p_input->p->p_es_out, i_es_out_mode ); @@ -1210,10 +1160,7 @@ static void InitPrograms( input_thread_t * p_input ) static int Init( input_thread_t * p_input ) { - vlc_meta_t *p_meta; - int i; - - for( i = 0; i < p_input->p->p_item->i_options; i++ ) + for( int i = 0; i < p_input->p->p_item->i_options; i++ ) { if( !strncmp( p_input->p->p_item->ppsz_options[i], "meta-file", 9 ) ) { @@ -1267,6 +1214,13 @@ static int Init( input_thread_t * p_input ) LoadSubtitles( p_input ); LoadSlaves( p_input ); InitPrograms( p_input ); + + double f_rate = var_InheritFloat( p_input, "rate" ); + if( f_rate != 0.0 && f_rate != 1.0 ) + { + vlc_value_t val = { .i_int = INPUT_RATE_DEFAULT / f_rate }; + input_ControlPush( p_input, INPUT_CONTROL_SET_RATE, &val ); + } } if( !p_input->b_preparsing && p_input->p->p_sout ) @@ -1277,15 +1231,15 @@ static int Init( input_thread_t * p_input ) { /* We don't want a high input priority here or we'll * end-up sucking up all the CPU time */ - vlc_thread_set_priority( p_input, VLC_THREAD_PRIORITY_LOW ); + vlc_set_priority( p_input->p->thread, VLC_THREAD_PRIORITY_LOW ); } msg_Dbg( p_input, "starting in %s mode", p_input->p->b_out_pace_control ? "async" : "sync" ); } - p_meta = vlc_meta_New(); - if( p_meta ) + vlc_meta_t *p_meta = vlc_meta_New(); + if( p_meta != NULL ) { /* Get meta data from users */ InputMetaUser( p_input, p_meta ); @@ -1297,8 +1251,8 @@ static int Init( input_thread_t * p_input ) for( int i = 0; i < p_input->p->i_slave; i++ ) InputSourceMeta( p_input, p_input->p->slave[i], p_meta ); - /* */ - InputUpdateMeta( p_input, p_meta ); + es_out_ControlSetMeta( p_input->p->p_es_out, p_meta ); + vlc_meta_Delete( p_meta ); } msg_Dbg( p_input, "`%s' successfully opened", @@ -1356,8 +1310,6 @@ error: /* Mark them deleted */ p_input->p->input.p_demux = NULL; - p_input->p->input.p_stream = NULL; - p_input->p->input.p_access = NULL; p_input->p->p_es_out = NULL; p_input->p->p_sout = NULL; @@ -1435,6 +1387,8 @@ static void End( input_thread_t * p_input ) for( i = 0; i < p_input->p->i_attachment; i++ ) vlc_input_attachment_Delete( p_input->p->attachment[i] ); TAB_CLEAN( p_input->p->i_attachment, p_input->p->attachment ); + free( p_input->p->attachment_demux); + p_input->p->attachment_demux = NULL; } vlc_mutex_unlock( &p_input->p->p_item->lock ); @@ -1531,18 +1485,23 @@ static inline int ControlPop( input_thread_t *p_input, while( p_sys->i_control <= 0 || ( b_postpone_seek && ControlIsSeekRequest( p_sys->control[0].i_type ) ) ) { - if( !vlc_object_alive( p_input ) || i_deadline < 0 ) + if( !vlc_object_alive( p_input ) ) { vlc_mutex_unlock( &p_sys->lock_control ); return VLC_EGENERIC; } - if( vlc_cond_timedwait( &p_sys->wait_control, &p_sys->lock_control, - i_deadline ) ) + if( i_deadline >= 0 ) { - vlc_mutex_unlock( &p_sys->lock_control ); - return VLC_EGENERIC; + if( vlc_cond_timedwait( &p_sys->wait_control, &p_sys->lock_control, + i_deadline ) ) + { + vlc_mutex_unlock( &p_sys->lock_control ); + return VLC_EGENERIC; + } } + else + vlc_cond_wait( &p_sys->wait_control, &p_sys->lock_control ); } /* */ @@ -1573,6 +1532,11 @@ static bool ControlIsSeekRequest( int i_type ) case INPUT_CONTROL_SET_SEEKPOINT_NEXT: case INPUT_CONTROL_SET_SEEKPOINT_PREV: case INPUT_CONTROL_SET_BOOKMARK: + case INPUT_CONTROL_NAV_ACTIVATE: + case INPUT_CONTROL_NAV_UP: + case INPUT_CONTROL_NAV_DOWN: + case INPUT_CONTROL_NAV_LEFT: + case INPUT_CONTROL_NAV_RIGHT: return true; default: return false; @@ -1601,12 +1565,12 @@ static void ControlPause( input_thread_t *p_input, mtime_t i_control_date ) if( p_input->p->b_can_pause ) { - if( p_input->p->input.p_access ) - i_ret = access_Control( p_input->p->input.p_access, - ACCESS_SET_PAUSE_STATE, true ); + demux_t *p_demux = p_input->p->input.p_demux; + + if( p_demux->s != NULL ) + i_ret = stream_Control( p_demux->s, STREAM_SET_PAUSE_STATE, true ); else - i_ret = demux_Control( p_input->p->input.p_demux, - DEMUX_SET_PAUSE_STATE, true ); + i_ret = demux_Control( p_demux, DEMUX_SET_PAUSE_STATE, true ); if( i_ret ) { @@ -1635,12 +1599,12 @@ static void ControlUnpause( input_thread_t *p_input, mtime_t i_control_date ) if( p_input->p->b_can_pause ) { - if( p_input->p->input.p_access ) - i_ret = access_Control( p_input->p->input.p_access, - ACCESS_SET_PAUSE_STATE, false ); + demux_t *p_demux = p_input->p->input.p_demux; + + if( p_demux->s != NULL ) + i_ret = stream_Control( p_demux->s, STREAM_SET_PAUSE_STATE, false ); else - i_ret = demux_Control( p_input->p->input.p_demux, - DEMUX_SET_PAUSE_STATE, false ); + i_ret = demux_Control( p_demux, DEMUX_SET_PAUSE_STATE, false ); if( i_ret ) { /* FIXME What to do ? */ @@ -1673,32 +1637,29 @@ static bool Control( input_thread_t *p_input, msg_Dbg( p_input, "control: stopping input" ); /* Mark all submodules to die */ - ObjectKillChildrens( p_input, VLC_OBJECT(p_input) ); + ObjectKillChildrens( VLC_OBJECT(p_input) ); break; case INPUT_CONTROL_SET_POSITION: { - double f_pos; - if( p_input->p->b_recording ) { msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) ignored while recording" ); break; } - f_pos = val.f_float; - if( i_type != INPUT_CONTROL_SET_POSITION ) - f_pos += var_GetFloat( p_input, "position" ); - if( f_pos < 0.0 ) - f_pos = 0.0; - else if( f_pos > 1.0 ) - f_pos = 1.0; + + float f_pos = val.f_float; + if( f_pos < 0.f ) + f_pos = 0.f; + else if( f_pos > 1.f ) + f_pos = 1.f; /* Reset the decoders states and clock sync (before calling the demuxer */ es_out_SetTime( p_input->p->p_es_out, -1 ); if( demux_Control( p_input->p->input.p_demux, DEMUX_SET_POSITION, - f_pos, !p_input->p->b_fast_seek ) ) + (double) f_pos, !p_input->p->b_fast_seek ) ) { msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) " - "%2.1f%% failed", f_pos * 100 ); + "%2.1f%% failed", (double)(f_pos * 100.f) ); } else { @@ -1723,9 +1684,6 @@ static bool Control( input_thread_t *p_input, } i_time = val.i_time; - if( i_type != INPUT_CONTROL_SET_TIME ) - i_time += var_GetTime( p_input, "time" ); - if( i_time < 0 ) i_time = 0; @@ -1833,12 +1791,10 @@ static bool Control( input_thread_t *p_input, if( i_rate != p_input->p->i_rate && !p_input->p->b_can_pace_control && p_input->p->b_can_rate_control ) { - int i_ret; - if( p_input->p->input.p_access ) - { - i_ret = VLC_EGENERIC; - } - else + demux_t *p_demux = p_input->p->input.p_demux; + int i_ret = VLC_EGENERIC; + + if( p_demux->s == NULL ) { if( !p_input->p->input.b_rescale_ts ) es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); @@ -1881,11 +1837,15 @@ static bool Control( input_thread_t *p_input, case INPUT_CONTROL_SET_ES: /* No need to force update, es_out does it if needed */ - es_out_Control( p_input->p->p_es_out_display, ES_OUT_SET_ES_BY_ID, val.i_int ); + es_out_Control( p_input->p->p_es_out_display, + ES_OUT_SET_ES_BY_ID, (int)val.i_int ); + + demux_Control( p_input->p->input.p_demux, DEMUX_SET_ES, (int)val.i_int ); break; case INPUT_CONTROL_RESTART_ES: - es_out_Control( p_input->p->p_es_out_display, ES_OUT_RESTART_ES_BY_ID, val.i_int ); + es_out_Control( p_input->p->p_es_out_display, + ES_OUT_RESTART_ES_BY_ID, (int)val.i_int ); break; case INPUT_CONTROL_SET_AUDIO_DELAY: @@ -1901,155 +1861,88 @@ static bool Control( input_thread_t *p_input, case INPUT_CONTROL_SET_TITLE: case INPUT_CONTROL_SET_TITLE_NEXT: case INPUT_CONTROL_SET_TITLE_PREV: + { if( p_input->p->b_recording ) { msg_Err( p_input, "INPUT_CONTROL_SET_TITLE(*) ignored while recording" ); break; } - if( p_input->p->input.b_title_demux && - p_input->p->input.i_title > 0 ) - { - /* TODO */ - /* FIXME handle demux title */ - demux_t *p_demux = p_input->p->input.p_demux; - int i_title; - - if( i_type == INPUT_CONTROL_SET_TITLE_PREV ) - i_title = p_demux->info.i_title - 1; - else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT ) - i_title = p_demux->info.i_title + 1; - else - i_title = val.i_int; - - if( i_title >= 0 && i_title < p_input->p->input.i_title ) - { - es_out_SetTime( p_input->p->p_es_out, -1 ); - - demux_Control( p_demux, DEMUX_SET_TITLE, i_title ); - input_SendEventTitle( p_input, i_title ); - } - } - else if( p_input->p->input.i_title > 0 ) - { - access_t *p_access = p_input->p->input.p_access; - int i_title; - - if( i_type == INPUT_CONTROL_SET_TITLE_PREV ) - i_title = p_access->info.i_title - 1; - else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT ) - i_title = p_access->info.i_title + 1; - else - i_title = val.i_int; + if( p_input->p->input.i_title <= 0 ) + break; - if( i_title >= 0 && i_title < p_input->p->input.i_title ) - { - es_out_SetTime( p_input->p->p_es_out, -1 ); + int i_title = p_input->p->input.p_demux->info.i_title; + if( i_type == INPUT_CONTROL_SET_TITLE_PREV ) + i_title--; + else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT ) + i_title++; + else + i_title = val.i_int; + if( i_title < 0 || i_title >= p_input->p->input.i_title ) + break; - stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS, - ACCESS_SET_TITLE, i_title ); - input_SendEventTitle( p_input, i_title ); - } - } + es_out_SetTime( p_input->p->p_es_out, -1 ); + demux_Control( p_input->p->input.p_demux, + DEMUX_SET_TITLE, i_title ); + input_SendEventTitle( p_input, i_title ); break; + } case INPUT_CONTROL_SET_SEEKPOINT: case INPUT_CONTROL_SET_SEEKPOINT_NEXT: case INPUT_CONTROL_SET_SEEKPOINT_PREV: + { if( p_input->p->b_recording ) { msg_Err( p_input, "INPUT_CONTROL_SET_SEEKPOINT(*) ignored while recording" ); break; } + if( p_input->p->input.i_title <= 0 ) + break; - if( p_input->p->input.b_title_demux && - p_input->p->input.i_title > 0 ) - { - demux_t *p_demux = p_input->p->input.p_demux; - int i_seekpoint; - int64_t i_input_time; - int64_t i_seekpoint_time; - - if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV ) - { - i_seekpoint = p_demux->info.i_seekpoint; - i_seekpoint_time = p_input->p->input.title[p_demux->info.i_title]->seekpoint[i_seekpoint]->i_time_offset; - i_input_time = var_GetTime( p_input, "time" ); - if( i_seekpoint_time >= 0 && i_input_time >= 0 ) - { - if( i_input_time < i_seekpoint_time + 3000000 ) - i_seekpoint--; - } - else - i_seekpoint--; - } - else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) - i_seekpoint = p_demux->info.i_seekpoint + 1; - else - i_seekpoint = val.i_int; - - if( i_seekpoint >= 0 && i_seekpoint < - p_input->p->input.title[p_demux->info.i_title]->i_seekpoint ) - { + demux_t *p_demux = p_input->p->input.p_demux; - es_out_SetTime( p_input->p->p_es_out, -1 ); + int i_title = p_demux->info.i_title; + int i_seekpoint = p_demux->info.i_seekpoint; - demux_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint ); - input_SendEventSeekpoint( p_input, p_demux->info.i_title, i_seekpoint ); - } - } - else if( p_input->p->input.i_title > 0 ) + if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV ) { - access_t *p_access = p_input->p->input.p_access; - int i_seekpoint; - int64_t i_input_time; - int64_t i_seekpoint_time; - - if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV ) + int64_t i_seekpoint_time = p_input->p->input.title[i_title]->seekpoint[i_seekpoint]->i_time_offset; + int64_t i_input_time = var_GetTime( p_input, "time" ); + if( i_seekpoint_time >= 0 && i_input_time >= 0 ) { - i_seekpoint = p_access->info.i_seekpoint; - i_seekpoint_time = p_input->p->input.title[p_access->info.i_title]->seekpoint[i_seekpoint]->i_time_offset; - i_input_time = var_GetTime( p_input, "time" ); - if( i_seekpoint_time >= 0 && i_input_time >= 0 ) - { - if( i_input_time < i_seekpoint_time + 3000000 ) - i_seekpoint--; - } - else + if( i_input_time < i_seekpoint_time + 3000000 ) i_seekpoint--; } - else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) - i_seekpoint = p_access->info.i_seekpoint + 1; else - i_seekpoint = val.i_int; - - if( i_seekpoint >= 0 && i_seekpoint < - p_input->p->input.title[p_access->info.i_title]->i_seekpoint ) - { - es_out_SetTime( p_input->p->p_es_out, -1 ); - - stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS, - ACCESS_SET_SEEKPOINT, i_seekpoint ); - input_SendEventSeekpoint( p_input, p_access->info.i_title, i_seekpoint ); - } + i_seekpoint--; } + else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) + i_seekpoint++; + else + i_seekpoint = val.i_int; + if( i_seekpoint < 0 + || i_seekpoint >= p_input->p->input.title[i_title]->i_seekpoint ) + break; + + es_out_SetTime( p_input->p->p_es_out, -1 ); + demux_Control( p_input->p->input.p_demux, + DEMUX_SET_SEEKPOINT, i_seekpoint ); + input_SendEventSeekpoint( p_input, i_title, i_seekpoint ); break; + } case INPUT_CONTROL_ADD_SUBTITLE: if( val.psz_string ) - SubtitleAdd( p_input, val.psz_string, true ); + input_SubtitleFileAdd( p_input, val.psz_string, true ); break; case INPUT_CONTROL_ADD_SLAVE: if( val.psz_string ) { - char *uri = make_URI( val.psz_string, NULL ); - if( uri == NULL ) - break; - + const char *uri = val.psz_string; input_source_t *slave = InputSourceNew( p_input ); if( slave && !InputSourceInit( p_input, slave, uri, NULL, false ) ) { - vlc_meta_t *p_meta; int64_t i_time; /* Add the slave */ @@ -2074,13 +1967,7 @@ static bool Control( input_thread_t *p_input, } /* Get meta (access and demux) */ - p_meta = vlc_meta_New(); - if( p_meta ) - { - access_Control( slave->p_access, ACCESS_GET_META, p_meta ); - demux_Control( slave->p_demux, DEMUX_GET_META, p_meta ); - InputUpdateMeta( p_input, p_meta ); - } + InputUpdateMeta( p_input, slave->p_demux ); TAB_APPEND( p_input->p->i_slave, p_input->p->slave, slave ); } @@ -2089,7 +1976,6 @@ static bool Control( input_thread_t *p_input, free( slave ); msg_Warn( p_input, "failed to add %s as slave", uri ); } - free( uri ); } break; @@ -2133,44 +2019,36 @@ static bool Control( input_thread_t *p_input, case INPUT_CONTROL_SET_BOOKMARK: { - seekpoint_t bookmark; - - bookmark.i_time_offset = -1; - bookmark.i_byte_offset = -1; + mtime_t time_offset = -1; vlc_mutex_lock( &p_input->p->p_item->lock ); if( val.i_int >= 0 && val.i_int < p_input->p->i_bookmark ) { const seekpoint_t *p_bookmark = p_input->p->pp_bookmark[val.i_int]; - bookmark.i_time_offset = p_bookmark->i_time_offset; - bookmark.i_byte_offset = p_bookmark->i_byte_offset; + time_offset = p_bookmark->i_time_offset; } vlc_mutex_unlock( &p_input->p->p_item->lock ); - if( bookmark.i_time_offset < 0 && bookmark.i_byte_offset < 0 ) + if( time_offset < 0 ) { msg_Err( p_input, "invalid bookmark %"PRId64, val.i_int ); break; } - if( bookmark.i_time_offset >= 0 ) - { - val.i_time = bookmark.i_time_offset; - b_force_update = Control( p_input, INPUT_CONTROL_SET_TIME, val ); - } - else if( bookmark.i_byte_offset >= 0 && - p_input->p->input.p_stream ) - { - const uint64_t i_size = stream_Size( p_input->p->input.p_stream ); - if( i_size > 0 && bookmark.i_byte_offset <= i_size ) - { - val.f_float = (double)bookmark.i_byte_offset / i_size; - b_force_update = Control( p_input, INPUT_CONTROL_SET_POSITION, val ); - } - } + val.i_time = time_offset; + b_force_update = Control( p_input, INPUT_CONTROL_SET_TIME, val ); break; } + case INPUT_CONTROL_NAV_ACTIVATE: + case INPUT_CONTROL_NAV_UP: + case INPUT_CONTROL_NAV_DOWN: + case INPUT_CONTROL_NAV_LEFT: + case INPUT_CONTROL_NAV_RIGHT: + demux_Control( p_input->p->input.p_demux, i_type + - INPUT_CONTROL_NAV_ACTIVATE + DEMUX_NAV_ACTIVATE ); + break; + default: msg_Err( p_input, "not yet implemented" ); break; @@ -2245,79 +2123,43 @@ static void UpdateGenericFromDemux( input_thread_t *p_input ) if( p_demux->info.i_update & INPUT_UPDATE_META ) { - vlc_meta_t *p_meta = vlc_meta_New(); - if( p_meta ) - { - demux_Control( p_input->p->input.p_demux, DEMUX_GET_META, p_meta ); - InputUpdateMeta( p_input, p_meta ); - } + InputUpdateMeta( p_input, p_demux ); p_demux->info.i_update &= ~INPUT_UPDATE_META; } - - p_demux->info.i_update &= ~INPUT_UPDATE_SIZE; -} - - -/***************************************************************************** - * Update*FromAccess: - *****************************************************************************/ -static int UpdateTitleSeekpointFromAccess( input_thread_t *p_input ) -{ - access_t *p_access = p_input->p->input.p_access; - - if( p_access->info.i_update & INPUT_UPDATE_TITLE ) { - input_SendEventTitle( p_input, p_access->info.i_title ); + double quality; + double strength; - stream_Control( p_input->p->input.p_stream, STREAM_UPDATE_SIZE ); - - p_access->info.i_update &= ~INPUT_UPDATE_TITLE; + if( !demux_Control( p_demux, DEMUX_GET_SIGNAL, &quality, &strength ) ) + input_SendEventSignal( p_input, quality, strength ); } - if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT ) - { - input_SendEventSeekpoint( p_input, - p_access->info.i_title, p_access->info.i_seekpoint ); - - p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT; - } - /* Hmmm only works with master input */ - if( p_input->p->input.p_access == p_access ) - return UpdateTitleSeekpoint( p_input, - p_access->info.i_title, - p_access->info.i_seekpoint ); - return 1; } -static void UpdateGenericFromAccess( input_thread_t *p_input ) + +static void UpdateTitleListfromDemux( input_thread_t *p_input ) { - access_t *p_access = p_input->p->input.p_access; + input_source_t *in = &p_input->p->input; - if( p_access->info.i_update & INPUT_UPDATE_META ) + /* Delete the preexisting titles */ + if( in->i_title > 0 ) { - /* TODO maybe multi - access ? */ - vlc_meta_t *p_meta = vlc_meta_New(); - if( p_meta ) - { - access_Control( p_input->p->input.p_access, ACCESS_GET_META, p_meta ); - InputUpdateMeta( p_input, p_meta ); - } - p_access->info.i_update &= ~INPUT_UPDATE_META; + for( int i = 0; i < in->i_title; i++ ) + vlc_input_title_Delete( in->title[i] ); + TAB_CLEAN( in->i_title, in->title ); + in->b_title_demux = false; } - if( p_access->info.i_update & INPUT_UPDATE_SIGNAL ) - { - double f_quality; - double f_strength; - if( access_Control( p_access, ACCESS_GET_SIGNAL, &f_quality, &f_strength ) ) - f_quality = f_strength = -1; - - input_SendEventSignal( p_input, f_quality, f_strength ); - - p_access->info.i_update &= ~INPUT_UPDATE_SIGNAL; - } + /* Get the new title list */ + if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO, + &in->title, &in->i_title, + &in->i_title_offset, &in->i_seekpoint_offset ) ) + TAB_INIT( in->i_title, in->title ); + else + in->b_title_demux = true; - p_access->info.i_update &= ~INPUT_UPDATE_SIZE; + InitTitle( p_input ); } + /***************************************************************************** * InputSourceNew: *****************************************************************************/ @@ -2335,9 +2177,7 @@ static int InputSourceInit( input_thread_t *p_input, input_source_t *in, const char *psz_mrl, const char *psz_forced_demux, bool b_in_can_fail ) { - const char *psz_access; - const char *psz_demux; - char *psz_path; + const char *psz_access, *psz_demux, *psz_path, *psz_anchor = NULL; char *psz_var_demux = NULL; double f_fps; @@ -2348,22 +2188,15 @@ static int InputSourceInit( input_thread_t *p_input, goto error; /* Split uri */ - input_SplitMRL( &psz_access, &psz_demux, &psz_path, psz_dup ); + input_SplitMRL( &psz_access, &psz_demux, &psz_path, &psz_anchor, psz_dup ); msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'", psz_mrl, psz_access, psz_demux, psz_path ); if( !p_input->b_preparsing ) { - /* Hack to allow udp://@:port syntax */ - if( !psz_access || - (strncmp( psz_access, "udp", 3 ) && - strncmp( psz_access, "rtp", 3 )) ) - { - /* Find optional titles and seekpoints */ - MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end, + /* Find optional titles and seekpoints */ + MRLSections( psz_anchor, &in->i_title_start, &in->i_title_end, &in->i_seekpoint_start, &in->i_seekpoint_end ); - } - if( psz_forced_demux && *psz_forced_demux ) { psz_demux = psz_forced_demux; @@ -2373,31 +2206,23 @@ static int InputSourceInit( input_thread_t *p_input, /* special hack for forcing a demuxer with --demux=module * (and do nothing with a list) */ psz_var_demux = var_GetNonEmptyString( p_input, "demux" ); - - if( psz_var_demux != NULL && - !strchr(psz_var_demux, ',' ) && - !strchr(psz_var_demux, ':' ) ) - { - psz_demux = psz_var_demux; - - msg_Dbg( p_input, "enforced demux ` %s'", psz_demux ); - } + psz_demux = psz_var_demux; + msg_Dbg( p_input, "specified demux `%s'", psz_demux ); } /* Try access_demux first */ - in->p_demux = demux_New( p_input, p_input, psz_access, psz_demux, psz_path, - NULL, p_input->p->p_es_out, false ); + in->p_demux = demux_New( p_input, p_input, psz_access, psz_demux, + psz_path, NULL, p_input->p->p_es_out, false ); } else { - /* Preparsing is only for file:// */ if( *psz_demux ) goto error; - if( strcmp( psz_access, "file" ) ) - goto error; msg_Dbg( p_input, "trying to pre-parse %s", psz_path ); } + mtime_t i_pts_delay; + if( in->p_demux ) { /* Get infos from access_demux */ @@ -2441,10 +2266,10 @@ static int InputSourceInit( input_thread_t *p_input, var_SetBool( p_input, "can-seek", b_can_seek ); } else - { - /* Now try a real access */ - in->p_access = access_New( p_input, p_input, psz_access, psz_demux, psz_path ); - if( in->p_access == NULL ) + { /* Now try a real access */ + access_t *p_access = access_New( p_input, p_input, + psz_access, psz_demux, psz_path ); + if( p_access == NULL ) { if( vlc_object_alive( p_input ) ) { @@ -2457,32 +2282,9 @@ static int InputSourceInit( input_thread_t *p_input, goto error; } - /* Get infos from access */ - if( !p_input->b_preparsing ) - { - bool b_can_seek; - - in->b_title_demux = false; - if( access_Control( in->p_access, ACCESS_GET_TITLE_INFO, - &in->title, &in->i_title, - &in->i_title_offset, &in->i_seekpoint_offset ) ) - - { - TAB_INIT( in->i_title, in->title ); - } - access_Control( in->p_access, ACCESS_CAN_CONTROL_PACE, - &in->b_can_pace_control ); - in->b_can_rate_control = in->b_can_pace_control; - in->b_rescale_ts = true; - - access_Control( in->p_access, ACCESS_CAN_PAUSE, &in->b_can_pause ); - var_SetBool( p_input, "can-pause", in->b_can_pause || !in->b_can_pace_control ); /* XXX temporary because of es_out_timeshift*/ - var_SetBool( p_input, "can-rate", !in->b_can_pace_control || in->b_can_rate_control ); /* XXX temporary because of es_out_timeshift*/ - var_SetBool( p_input, "can-rewind", !in->b_rescale_ts && !in->b_can_pace_control ); - - access_Control( in->p_access, ACCESS_CAN_SEEK, &b_can_seek ); - var_SetBool( p_input, "can-seek", b_can_seek ); - } + /* Access-forced demuxer (PARENTAL ADVISORY: EXPLICIT HACK) */ + if( !psz_demux[0] || !strcasecmp( psz_demux, "any" ) ) + psz_demux = p_access->psz_demux; /* */ int i_input_list; @@ -2526,7 +2328,7 @@ static int InputSourceInit( input_thread_t *p_input, TAB_APPEND( i_input_list, ppsz_input_list, NULL ); /* Create the stream_t */ - in->p_stream = stream_AccessNew( in->p_access, ppsz_input_list ); + stream_t *p_stream = stream_AccessNew( p_access, ppsz_input_list ); if( ppsz_input_list ) { for( int i = 0; ppsz_input_list[i] != NULL; i++ ) @@ -2534,7 +2336,7 @@ static int InputSourceInit( input_thread_t *p_input, TAB_CLEAN( i_input_list, ppsz_input_list ); } - if( in->p_stream == NULL ) + if( p_stream == NULL ) { msg_Warn( p_input, "cannot create a stream_t from access" ); goto error; @@ -2543,21 +2345,39 @@ static int InputSourceInit( input_thread_t *p_input, /* Add stream filters */ char *psz_stream_filter = var_GetNonEmptyString( p_input, "stream-filter" ); - in->p_stream = stream_FilterChainNew( in->p_stream, - psz_stream_filter, - var_GetBool( p_input, "input-record-native" ) ); + p_stream = stream_FilterChainNew( p_stream, psz_stream_filter, + var_GetBool( p_input, "input-record-native" ) ); free( psz_stream_filter ); - /* Open a demuxer */ - if( *psz_demux == '\0' && *in->p_access->psz_demux ) + if( !p_input->b_preparsing ) { - psz_demux = in->p_access->psz_demux; + bool b; + + stream_Control( p_stream, STREAM_CAN_CONTROL_PACE, + &in->b_can_pace_control ); + in->b_can_rate_control = in->b_can_pace_control; + in->b_rescale_ts = true; + + stream_Control( p_stream, STREAM_CAN_PAUSE, &in->b_can_pause ); + var_SetBool( p_input, "can-pause", + in->b_can_pause || !in->b_can_pace_control ); /* XXX temporary because of es_out_timeshift*/ + var_SetBool( p_input, "can-rate", + !in->b_can_pace_control || in->b_can_rate_control ); /* XXX temporary because of es_out_timeshift*/ + var_SetBool( p_input, "can-rewind", + !in->b_rescale_ts && !in->b_can_pace_control ); + + stream_Control( p_stream, STREAM_CAN_SEEK, &b ); + var_SetBool( p_input, "can-seek", b ); + + in->b_title_demux = false; + + stream_Control( p_stream, STREAM_GET_PTS_DELAY, &i_pts_delay ); } in->p_demux = demux_New( p_input, p_input, psz_access, psz_demux, /* Take access/stream redirections into account: */ - in->p_stream->psz_path ? in->p_stream->psz_path : psz_path, - in->p_stream, p_input->p->p_es_out, + p_stream->psz_path ? p_stream->psz_path : psz_path, + p_stream, p_input->p->p_es_out, p_input->b_preparsing ); if( in->p_demux == NULL ) @@ -2572,6 +2392,7 @@ static int InputSourceInit( input_thread_t *p_input, _("The format of '%s' cannot be detected. " "Have a look at the log for details."), psz_mrl ); } + stream_Delete( p_stream ); goto error; } assert( in->p_demux->pf_demux != NULL ); @@ -2616,8 +2437,8 @@ static int InputSourceInit( input_thread_t *p_input, &attachment, &i_attachment ) ) { vlc_mutex_lock( &p_input->p->p_item->lock ); - AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, - i_attachment, attachment ); + AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, &p_input->p->attachment_demux, + i_attachment, attachment, in->p_demux ); vlc_mutex_unlock( &p_input->p->p_item->lock ); } @@ -2626,12 +2447,7 @@ static int InputSourceInit( input_thread_t *p_input, * fallback to access */ if( demux_Control( in->p_demux, DEMUX_GET_PTS_DELAY, &in->i_pts_delay ) ) - { - /* GET_PTS_DELAY is mandatory for access_demux */ - assert( in->p_access ); - access_Control( in->p_access, - ACCESS_GET_PTS_DELAY, &in->i_pts_delay ); - } + in->i_pts_delay = i_pts_delay; if( in->i_pts_delay > INPUT_PTS_DELAY_MAX ) in->i_pts_delay = INPUT_PTS_DELAY_MAX; else if( in->i_pts_delay < 0 ) @@ -2654,12 +2470,6 @@ error: if( in->p_demux ) demux_Delete( in->p_demux ); - if( in->p_stream ) - stream_Delete( in->p_stream ); - - if( in->p_access ) - access_Delete( in->p_access ); - free( psz_var_demux ); free( psz_dup ); @@ -2676,12 +2486,6 @@ static void InputSourceClean( input_source_t *in ) if( in->p_demux ) demux_Delete( in->p_demux ); - if( in->p_stream ) - stream_Delete( in->p_stream ); - - if( in->p_access ) - access_Delete( in->p_access ); - if( in->i_title > 0 ) { for( i = 0; i < in->i_title; i++ ) @@ -2696,19 +2500,16 @@ static void InputSourceClean( input_source_t *in ) static void InputSourceMeta( input_thread_t *p_input, input_source_t *p_source, vlc_meta_t *p_meta ) { - access_t *p_access = p_source->p_access; demux_t *p_demux = p_source->p_demux; /* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED * is a bad idea */ - bool has_meta; - - /* Read access meta */ - has_meta = p_access && !access_Control( p_access, ACCESS_GET_META, p_meta ); + bool has_meta = false; /* Read demux meta */ - has_meta |= !demux_Control( p_demux, DEMUX_GET_META, p_meta ); + if( !demux_Control( p_demux, DEMUX_GET_META, p_meta ) ) + has_meta = true; bool has_unsupported; if( demux_Control( p_demux, DEMUX_HAS_UNSUPPORTED_META, &has_unsupported ) ) @@ -2720,11 +2521,9 @@ static void InputSourceMeta( input_thread_t *p_input, return; demux_meta_t *p_demux_meta = - vlc_custom_create( p_demux, sizeof( *p_demux_meta ), - VLC_OBJECT_GENERIC, "demux meta" ); + vlc_custom_create( p_demux, sizeof( *p_demux_meta ), "demux meta" ); if( !p_demux_meta ) return; - vlc_object_attach( p_demux_meta, p_demux ); p_demux_meta->p_demux = p_demux; p_demux_meta->p_item = p_input->p->p_item; @@ -2740,8 +2539,8 @@ static void InputSourceMeta( input_thread_t *p_input, if( p_demux_meta->i_attachments > 0 ) { vlc_mutex_lock( &p_input->p->p_item->lock ); - AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, - p_demux_meta->i_attachments, p_demux_meta->attachments ); + AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, &p_input->p->attachment_demux, + p_demux_meta->i_attachments, p_demux_meta->attachments, p_demux); vlc_mutex_unlock( &p_input->p->p_item->lock ); } module_unneed( p_demux, p_id3 ); @@ -2750,12 +2549,11 @@ static void InputSourceMeta( input_thread_t *p_input, } -static void SlaveDemux( input_thread_t *p_input, bool *pb_demux_polled ) +static void SlaveDemux( input_thread_t *p_input ) { int64_t i_time; int i; - *pb_demux_polled = false; if( demux_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) ) { msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" ); @@ -2770,12 +2568,6 @@ static void SlaveDemux( input_thread_t *p_input, bool *pb_demux_polled ) if( in->b_eof ) continue; - const bool b_demux_polled = in->p_demux->pf_demux != NULL; - if( !b_demux_polled ) - continue; - - *pb_demux_polled = true; - /* Call demux_Demux until we have read enough data */ if( demux_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) ) { @@ -2870,33 +2662,77 @@ static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta ) } } -/***************************************************************************** - * InputUpdateMeta: merge p_item meta data with p_meta taking care of - * arturl and locking issue. - *****************************************************************************/ -static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta ) -{ - es_out_ControlSetMeta( p_input->p->p_es_out, p_meta ); - vlc_meta_Delete( p_meta ); -} - -static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment, - int i_new, input_attachment_t **pp_new ) +static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment, demux_t ***ppp_attachment_demux, + int i_new, input_attachment_t **pp_new, demux_t *p_demux ) { int i_attachment = *pi_attachment; input_attachment_t **attachment = *ppp_attachment; + demux_t **attachment_demux = *ppp_attachment_demux; int i; attachment = xrealloc( attachment, - sizeof(input_attachment_t**) * ( i_attachment + i_new ) ); + sizeof(*attachment) * ( i_attachment + i_new ) ); + attachment_demux = xrealloc( attachment_demux, + sizeof(*attachment_demux) * ( i_attachment + i_new ) ); for( i = 0; i < i_new; i++ ) - attachment[i_attachment++] = pp_new[i]; + { + attachment[i_attachment] = pp_new[i]; + attachment_demux[i_attachment++] = p_demux; + } free( pp_new ); /* */ *pi_attachment = i_attachment; *ppp_attachment = attachment; + *ppp_attachment_demux = attachment_demux; +} + +/***************************************************************************** + * InputUpdateMeta: merge p_item meta data with p_meta taking care of + * arturl and locking issue. + *****************************************************************************/ +static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux ) +{ + vlc_meta_t *p_meta = vlc_meta_New(); + if( unlikely(p_meta == NULL) ) + return; + + demux_Control( p_demux, DEMUX_GET_META, p_meta ); + + /* If metadata changed, then the attachments might have changed. + We need to update them in case they contain album art. */ + input_attachment_t **attachment; + int i_attachment; + + if( !demux_Control( p_demux, DEMUX_GET_ATTACHMENTS, + &attachment, &i_attachment ) ) + { + vlc_mutex_lock( &p_input->p->p_item->lock ); + if( p_input->p->i_attachment > 0 ) + { + int j = 0; + for( int i = 0; i < p_input->p->i_attachment; i++ ) + { + if( p_input->p->attachment_demux[i] == p_demux ) + vlc_input_attachment_Delete( p_input->p->attachment[i] ); + else + { + p_input->p->attachment[j] = p_input->p->attachment[i]; + p_input->p->attachment_demux[j] = p_input->p->attachment_demux[i]; + j++; + } + } + p_input->p->i_attachment = j; + } + AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, &p_input->p->attachment_demux, + i_attachment, attachment, p_demux ); + vlc_mutex_unlock( &p_input->p->p_item->lock ); + } + + es_out_ControlSetMeta( p_input->p->p_es_out, p_meta ); + vlc_meta_Delete( p_meta ); } + /***************************************************************************** * InputGetExtraFiles * Autodetect extra input list @@ -2931,14 +2767,18 @@ static void InputGetExtraFilesPattern( input_thread_t *p_input, if( asprintf( &psz_file, psz_format, psz_base, i ) < 0 ) break; - if( vlc_stat( psz_file, &st ) || !S_ISREG( st.st_mode ) || !st.st_size ) + char *psz_tmp_path = get_path( psz_file ); + + if( vlc_stat( psz_tmp_path, &st ) || !S_ISREG( st.st_mode ) || !st.st_size ) { free( psz_file ); + free( psz_tmp_path ); break; } msg_Dbg( p_input, "Detected extra file `%s'", psz_file ); TAB_APPEND( i_list, ppsz_list, psz_file ); + free( psz_tmp_path ); } free( psz_base ); exit: @@ -2959,10 +2799,6 @@ static void InputGetExtraFiles( input_thread_t *p_input, } p_pattern[] = { /* XXX the order is important */ { ".001", "%s.%.3d", 2, 999 }, - { ".part1.rar", "%s.part%.1d.rar",2, 9 }, - { ".part01.rar", "%s.part%.2d.rar",2, 99, }, - { ".part001.rar", "%s.part%.3d.rar",2, 999 }, - { ".rar", "%s.r%.2d", 0, 99 }, { NULL, NULL, 0, 0 } }; @@ -3013,162 +2849,173 @@ static void input_ChangeState( input_thread_t *p_input, int i_state ) * MRLSplit: parse the access, demux and url part of the * Media Resource Locator. *****************************************************************************/ -void input_SplitMRL( const char **ppsz_access, const char **ppsz_demux, - char **ppsz_path, char *psz_dup ) +void input_SplitMRL( const char **access, const char **demux, + const char **path, const char **anchor, char *buf ) { char *p; /* Separate from [/]:// */ - p = strstr( psz_dup, "://" ); + p = strstr( buf, "://" ); if( p != NULL ) { *p = '\0'; p += 3; /* skips "://" */ - *ppsz_path = p; + *path = p; /* Remove HTML anchor if present (not supported). * The hash symbol itself should be URI-encoded. */ p = strchr( p, '#' ); - if( p ) - *p = '\0'; + if( p != NULL ) + { + *(p++) = '\0'; + *anchor = p; + } + else + *anchor = ""; } else { #ifndef NDEBUG fprintf( stderr, "%s(\"%s\") probably not a valid URI!\n", __func__, - psz_dup ); + buf ); #endif /* Note: this is a valid non const pointer to "": */ - *ppsz_path = psz_dup + strlen( psz_dup ); + *path = buf + strlen( buf ); } /* Separate access from demux */ - p = strchr( psz_dup, '/' ); + p = strchr( buf, '/' ); if( p != NULL ) { *(p++) = '\0'; if( p[0] == '$' ) p++; - *ppsz_demux = p; + *demux = p; } else - *ppsz_demux = ""; + *demux = ""; /* We really don't want module name substitution here! */ - p = psz_dup; + p = buf; if( p[0] == '$' ) p++; - *ppsz_access = p; + *access = p; } -static inline bool next(char ** src) +static const char *MRLSeekPoint( const char *str, int *title, int *chapter ) { char *end; - errno = 0; - long result = strtol( *src, &end, 0 ); - if( errno != 0 || result >= LONG_MAX || result <= LONG_MIN || - end == *src ) + unsigned long u; + + /* Look for the title */ + u = strtoul( str, &end, 0 ); + *title = (str == end || u > (unsigned long)INT_MAX) ? -1 : (int)u; + str = end; + + /* Look for the chapter */ + if( *str == ':' ) { - return false; + str++; + u = strtoul( str, &end, 0 ); + *chapter = (str == end || u > (unsigned long)INT_MAX) ? -1 : (int)u; + str = end; } - *src = end; - return true; + else + *chapter = -1; + + return str; } + /***************************************************************************** * MRLSections: parse title and seekpoint info from the Media Resource Locator. * * Syntax: - * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]] + * [url][@[title_start][:chapter_start][-[title_end][:chapter_end]]] *****************************************************************************/ -static void MRLSections( input_thread_t *p_input, char *psz_source, +static void MRLSections( const char *p, int *pi_title_start, int *pi_title_end, int *pi_chapter_start, int *pi_chapter_end ) { - char *psz, *psz_end, *psz_next, *psz_check; + *pi_title_start = *pi_title_end = *pi_chapter_start = *pi_chapter_end = -1; - *pi_title_start = *pi_title_end = -1; - *pi_chapter_start = *pi_chapter_end = -1; + int title_start, chapter_start, title_end, chapter_end; - /* Start by parsing titles and chapters */ - if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return; + if( !p ) + return; + if( *p != '-' ) + p = MRLSeekPoint( p, &title_start, &chapter_start ); + else + title_start = chapter_start = -1; - /* Check we are really dealing with a title/chapter section */ - psz_check = psz + 1; - if( !*psz_check ) return; - if( isdigit(*psz_check) ) - if(!next(&psz_check)) return; - if( *psz_check != ':' && *psz_check != '-' && *psz_check ) return; - if( *psz_check == ':' && ++psz_check ) - { - if( isdigit(*psz_check) ) - if(!next(&psz_check)) return; - } - if( *psz_check != '-' && *psz_check ) return; - if( *psz_check == '-' && ++psz_check ) - { - if( isdigit(*psz_check) ) - if(!next(&psz_check)) return; - } - if( *psz_check != ':' && *psz_check ) return; - if( *psz_check == ':' && ++psz_check ) + if( *p == '-' ) + p = MRLSeekPoint( p + 1, &title_end, &chapter_end ); + else + title_end = chapter_end = -1; + + if( *p ) /* syntax error */ + return; + + *pi_title_start = title_start; + *pi_title_end = title_end; + *pi_chapter_start = chapter_start; + *pi_chapter_end = chapter_end; +} + +/***************************************************************************** + * input_AddSubtitles: add a subtitle file and enable it + *****************************************************************************/ +static void input_SubtitleAdd( input_thread_t *p_input, + const char *url, unsigned i_flags ) +{ + input_source_t *sub = InputSourceNew( p_input ); + if( sub == NULL ) + return; + + vlc_value_t count; + + var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL ); + + if( InputSourceInit( p_input, sub, url, "subtitle", + (i_flags & SUB_CANFAIL) ) ) { - if( isdigit(*psz_check) ) - if(!next(&psz_check)) return; + free( sub ); + return; } - if( *psz_check ) return; + TAB_APPEND( p_input->p->i_slave, p_input->p->slave, sub ); - /* Separate start and end */ - *psz++ = 0; - if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0; + if( !(i_flags & SUB_FORCED) ) + return; - /* Look for the start title */ - *pi_title_start = strtol( psz, &psz_next, 0 ); - if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1; - *pi_title_end = *pi_title_start; - psz = psz_next; + /* Select the ES */ + vlc_value_t list; - /* Look for the start chapter */ - if( *psz ) psz++; - *pi_chapter_start = strtol( psz, &psz_next, 0 ); - if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1; - *pi_chapter_end = *pi_chapter_start; + if( var_Change( p_input, "spu-es", VLC_VAR_GETCHOICES, &list, NULL ) ) + return; + if( count.i_int == 0 ) + count.i_int++; + /* if it was first one, there is disable too */ - if( psz_end ) + if( count.i_int < list.p_list->i_count ) { - /* Look for the end title */ - *pi_title_end = strtol( psz_end, &psz_next, 0 ); - if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1; - psz_end = psz_next; + const int i_id = list.p_list->p_values[count.i_int].i_int; - /* Look for the end chapter */ - if( *psz_end ) psz_end++; - *pi_chapter_end = strtol( psz_end, &psz_next, 0 ); - if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1; + es_out_Control( p_input->p->p_es_out_display, ES_OUT_SET_ES_DEFAULT_BY_ID, i_id ); + es_out_Control( p_input->p->p_es_out_display, ES_OUT_SET_ES_BY_ID, i_id ); } - - msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d", - psz_source, *pi_title_start, *pi_chapter_start, - *pi_title_end, *pi_chapter_end ); + var_FreeList( &list, NULL ); } -/***************************************************************************** - * input_AddSubtitles: add a subtitles file and enable it - *****************************************************************************/ -static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, unsigned i_flags ) +static void input_SubtitleFileAdd( input_thread_t *p_input, char *psz_subtitle, + unsigned i_flags ) { - input_source_t *sub; - vlc_value_t count; - vlc_value_t list; - char *psz_path, *psz_extension; - /* if we are provided a subtitle.sub file, * see if we don't have a subtitle.idx and use it instead */ - psz_path = strdup( psz_subtitle ); - if( psz_path ) + char *psz_path = strdup( psz_subtitle ); + if( likely(psz_path != NULL) ) { - psz_extension = strrchr( psz_path, '.'); + char *psz_extension = strrchr( psz_path, '.'); if( psz_extension && strcmp( psz_extension, ".sub" ) == 0 ) { struct stat st; @@ -3177,45 +3024,20 @@ static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, unsigned i if( !vlc_stat( psz_path, &st ) && S_ISREG( st.st_mode ) ) { - msg_Dbg( p_input, "using %s subtitles file instead of %s", + msg_Dbg( p_input, "using %s as subtitle file instead of %s", psz_path, psz_subtitle ); - strcpy( psz_subtitle, psz_path ); + strcpy( psz_subtitle, psz_path ); /* <- FIXME! constify */ } } free( psz_path ); } - char *url = make_URI( psz_subtitle, "file" ); - - var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL ); - - sub = InputSourceNew( p_input ); - if( !sub || !url - || InputSourceInit( p_input, sub, url, "subtitle", (i_flags & SUB_CANFAIL) ) ) - { - free( sub ); - free( url ); + char *url = vlc_path2uri( psz_subtitle, NULL ); + if( url == NULL ) return; - } - free( url ); - TAB_APPEND( p_input->p->i_slave, p_input->p->slave, sub ); - - /* Select the ES */ - if( (i_flags & SUB_FORCED) && !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list, NULL ) ) - { - if( count.i_int == 0 ) - count.i_int++; - /* if it was first one, there is disable too */ - - if( count.i_int < list.p_list->i_count ) - { - const int i_id = list.p_list->p_values[count.i_int].i_int; - es_out_Control( p_input->p->p_es_out_display, ES_OUT_SET_ES_DEFAULT_BY_ID, i_id ); - es_out_Control( p_input->p->p_es_out_display, ES_OUT_SET_ES_BY_ID, i_id ); - } - var_FreeList( &list, NULL ); - } + input_SubtitleAdd( p_input, url, i_flags ); + free( url ); } /***************************************************************************** @@ -3229,7 +3051,7 @@ void input_UpdateStatistic( input_thread_t *p_input, vlc_mutex_lock( &p_input->p->counters.counters_lock); switch( i_type ) { -#define I(c) stats_UpdateInteger( p_input, p_input->p->counters.c, i_delta, NULL ) +#define I(c) stats_Update( p_input->p->counters.c, i_delta, NULL ) case INPUT_STATISTIC_DECODED_VIDEO: I(p_decoded_video); break; @@ -3245,10 +3067,10 @@ void input_UpdateStatistic( input_thread_t *p_input, #undef I case INPUT_STATISTIC_SENT_BYTE: { - int i_bytes; /* That's pretty stupid to define it as an integer, it will overflow - really fast ... */ - if( !stats_UpdateInteger( p_input, p_input->p->counters.p_sout_sent_bytes, i_delta, &i_bytes ) ) - stats_UpdateFloat( p_input, p_input->p->counters.p_sout_send_bitrate, i_bytes, NULL ); + uint64_t bytes; + + stats_Update( p_input->p->counters.p_sout_sent_bytes, i_delta, &bytes ); + stats_Update( p_input->p->counters.p_sout_send_bitrate, bytes, NULL ); break; } default: @@ -3260,7 +3082,7 @@ void input_UpdateStatistic( input_thread_t *p_input, /**/ /* TODO FIXME nearly the same logic that snapshot code */ -char *input_CreateFilename( vlc_object_t *p_obj, const char *psz_path, const char *psz_prefix, const char *psz_extension ) +char *input_CreateFilename( input_thread_t *input, const char *psz_path, const char *psz_prefix, const char *psz_extension ) { char *psz_file; DIR *path; @@ -3270,7 +3092,7 @@ char *input_CreateFilename( vlc_object_t *p_obj, const char *psz_path, const cha { closedir( path ); - char *psz_tmp = str_format( p_obj, psz_prefix ); + char *psz_tmp = str_format( input, psz_prefix ); if( !psz_tmp ) return NULL; @@ -3286,9 +3108,8 @@ char *input_CreateFilename( vlc_object_t *p_obj, const char *psz_path, const cha } else { - psz_file = str_format( p_obj, psz_path ); + psz_file = str_format( input, psz_path ); path_sanitize( psz_file ); return psz_file; } } -