X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=91371912671f208e8691f7f5f2ba10de30ec5dee;hb=745bd15ffe52fff777d201248b7cbe6b7e92ceca;hp=c40b9f0f306094585ca80e2a366ce77255fe28a6;hpb=51bbf793131496c6f31f70953ff434f17be80d63;p=vlc diff --git a/src/input/input.c b/src/input/input.c index c40b9f0f30..9137191267 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "input_internal.h" #include "event.h" @@ -94,7 +95,7 @@ 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 ); +static void SlaveDemux( input_thread_t *p_input, bool *pb_demux_polled ); static void SlaveSeek( input_thread_t *p_input ); static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta ); @@ -296,7 +297,7 @@ static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj ) 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 || i == VLC_OBJECT_PACKETIZER ) + i == VLC_OBJECT_DECODER ) return; vlc_object_kill( p_obj ); @@ -592,14 +593,15 @@ exit: * MainLoopDemux * It asks the demuxer to demux some data */ -static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, mtime_t *pi_start_mdate ) +static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, bool *pb_demux_polled, 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 && *pi_start_mdate+p_input->p->i_run < mdate() ) ) + ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) ) i_ret = 0; /* EOF */ else i_ret = demux_Demux( p_input->p->input.p_demux ); @@ -629,66 +631,67 @@ static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, mtime_t *p if( i_ret == 0 ) /* EOF */ { - int i_repeat = var_GetInteger( p_input, "input-repeat" ); - if( i_repeat == 0 ) - { - /* End of file - we do not set b_die because only the - * playlist is allowed to do so. */ - msg_Dbg( p_input, "EOF reached" ); - p_input->p->input.b_eof = true; - } - else - { - vlc_value_t val; + msg_Dbg( p_input, "EOF reached" ); + p_input->p->input.b_eof = true; + } + else if( i_ret < 0 ) + { + input_ChangeState( p_input, ERROR_S ); + } - msg_Dbg( p_input, "repeating the same input (%d)", i_repeat ); - if( i_repeat > 0 ) - { - i_repeat--; - var_SetInteger( p_input, "input-repeat", i_repeat ); - } + if( i_ret > 0 && p_input->p->i_slave > 0 ) + { + bool b_demux_polled; + SlaveDemux( p_input, &b_demux_polled ); - /* Seek to start title/seekpoint */ - val.i_int = p_input->p->input.i_title_start - - p_input->p->input.i_title_offset; - if( val.i_int < 0 || val.i_int >= p_input->p->input.i_title ) - val.i_int = 0; - input_ControlPush( p_input, - INPUT_CONTROL_SET_TITLE, &val ); + *pb_demux_polled |= b_demux_polled; + } +} - val.i_int = p_input->p->input.i_seekpoint_start - - p_input->p->input.i_seekpoint_offset; - if( val.i_int > 0 /* TODO: check upper boundary */ ) - input_ControlPush( p_input, - INPUT_CONTROL_SET_SEEKPOINT, &val ); +static int MainLoopTryRepeat( input_thread_t *p_input, mtime_t *pi_start_mdate ) +{ + int i_repeat = var_GetInteger( p_input, "input-repeat" ); + if( i_repeat == 0 ) + return VLC_EGENERIC; - /* Seek to start position */ - if( p_input->p->i_start > 0 ) - { - val.i_time = p_input->p->i_start; - input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, - &val ); - } - else - { - val.f_float = 0.0; - input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, - &val ); - } + vlc_value_t val; - /* */ - *pi_start_mdate = mdate(); - } - } - else if( i_ret < 0 ) + msg_Dbg( p_input, "repeating the same input (%d)", i_repeat ); + if( i_repeat > 0 ) { - input_ChangeState( p_input, ERROR_S ); + i_repeat--; + var_SetInteger( p_input, "input-repeat", i_repeat ); } - if( i_ret > 0 && p_input->p->i_slave > 0 ) + /* Seek to start title/seekpoint */ + val.i_int = p_input->p->input.i_title_start - + p_input->p->input.i_title_offset; + if( val.i_int < 0 || val.i_int >= p_input->p->input.i_title ) + val.i_int = 0; + input_ControlPush( p_input, + INPUT_CONTROL_SET_TITLE, &val ); + + val.i_int = p_input->p->input.i_seekpoint_start - + p_input->p->input.i_seekpoint_offset; + if( val.i_int > 0 /* TODO: check upper boundary */ ) + input_ControlPush( p_input, + INPUT_CONTROL_SET_SEEKPOINT, &val ); + + /* Seek to start position */ + if( p_input->p->i_start > 0 ) { - SlaveDemux( p_input ); + val.i_time = p_input->p->i_start; + input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &val ); } + else + { + val.f_float = 0.0; + input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val ); + } + + /* */ + *pi_start_mdate = mdate(); + return VLC_SUCCESS; } /** @@ -757,6 +760,7 @@ static void MainLoop( input_thread_t *p_input ) mtime_t i_deadline; mtime_t i_wakeup; bool b_paused; + bool b_demux_polled; /* Demux data */ b_force_update = false; @@ -767,11 +771,12 @@ static void MainLoop( input_thread_t *p_input ) b_paused = p_input->p->i_state == PAUSE_S && !es_out_GetBuffering( p_input->p->p_es_out ); + b_demux_polled = true; if( !b_paused ) { if( !p_input->p->input.b_eof ) { - MainLoopDemux( p_input, &b_force_update, &i_start_mdate ); + MainLoopDemux( p_input, &b_force_update, &b_demux_polled, i_start_mdate ); i_wakeup = es_out_GetWakeup( p_input->p->p_es_out ); } @@ -782,14 +787,15 @@ static void MainLoop( input_thread_t *p_input ) } else { - break; + if( MainLoopTryRepeat( p_input, &i_start_mdate ) ) + break; } } /* */ do { i_deadline = i_wakeup; - if( b_paused ) + if( b_paused || !b_demux_polled ) i_deadline = __MIN( i_intf_update, i_statistic_update ); /* Handle control */ @@ -817,13 +823,9 @@ static void MainLoop( input_thread_t *p_input ) i_statistic_update = i_current + INT64_C(1000000); } - /* Check if i_wakeup is still valid */ + /* Update the wakeup time */ if( i_wakeup != 0 ) - { - mtime_t i_new_wakeup = es_out_GetWakeup( p_input->p->p_es_out ); - if( !i_new_wakeup ) - i_wakeup = 0; - } + i_wakeup = es_out_GetWakeup( p_input->p->p_es_out ); } while( i_current < i_wakeup ); } @@ -956,23 +958,15 @@ static void StartTitle( input_thread_t * p_input ) p_input->p->i_run = 0; } - const mtime_t i_length = var_GetTime( p_input, "length" ); if( p_input->p->i_start > 0 ) { - if( p_input->p->i_start >= i_length ) - { - msg_Warn( p_input, "invalid start-time ignored" ); - } - else - { - vlc_value_t s; + vlc_value_t s; - msg_Dbg( p_input, "starting at time: %ds", - (int)( p_input->p->i_start / INT64_C(1000000) ) ); + msg_Dbg( p_input, "starting at time: %ds", + (int)( p_input->p->i_start / INT64_C(1000000) ) ); - s.i_time = p_input->p->i_start; - input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s ); - } + s.i_time = p_input->p->i_start; + input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s ); } if( p_input->p->i_stop > 0 && p_input->p->i_stop <= p_input->p->i_start ) { @@ -1138,7 +1132,6 @@ static void InitPrograms( input_thread_t * p_input ) { demux_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, -1, val.p_list ); - var_FreeList( &val, NULL ); } else { @@ -1546,24 +1539,22 @@ static void ControlPause( input_thread_t *p_input, mtime_t i_control_date ) if( i_ret ) { msg_Warn( p_input, "cannot set pause state" ); - i_state = p_input->p->i_state; + return; } } /* */ - if( !i_ret ) + i_ret = es_out_SetPauseState( p_input->p->p_es_out, + p_input->p->b_can_pause, true, + i_control_date ); + if( i_ret ) { - i_ret = es_out_SetPauseState( p_input->p->p_es_out, p_input->p->b_can_pause, true, i_control_date ); - if( i_ret ) - { - msg_Warn( p_input, "cannot set pause state at es_out level" ); - i_state = p_input->p->i_state; - } + msg_Warn( p_input, "cannot set pause state at es_out level" ); + return; } /* Switch to new state */ input_ChangeState( p_input, i_state ); - } static void ControlUnpause( input_thread_t *p_input, mtime_t i_control_date ) @@ -1679,9 +1670,8 @@ static bool Control( input_thread_t *p_input, int64_t i_length; /* Emulate it with a SET_POS */ - demux_Control( p_input->p->input.p_demux, - DEMUX_GET_LENGTH, &i_length ); - if( i_length > 0 ) + if( !demux_Control( p_input->p->input.p_demux, + DEMUX_GET_LENGTH, &i_length ) && i_length > 0 ) { double f_pos = (double)i_time / (double)i_length; i_ret = demux_Control( p_input->p->input.p_demux, @@ -1706,8 +1696,9 @@ static bool Control( input_thread_t *p_input, } case INPUT_CONTROL_SET_STATE: - if( ( val.i_int == PLAYING_S && p_input->p->i_state == PAUSE_S ) || - ( val.i_int == PAUSE_S && p_input->p->i_state == PAUSE_S ) ) + if( val.i_int != PLAYING_S && val.i_int != PAUSE_S ) + msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" ); + else if( p_input->p->i_state == PAUSE_S ) { ControlUnpause( p_input, i_control_date ); @@ -1727,10 +1718,6 @@ static bool Control( input_thread_t *p_input, /* Correct "state" value */ input_ChangeState( p_input, p_input->p->i_state ); } - else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S ) - { - msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" ); - } break; case INPUT_CONTROL_SET_RATE: @@ -2337,8 +2324,10 @@ static int InputSourceInit( input_thread_t *p_input, const char *psz_access; const char *psz_demux; char *psz_path; + char *psz_var_demux = NULL; double f_fps; + assert( psz_mrl ); char *psz_dup = strdup( psz_mrl ); if( psz_dup == NULL ) @@ -2347,6 +2336,46 @@ static int InputSourceInit( input_thread_t *p_input, /* Split uri */ input_SplitMRL( &psz_access, &psz_demux, &psz_path, psz_dup ); + /* FIXME: file:// handling plugins do not support URIs properly... + * So we pre-decoded the URI to a path for them. Note that we do not do it + * for non-standard VLC-specific schemes. */ + if( !strcmp( psz_access, "file" ) ) + { + if( psz_path[0] != '/' +#if (DIR_SEP_CHAR != '/') + /* We accept invalid URIs too. */ + && psz_path[0] != DIR_SEP_CHAR +#endif + ) + { /* host specified -> only localhost is supported */ + static const size_t i_localhost = sizeof("localhost")-1; + if( strncmp( psz_path, "localhost/", i_localhost + 1) != 0 ) + { + msg_Err( p_input, "cannot open remote file `%s://%s'", + psz_access, psz_path ); + msg_Info( p_input, "Did you mean `%s:///%s'?", + psz_access, psz_path ); + goto error; + } + psz_path += i_localhost; + } + /* Remove HTML anchor if present (not supported). */ + char *p = strchr( psz_path, '#' ); + if( p ) + *p = '\0'; + /* Then URI-decode the path. */ + decode_URI( psz_path ); +#if defined( WIN32 ) && !defined( UNDER_CE ) + /* Strip leading slash in front of the drive letter */ + psz_path++; +#endif +#if (DIR_SEP_CHAR != '/') + /* Turn slashes into anti-slashes */ + for( char *s = strchr( psz_path, '/' ); s; s = strchr( s + 1, '/' ) ) + *s = DIR_SEP_CHAR; +#endif + } + 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 ) @@ -2369,7 +2398,7 @@ static int InputSourceInit( input_thread_t *p_input, { /* special hack for forcing a demuxer with --demux=module * (and do nothing with a list) */ - char *psz_var_demux = var_GetNonEmptyString( p_input, "demux" ); + psz_var_demux = var_GetNonEmptyString( p_input, "demux" ); if( psz_var_demux != NULL && !strchr(psz_var_demux, ',' ) && @@ -2382,7 +2411,7 @@ static int InputSourceInit( input_thread_t *p_input, } /* Try access_demux first */ - in->p_demux = demux_New( p_input, psz_access, psz_demux, psz_path, + in->p_demux = demux_New( p_input, p_input, psz_access, psz_demux, psz_path, NULL, p_input->p->p_es_out, false ); } else @@ -2400,8 +2429,9 @@ static int InputSourceInit( input_thread_t *p_input, if( in->p_demux ) { /* Get infos from access_demux */ - demux_Control( in->p_demux, - DEMUX_GET_PTS_DELAY, &in->i_pts_delay ); + int i_ret = demux_Control( in->p_demux, + DEMUX_GET_PTS_DELAY, &in->i_pts_delay ); + assert( !i_ret ); in->i_pts_delay = __MAX( 0, __MIN( in->i_pts_delay, INPUT_PTS_DELAY_MAX ) ); @@ -2416,6 +2446,8 @@ static int InputSourceInit( input_thread_t *p_input, &in->b_can_pace_control ) ) in->b_can_pace_control = false; + assert( in->p_demux->pf_demux != NULL || !in->b_can_pace_control ); + if( !in->b_can_pace_control ) { if( demux_Control( in->p_demux, DEMUX_CAN_CONTROL_RATE, @@ -2445,26 +2477,17 @@ static int InputSourceInit( input_thread_t *p_input, else { /* Now try a real access */ - in->p_access = access_New( p_input, psz_access, psz_demux, psz_path ); - - /* Access failed, URL encoded ? */ - if( in->p_access == NULL && strchr( psz_path, '%' ) ) - { - decode_URI( psz_path ); - - msg_Dbg( p_input, "retrying with access `%s' demux `%s' path `%s'", - psz_access, psz_demux, psz_path ); - - in->p_access = access_New( p_input, - psz_access, psz_demux, psz_path ); - } + in->p_access = access_New( p_input, p_input, psz_access, psz_demux, psz_path ); if( in->p_access == NULL ) { - msg_Err( p_input, "open of `%s' failed: %s", psz_mrl, - msg_StackMsg() ); - dialog_Fatal( p_input, _("Your input can't be opened"), - _("VLC is unable to open the MRL '%s'." - " Check the log for details."), psz_mrl ); + if( vlc_object_alive( p_input ) ) + { + msg_Err( p_input, "open of `%s' failed: %s", psz_mrl, + msg_StackMsg() ); + dialog_Fatal( p_input, _("Your input can't be opened"), + _("VLC is unable to open the MRL '%s'." + " Check the log for details."), psz_mrl ); + } goto error; } @@ -2582,7 +2605,7 @@ static int InputSourceInit( input_thread_t *p_input, { psz_real_path = psz_path; } - in->p_demux = demux_New( p_input, psz_access, psz_demux, + in->p_demux = demux_New( p_input, p_input, psz_access, psz_demux, psz_real_path, in->p_stream, p_input->p->p_es_out, p_input->b_preparsing ); @@ -2591,14 +2614,18 @@ static int InputSourceInit( input_thread_t *p_input, if( in->p_demux == NULL ) { - msg_Err( p_input, "no suitable demux module for `%s/%s://%s'", - psz_access, psz_demux, psz_path ); - dialog_Fatal( VLC_OBJECT( p_input ), - _("VLC can't recognize the input's format"), - _("The format of '%s' cannot be detected. " - "Have a look at the log for details."), psz_mrl ); + if( vlc_object_alive( p_input ) ) + { + msg_Err( p_input, "no suitable demux module for `%s/%s://%s'", + psz_access, psz_demux, psz_path ); + dialog_Fatal( VLC_OBJECT( p_input ), + _("VLC can't recognize the input's format"), + _("The format of '%s' cannot be detected. " + "Have a look at the log for details."), psz_mrl ); + } goto error; } + assert( in->p_demux->pf_demux != NULL ); /* Get title from demux */ if( !p_input->b_preparsing && in->i_title <= 0 ) @@ -2616,6 +2643,7 @@ static int InputSourceInit( input_thread_t *p_input, } } + free( psz_var_demux ); free( psz_dup ); /* Set record capabilities */ @@ -2665,6 +2693,8 @@ error: if( in->p_access ) access_Delete( in->p_access ); + + free( psz_var_demux ); free( psz_dup ); return VLC_EGENERIC; @@ -2720,11 +2750,14 @@ static void InputSourceMeta( input_thread_t *p_input, if( !b_bool ) return; - demux_meta_t *p_demux_meta = p_demux->p_private = calloc( 1, sizeof(*p_demux_meta) ); + demux_meta_t *p_demux_meta = + vlc_custom_create( p_demux, sizeof( *p_demux_meta ), + VLC_OBJECT_GENERIC, "demux meta" ); if( !p_demux_meta ) return; + p_demux_meta->p_demux = p_demux; - module_t *p_id3 = module_need( p_demux, "meta reader", NULL, false ); + module_t *p_id3 = module_need( p_demux_meta, "meta reader", NULL, false ); if( p_id3 ) { if( p_demux_meta->p_meta ) @@ -2742,15 +2775,16 @@ static void InputSourceMeta( input_thread_t *p_input, } module_unneed( p_demux, p_id3 ); } - free( p_demux_meta ); + vlc_object_release( p_demux_meta ); } -static void SlaveDemux( input_thread_t *p_input ) +static void SlaveDemux( input_thread_t *p_input, bool *pb_demux_polled ) { 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" ); @@ -2760,11 +2794,18 @@ static void SlaveDemux( input_thread_t *p_input ) for( i = 0; i < p_input->p->i_slave; i++ ) { input_source_t *in = p_input->p->slave[i]; - int i_ret = 1; + int i_ret; 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 ) ) { for( ;; ) @@ -2779,7 +2820,10 @@ static void SlaveDemux( input_thread_t *p_input ) } if( i_stime >= i_time ) + { + i_ret = 1; break; + } if( ( i_ret = demux_Demux( in->p_demux ) ) <= 0 ) break; @@ -2861,54 +2905,8 @@ 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 ) { - input_item_t *p_item = p_input->p->p_item; - - char *psz_title = NULL; - char *psz_arturl = input_item_GetArtURL( p_item ); - - vlc_mutex_lock( &p_item->lock ); - - if( vlc_meta_Get( p_meta, vlc_meta_Title ) && !p_item->b_fixed_name ) - psz_title = strdup( vlc_meta_Get( p_meta, vlc_meta_Title ) ); - - vlc_meta_Merge( p_item->p_meta, p_meta ); - + es_out_ControlSetMeta( p_input->p->p_es_out, p_meta ); vlc_meta_Delete( p_meta ); - - if( !psz_arturl || *psz_arturl == '\0' ) - { - const char *psz_tmp = vlc_meta_Get( p_item->p_meta, vlc_meta_ArtworkURL ); - if( psz_tmp ) - psz_arturl = strdup( psz_tmp ); - } - vlc_mutex_unlock( &p_item->lock ); - - if( psz_arturl && *psz_arturl ) - { - input_item_SetArtURL( p_item, psz_arturl ); - - if( !strncmp( psz_arturl, "attachment://", strlen("attachment") ) ) - { - /* Don't look for art cover if sout - * XXX It can change when sout has meta data support */ - if( p_input->p->p_sout && !p_input->b_preparsing ) - input_item_SetArtURL( p_item, "" ); - else - input_ExtractAttachmentAndCacheArt( p_input ); - } - } - free( psz_arturl ); - - if( psz_title ) - { - input_item_SetName( p_item, psz_title ); - free( psz_title ); - } - input_item_SetPreparsed( p_item, true ); - - input_SendEventMeta( p_input ); - - /** \todo handle sout meta */ } static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment, @@ -2993,7 +2991,7 @@ static void InputGetExtraFiles( input_thread_t *p_input, { ".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", 1, 99 }, + { ".rar", "%s.r%.2d", 0, 99 }, { NULL, NULL, 0, 0 } };