X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Finput%2Finput.c;h=dbe4a668c104043621fadf8816ac42c50bbba4ac;hb=9fc1c6d158fdc6bd7691f79396a7bd5e22805705;hp=0c7bb67ea95a182f549e47e8b5783ee4aa8b90f0;hpb=9e8d440d94c73aa546b51cb0bf0536e143a4f660;p=vlc diff --git a/src/input/input.c b/src/input/input.c index 0c7bb67ea9..dbe4a668c1 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -25,10 +25,15 @@ /***************************************************************************** * Preamble *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include #include #include +#include #include "input_internal.h" @@ -48,6 +53,8 @@ /***************************************************************************** * Local prototypes *****************************************************************************/ +static void Destructor( input_thread_t * p_input ); + static int Run ( input_thread_t *p_input ); static int RunAndDestroy ( input_thread_t *p_input ); @@ -57,7 +64,6 @@ static int Init ( input_thread_t *p_input ); static void Error ( input_thread_t *p_input ); static void End ( input_thread_t *p_input ); static void MainLoop( input_thread_t *p_input ); -static void Destroy( input_thread_t *p_input, sout_instance_t **pp_sout ); static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * ); static void ControlReduce( input_thread_t * ); @@ -108,8 +114,10 @@ static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_atta * - length * - bookmarks * - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0) + * - can-pause * * For intf callback upon changes * - intf-change + * - rate-change for when playback rate changes * TODO explain when Callback is called * TODO complete this list (?) *****************************************************************************/ @@ -160,6 +168,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, TAB_INIT( p_input->p->i_attachment, p_input->p->attachment ); p_input->p->p_es_out = NULL; p_input->p->p_sout = NULL; + p_input->p->b_owns_its_sout = VLC_TRUE; p_input->p->b_sout_keep = VLC_FALSE; p_input->p->b_out_pace_control = VLC_FALSE; p_input->i_pts_delay = 0; @@ -174,6 +183,8 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, p_input->p->input.title = NULL; p_input->p->input.i_title_offset = p_input->p->input.i_seekpoint_offset = 0; p_input->p->input.b_can_pace_control = VLC_TRUE; + p_input->p->input.b_can_rate_control = VLC_TRUE; + p_input->p->input.b_rescale_ts = VLC_TRUE; p_input->p->input.b_eof = VLC_FALSE; p_input->p->input.i_cr_average = 0; @@ -193,8 +204,10 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, /* Parse input options */ vlc_mutex_lock( &p_item->lock ); + assert( p_item->optflagc == p_item->i_options ); for( i = 0; i < p_item->i_options; i++ ) - var_OptionParse( p_input, p_item->ppsz_options[i] ); + var_OptionParse( VLC_OBJECT(p_input), p_item->ppsz_options[i], + !!(p_item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED) ); vlc_mutex_unlock( &p_item->lock ); /* Create Object Variables for private use only */ @@ -265,32 +278,40 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, /* */ if( p_sout ) + { p_input->p->p_sout = p_sout; + p_input->p->b_owns_its_sout = VLC_FALSE; + } + + memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) ); + vlc_mutex_init( p_input, &p_input->p->counters.counters_lock ); /* Attach only once we are ready */ vlc_object_attach( p_input, p_parent ); + /* Set the destructor when we are sure we are initialized */ + vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor ); + return p_input; } -static void Destroy( input_thread_t *p_input, sout_instance_t **pp_sout ) +/** + * Input destructor (called when the object's refcount reaches 0). + */ +static void Destructor( input_thread_t * p_input ) { - vlc_object_detach( p_input ); input_thread_private_t *priv = p_input->p; - if( pp_sout ) - *pp_sout = NULL; - if( priv->p_sout ) + if( priv->b_owns_its_sout && priv->p_sout ) { - if( pp_sout ) - *pp_sout = priv->p_sout; - else if( priv->b_sout_keep ) + if( priv->b_sout_keep ) SoutKeep( priv->p_sout ); else sout_DeleteInstance( priv->p_sout ); } - vlc_object_destroy( p_input ); + vlc_mutex_destroy( &p_input->p->counters.counters_lock ); + vlc_mutex_destroy( &priv->lock_control ); free( priv ); } @@ -334,7 +355,8 @@ input_thread_t *__input_CreateThreadExtended( vlc_object_t *p_parent, { input_ChangeState( p_input, ERROR_S ); msg_Err( p_input, "cannot create input thread" ); - Destroy( p_input, &p_sout ); + vlc_object_detach( p_input ); + vlc_object_release( p_input ); return NULL; } @@ -377,7 +399,7 @@ int __input_Read( vlc_object_t *p_parent, input_item_t *p_item, { input_ChangeState( p_input, ERROR_S ); msg_Err( p_input, "cannot create input thread" ); - Destroy( p_input, NULL ); + vlc_object_release( p_input ); return VLC_EGENERIC; } } @@ -404,7 +426,8 @@ int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item ) if( !Init( p_input ) ) End( p_input ); - Destroy( p_input, NULL ); + vlc_object_detach( p_input ); + vlc_object_release( p_input ); return VLC_SUCCESS; } @@ -453,24 +476,10 @@ void input_StopThread( input_thread_t *p_input ) input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL ); } -/** - * Clean up a dead input thread - * This function does not return until the thread is effectively cancelled. - * - * \param the input thread to kill - */ -void input_DestroyThread( input_thread_t *p_input ) +sout_instance_t * input_DetachSout( input_thread_t *p_input ) { - input_DestroyThreadExtended( p_input, NULL ); -} - -void input_DestroyThreadExtended( input_thread_t *p_input, sout_instance_t **pp_sout ) -{ - /* Join the thread */ - vlc_thread_join( p_input ); - - /* */ - Destroy( p_input, pp_sout ); + p_input->p->b_owns_its_sout = VLC_FALSE; + return p_input->p->p_sout; } /***************************************************************************** @@ -566,7 +575,7 @@ static int RunAndDestroy( input_thread_t *p_input ) exit: /* Release memory */ - Destroy( p_input, NULL ); + vlc_object_release( p_input ); return 0; } @@ -755,16 +764,6 @@ static int Init( input_thread_t * p_input ) int i_es_out_mode; int i, i_delay; - /* Initialize optional stream output. (before access/demuxer) - * XXX: we add a special case if the uri starts by vlc. - * else 'vlc in.file --sout "" vlc:quit' cannot work (the output will - * be destroyed in case of a file). - * (this will break playing of file starting by 'vlc:' but I don't - * want to add more logic, just force file by file:// or code it ;) - */ - memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) ); - vlc_mutex_init( p_input, &p_input->p->counters.counters_lock ); - for( i = 0; i < p_input->p->input.p_item->i_options; i++ ) { if( !strncmp( p_input->p->input.p_item->ppsz_options[i], "meta-file", 9 ) ) @@ -835,7 +834,6 @@ static int Init( input_thread_t * p_input ) { /* Create a new one */ p_input->p->p_sout = sout_NewInstance( p_input, psz ); - if( !p_input->p->p_sout ) { input_ChangeState( p_input, ERROR_S ); @@ -867,7 +865,7 @@ static int Init( input_thread_t * p_input ) } /* Create es out */ - p_input->p->p_es_out = input_EsOutNew( p_input ); + p_input->p->p_es_out = input_EsOutNew( p_input, p_input->p->i_rate ); es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE ); es_out_Control( p_input->p->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE ); @@ -897,6 +895,7 @@ static int Init( input_thread_t * p_input ) /* Global flag */ p_input->b_can_pace_control = p_input->p->input.b_can_pace_control; p_input->p->b_can_pause = p_input->p->input.b_can_pause; + p_input->p->b_can_rate_control = p_input->p->input.b_can_rate_control; /* Fix pts delay */ if( p_input->i_pts_delay < 0 ) @@ -1044,8 +1043,8 @@ static int Init( input_thread_t * p_input ) } free( subs[i] ); } - if( subs ) free( subs ); - if( psz_autopath ) free( psz_autopath ); + free( subs ); + free( psz_autopath ); } free( psz_subtitle ); @@ -1253,10 +1252,10 @@ error: *****************************************************************************/ static void Error( input_thread_t *p_input ) { + input_ChangeState( p_input, ERROR_S ); while( !p_input->b_die ) { /* Sleep a while */ - input_ChangeState( p_input, ERROR_S ); msleep( INPUT_IDLE_SLEEP ); } } @@ -1283,7 +1282,7 @@ static void End( input_thread_t * p_input ) InputSourceClean( p_input->p->slave[i] ); free( p_input->p->slave[i] ); } - if( p_input->p->slave ) free( p_input->p->slave ); + free( p_input->p->slave ); /* Unload all modules */ if( p_input->p->p_es_out ) @@ -1335,8 +1334,6 @@ static void End( input_thread_t * p_input ) TAB_CLEAN( p_input->p->i_attachment, p_input->p->attachment ); } - vlc_mutex_destroy( &p_input->p->counters.counters_lock ); - /* Tell we're dead */ p_input->b_dead = VLC_TRUE; } @@ -1733,20 +1730,40 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, i_rate = INPUT_RATE_MAX; } if( i_rate != INPUT_RATE_DEFAULT && - ( !p_input->b_can_pace_control || + ( ( !p_input->b_can_pace_control && !p_input->p->b_can_rate_control ) || ( p_input->p->p_sout && !p_input->p->b_out_pace_control ) ) ) { msg_Dbg( p_input, "cannot change rate" ); i_rate = INPUT_RATE_DEFAULT; } + if( i_rate != p_input->p->i_rate && + !p_input->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 + i_ret = demux2_Control( p_input->p->input.p_demux, + DEMUX_SET_RATE, &i_rate ); + if( i_ret ) + { + msg_Warn( p_input, "ACCESS/DEMUX_SET_RATE failed" ); + i_rate = p_input->p->i_rate; + } + } + + /* */ if( i_rate != p_input->p->i_rate ) { val.i_int = i_rate; var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL ); + var_SetBool( p_input, "rate-change", VLC_TRUE ); p_input->p->i_rate = i_rate; - input_EsOutChangeRate( p_input->p->p_es_out ); + /* FIXME do we need a RESET_PCR when !p_input->p->input.b_rescale_ts ? */ + if( p_input->p->input.b_rescale_ts ) + input_EsOutChangeRate( p_input->p->p_es_out, i_rate ); b_force_update = VLC_TRUE; } @@ -2096,7 +2113,7 @@ static void UpdateItemLength( input_thread_t *p_input, int64_t i_length ) pl_Yield( p_input ); var_SetInteger( pl_Get( p_input ), "item-change", p_input->p->input.p_item->i_id ); - pl_Release( p_input ) + pl_Release( p_input ); } } @@ -2119,7 +2136,10 @@ static input_source_t *InputSourceNew( input_thread_t *p_input ) in->p_demux = NULL; in->b_title_demux = VLC_FALSE; TAB_INIT( in->i_title, in->title ); + in->b_can_pause = VLC_TRUE; in->b_can_pace_control = VLC_TRUE; + in->b_can_rate_control = VLC_TRUE; + in->b_rescale_ts = VLC_TRUE; in->b_eof = VLC_FALSE; in->f_fps = 0.0; in->i_cr_average = 0; @@ -2149,28 +2169,27 @@ static int InputSourceInit( input_thread_t *p_input, if( !p_input ) return VLC_EGENERIC; /* Split uri */ + MRLSplit( psz_dup, &psz_access, &psz_demux, &psz_path ); + + 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 ) { - MRLSplit( VLC_OBJECT(p_input), psz_dup, - &psz_access, &psz_demux, &psz_path ); - - msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'", - psz_mrl, psz_access, psz_demux, psz_path ); - /* 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( p_input, psz_path, &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; } - else if( !psz_demux || *psz_demux == '\0' ) + else if( *psz_demux == '\0' ) { /* special hack for forcing a demuxer with --demux=module * (and do nothing with a list) */ @@ -2189,19 +2208,20 @@ static int InputSourceInit( input_thread_t *p_input, /* Try access_demux if no demux given */ if( *psz_demux == '\0' ) { - printf("******** psz_path = %s", psz_path); in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path, NULL, p_input->p->p_es_out, VLC_FALSE ); } } else { - psz_path = psz_dup; - if( !strncmp( psz_path, "file://", 7 ) ) - psz_path += 7; + /* Preparsing is only for file:// */ + if( *psz_demux ) + goto error; + if( !*psz_access ) /* path without scheme:// */ + psz_access = "file"; + if( strcmp( psz_access, "file" ) ) + goto error; msg_Dbg( p_input, "trying to pre-parse %s", psz_path ); - psz_demux = ""; - psz_access = "file"; } if( in->p_demux ) @@ -2221,15 +2241,34 @@ static int InputSourceInit( input_thread_t *p_input, in->i_title = 0; in->title = NULL; } - demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE, - &in->b_can_pace_control ); - demux2_Control( in->p_demux, DEMUX_CAN_PAUSE, - &in->b_can_pause ); + if( demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE, + &in->b_can_pace_control ) ) + in->b_can_pace_control = VLC_FALSE; + + if( !in->b_can_pace_control ) + { + if( demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_RATE, + &in->b_can_rate_control, &in->b_rescale_ts ) ) + { + in->b_can_rate_control = VLC_FALSE; + in->b_rescale_ts = VLC_TRUE; /* not used */ + } + } + else + { + in->b_can_rate_control = VLC_TRUE; + in->b_rescale_ts = VLC_TRUE; + } + if( demux2_Control( in->p_demux, DEMUX_CAN_PAUSE, + &in->b_can_pause ) ) + in->b_can_pause = VLC_FALSE; + var_SetBool( p_input, "can-pause", in->b_can_pause ); - /* FIXME todo - demux2_Control( in->p_demux, DEMUX_CAN_SEEK, + int ret = demux2_Control( in->p_demux, DEMUX_CAN_SEEK, &val.b_bool ); - */ + if( ret != VLC_SUCCESS ) + val.b_bool = VLC_FALSE; + var_Set( p_input, "seekable", val ); } else { @@ -2238,8 +2277,7 @@ static int InputSourceInit( input_thread_t *p_input, input_ChangeState( p_input, OPENING_S ); /* Now try a real access */ - in->p_access = access2_New( p_input, psz_access, psz_demux, psz_path, - p_input->b_preparsing ); + in->p_access = access2_New( p_input, psz_access, psz_demux, psz_path ); /* Access failed, URL encoded ? */ if( in->p_access == NULL && strchr( psz_path, '%' ) ) @@ -2250,20 +2288,7 @@ static int InputSourceInit( input_thread_t *p_input, psz_access, psz_demux, psz_path ); in->p_access = access2_New( p_input, - psz_access, psz_demux, psz_path, - p_input->b_preparsing ); - } - /* access failed, maybe our access detection was wrong. - * Retry with the full name */ - if( in->p_access == NULL && strchr( psz_mrl, ':' ) ) - { - msg_Dbg( p_input, "retrying with access `' demux `' path `%s'", - psz_mrl ); - psz_demux = "" ; - psz_path = psz_mrl; - in->p_access = access2_New( p_input, - "", "", psz_mrl, - p_input->b_preparsing ); + psz_access, psz_demux, psz_path ); } if( in->p_access == NULL ) { @@ -2316,8 +2341,12 @@ static int InputSourceInit( input_thread_t *p_input, } access2_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 = VLC_TRUE; + access2_Control( in->p_access, ACCESS_CAN_PAUSE, &in->b_can_pause ); + var_SetBool( p_input, "can-pause", in->b_can_pause ); access2_Control( in->p_access, ACCESS_CAN_SEEK, &val.b_bool ); var_Set( p_input, "seekable", val ); @@ -2346,10 +2375,8 @@ static int InputSourceInit( input_thread_t *p_input, if( in->p_access->psz_path ) { const char *psz_a, *psz_d; - psz_buf = strdup( in->p_access->psz_path ); - MRLSplit( VLC_OBJECT(p_input), psz_buf, - &psz_a, &psz_d, &psz_real_path ); + MRLSplit( psz_buf, &psz_a, &psz_d, &psz_real_path ); } else { @@ -2648,23 +2675,6 @@ static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta ) } -static inline vlc_bool_t IsValidAccess( const char *psz ) -{ - char c; - - while( ( c = *psz ) != '\0' ) - { - if( c == ':' ) - return VLC_TRUE; - - if( ( !isascii( c ) || !isalnum( c ) ) && c != '-' && ( c != '/' ) ) - return VLC_FALSE; - psz++; - } - /* should not happen though */ - return VLC_FALSE; -} - static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment, int i_new, input_attachment_t **pp_new ) { @@ -2676,8 +2686,7 @@ static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_atta sizeof(input_attachment_t**) * ( i_attachment + i_new ) ); for( i = 0; i < i_new; i++ ) attachment[i_attachment++] = pp_new[i]; - if( pp_new ) - free( pp_new ); + free( pp_new ); /* */ *pi_attachment = i_attachment; @@ -2740,56 +2749,35 @@ static void DemuxMeta( input_thread_t *p_input, vlc_meta_t *p_meta, demux_t *p_d * MRLSplit: parse the access, demux and url part of the * Media Resource Locator. *****************************************************************************/ -void MRLSplit( vlc_object_t *p_input, char *psz_dup, - const char **ppsz_access, const char **ppsz_demux, +void MRLSplit( char *psz_dup, const char **ppsz_access, const char **ppsz_demux, char **ppsz_path ) { - const char *psz_access = ""; - const char *psz_demux = ""; + char *psz_access = NULL; + char *psz_demux = NULL; char *psz_path; - char *psz; - - psz = strchr( psz_dup, ':' ); - if( psz != NULL ) + /* Either there is an access/demux specification before :// + * or we have a plain local file path. */ + psz_path = strstr( psz_dup, "://" ); + if( psz_path != NULL ) { - /* Guess whether ':' is part of a local filename, or separates - * access/demux from path */ - if( !IsValidAccess( psz_dup ) ) - psz = NULL; -#if defined( WIN32 ) || defined( UNDER_CE ) - else if( ( psz - psz_dup == 1 ) && isalpha( psz_dup[0] ) ) - { - msg_Dbg( p_input, "drive letter %c: found in source", *psz_dup ); - psz = NULL; - } -#endif - } - - if( psz != NULL ) - { - *psz++ = '\0'; - if( psz[0] == '/' && psz[1] == '/' ) psz += 2; - - psz_path = psz; - - psz = strchr( psz_dup, '/' ); - if( psz ) - { - *psz++ = '\0'; - psz_demux = psz; - } + *psz_path = '\0'; + psz_path += 3; /* skips "://" */ + /* Separate access from demux (/://) */ psz_access = psz_dup; + psz_demux = strchr( psz_access, '/' ); + if( psz_demux ) + *psz_demux++ = '\0'; } else { psz_path = psz_dup; } - *ppsz_access = psz_access; - *ppsz_demux = psz_demux; - *ppsz_path = psz_path; + *ppsz_access = psz_access ? psz_access : ""; + *ppsz_demux = psz_demux ? psz_demux : ""; + *ppsz_path = psz_path ? psz_path : ""; } /*****************************************************************************