X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=23ee04166f12a551ec49c4931d7cc92e797500e7;hb=4455e6d2935a498e02ac3c6ac144f0525d2e01f0;hp=afc01ad67d3dc064124f681d391092fb66785722;hpb=2ee43275e3dfe528f9bc41f8520ba218487d0588;p=vlc diff --git a/src/input/input.c b/src/input/input.c index afc01ad67d..23ee04166f 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "input_internal.h" @@ -47,15 +48,12 @@ #include "resource.h" #include -#include "../stream_output/stream_output.h" - #include #include #include #include #include #include -#include // FIXME /***************************************************************************** * Local prototypes @@ -70,18 +68,14 @@ 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( const char *, int *, int *, int *, int *); @@ -94,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 @@ -197,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 ); @@ -229,24 +236,14 @@ 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) ); - - vlc_mutex_lock( &p_input->p->lock_control ); - p_input->p->b_abort |= b_abort; - vlc_mutex_unlock( &p_input->p->lock_control ); - + ObjectKillChildrens( VLC_OBJECT(p_input) ); input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL ); } @@ -284,25 +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; - - /* FIXME ObjectKillChildrens seems a very bad idea in fact */ - if( p_obj == VLC_OBJECT(p_input->p->p_sout) ) - return; - - vlc_object_kill( p_obj ); - - p_list = vlc_list_children( p_obj ); - for( int 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. @@ -333,7 +311,10 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, 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 ); @@ -362,6 +343,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, 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; @@ -369,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; @@ -385,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 */ @@ -408,7 +408,6 @@ 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 */ @@ -453,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; } @@ -470,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 ); /* */ @@ -537,22 +537,14 @@ static void *Run( void *obj ) 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 ); @@ -567,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() ) ) @@ -584,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 ); @@ -591,16 +587,6 @@ 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 */ @@ -615,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 ) @@ -660,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 ); } @@ -670,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; @@ -698,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 ); } @@ -721,37 +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" ); 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 ) ) { @@ -762,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; @@ -774,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 ) @@ -952,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 ) { @@ -969,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 ); @@ -986,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| @@ -1014,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; } @@ -1030,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; } @@ -1068,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 ); @@ -1158,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; @@ -1182,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 ); @@ -1205,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 ) ) { @@ -1286,8 +1238,8 @@ static int Init( input_thread_t * p_input ) 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 ); @@ -1299,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", @@ -1358,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; @@ -1437,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 ); @@ -1533,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 ); } /* */ @@ -1575,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; @@ -1603,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 ) { @@ -1637,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 ? */ @@ -1675,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 { @@ -1725,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; @@ -1835,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 ); @@ -1883,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: @@ -1903,141 +1861,78 @@ 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: @@ -2048,7 +1943,6 @@ static bool Control( input_thread_t *p_input, if( slave && !InputSourceInit( p_input, slave, uri, NULL, false ) ) { - vlc_meta_t *p_meta; int64_t i_time; /* Add the slave */ @@ -2073,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 ); } @@ -2131,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 && (uint64_t)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; @@ -2243,91 +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; } - if( p_demux->info.i_update & INPUT_UPDATE_SIGNAL ) { double quality; double strength; - if( demux_Control( p_demux, DEMUX_GET_SIGNAL, &quality, &strength ) ) - quality = strength = -1.; - - input_SendEventSignal( p_input, quality, strength ); - - p_demux->info.i_update &= ~INPUT_UPDATE_SIGNAL; + if( !demux_Control( p_demux, DEMUX_GET_SIGNAL, &quality, &strength ) ) + input_SendEventSignal( p_input, quality, strength ); } - - p_demux->info.i_update &= ~INPUT_UPDATE_SIZE; } - -/***************************************************************************** - * Update*FromAccess: - *****************************************************************************/ -static int UpdateTitleSeekpointFromAccess( input_thread_t *p_input ) +static void UpdateTitleListfromDemux( 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 ); + input_source_t *in = &p_input->p->input; - stream_Control( p_input->p->input.p_stream, STREAM_UPDATE_SIZE ); - - p_access->info.i_update &= ~INPUT_UPDATE_TITLE; - } - 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 ) -{ - access_t *p_access = p_input->p->input.p_access; - - 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: *****************************************************************************/ @@ -2374,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 */ @@ -2442,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 ) ) { @@ -2458,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; @@ -2527,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++ ) @@ -2535,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; @@ -2544,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 ) @@ -2573,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 ); @@ -2617,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 ); } @@ -2627,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 ) @@ -2655,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 ); @@ -2677,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++ ) @@ -2697,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 ) ) @@ -2739,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 ); @@ -2749,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" ); @@ -2769,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 ) ) { @@ -2869,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 @@ -2930,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: @@ -3123,21 +2964,58 @@ static void MRLSections( const char *p, } /***************************************************************************** - * input_AddSubtitles: add a subtitles file and enable it + * input_AddSubtitles: add a subtitle file and enable it *****************************************************************************/ -static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, unsigned i_flags ) +static void input_SubtitleAdd( input_thread_t *p_input, + const char *url, unsigned i_flags ) { - input_source_t *sub; + 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) ) ) + { + free( sub ); + return; + } + TAB_APPEND( p_input->p->i_slave, p_input->p->slave, sub ); + + if( !(i_flags & SUB_FORCED) ) + return; + + /* Select the ES */ vlc_value_t list; - char *psz_path, *psz_extension; + 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( 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 ); +} + +static void input_SubtitleFileAdd( input_thread_t *p_input, char *psz_subtitle, + unsigned i_flags ) +{ /* 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; @@ -3146,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 = vlc_path2uri( psz_subtitle, NULL ); - - 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 ); + 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 +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; @@ -3239,7 +3092,7 @@ char *input_CreateFilename( vlc_object_t *p_obj, const char *psz_path, const cha { closedir( path ); - char *psz_tmp = str_format( pl_Get(p_obj), psz_prefix ); + char *psz_tmp = str_format( input, psz_prefix ); if( !psz_tmp ) return NULL; @@ -3255,9 +3108,8 @@ char *input_CreateFilename( vlc_object_t *p_obj, const char *psz_path, const cha } else { - psz_file = str_format( pl_Get(p_obj), psz_path ); + psz_file = str_format( input, psz_path ); path_sanitize( psz_file ); return psz_file; } } -