X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=35da58bd31014e589b6593654d4653b3310b4210;hb=7e39dc8b10afd76ab1b40844d971cdcb63e8d843;hp=9eb05d99e946465795d5fcaeee8e34d9df8cdd5e;hpb=ccba67b5ee8f7a31d5a28714375c93a939c24aa6;p=vlc diff --git a/src/input/input.c b/src/input/input.c index 9eb05d99e9..35da58bd31 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -53,6 +53,7 @@ #include #include #include +#include #ifdef HAVE_SYS_STAT_H # include @@ -110,9 +111,6 @@ static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_for static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO fix name */ -/* Do not let a pts_delay from access/demux go beyong 60s */ -#define INPUT_PTS_DELAY_MAX INT64_C(60000000) - #undef input_Create /** * Create a new input_thread_t. @@ -247,18 +245,6 @@ void input_Stop( input_thread_t *p_input, bool b_abort ) input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL ); } -input_resource_t *input_DetachResource( input_thread_t *p_input ) -{ - assert( p_input->b_dead ); - - input_resource_SetInput( p_input->p->p_resource, NULL ); - - input_resource_t *p_resource = input_resource_Detach( p_input->p->p_resource ); - p_input->p->p_sout = NULL; - - return p_resource; -} - /** * Get the item from an input thread * FIXME it does not increase ref count of the item. @@ -335,6 +321,14 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, if( !p_input->p ) return NULL; + /* Parse input options */ + vlc_mutex_lock( &p_item->lock ); + assert( (int)p_item->optflagc == p_item->i_options ); + for( i = 0; i < p_item->i_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 ); + p_input->b_preparsing = b_quick; p_input->psz_header = psz_header ? strdup( psz_header ) : NULL; @@ -349,11 +343,13 @@ 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; - p_input->p->i_rate = INPUT_RATE_DEFAULT - / var_CreateGetFloat( p_input, "rate" ); - /* Currently, the input rate variable is an integer. So we need to destroy - * the float variable inherited from the configuration. */ - var_Destroy( p_input, "rate" ); + 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->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 ); @@ -389,9 +385,15 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, /* */ if( p_resource ) - p_input->p->p_resource = p_resource; + { + p_input->p->p_resource_private = NULL; + p_input->p->p_resource = input_resource_Hold( p_resource ); + } else - p_input->p->p_resource = input_resource_New(); + { + p_input->p->p_resource_private = input_resource_New( VLC_OBJECT( p_input ) ); + p_input->p->p_resource = input_resource_Hold( p_input->p->p_resource_private ); + } input_resource_SetInput( p_input->p->p_resource, p_input ); /* Init control buffer */ @@ -400,14 +402,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, p_input->p->i_control = 0; p_input->p->b_abort = false; - /* Parse input options */ - vlc_mutex_lock( &p_item->lock ); - assert( (int)p_item->optflagc == p_item->i_options ); - for( i = 0; i < p_item->i_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 */ input_ConfigVarInit( p_input ); @@ -508,7 +502,9 @@ static void Destructor( input_thread_t * p_input ) es_out_Delete( p_input->p->p_es_out_display ); if( p_input->p->p_resource ) - input_resource_Delete( p_input->p->p_resource ); + input_resource_Release( p_input->p->p_resource ); + if( p_input->p->p_resource_private ) + input_resource_Release( p_input->p->p_resource_private ); vlc_gc_decref( p_input->p->p_item ); @@ -1138,13 +1134,15 @@ static void UpdatePtsDelay( input_thread_t *p_input ) const int i_cr_average = var_GetInteger( p_input, "cr-average" ) * i_pts_delay / DEFAULT_PTS_DELAY; /* */ - es_out_SetJitter( p_input->p->p_es_out, i_pts_delay, i_cr_average ); + es_out_SetDelay( p_input->p->p_es_out_display, AUDIO_ES, i_audio_delay ); + es_out_SetDelay( p_input->p->p_es_out_display, SPU_ES, i_spu_delay ); + es_out_SetJitter( p_input->p->p_es_out, i_pts_delay, 0, i_cr_average ); } static void InitPrograms( input_thread_t * p_input ) { int i_es_out_mode; - vlc_value_t val; + vlc_list_t list; /* Compute correct pts_delay */ UpdatePtsDelay( p_input ); @@ -1153,22 +1151,31 @@ static void InitPrograms( input_thread_t * p_input ) i_es_out_mode = ES_OUT_MODE_AUTO; if( p_input->p->p_sout ) { + 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 ) { - var_Get( p_input, "programs", &val ); - if( val.p_list && val.p_list->i_count ) + char *buf; + + TAB_INIT( list.i_count, list.p_values ); + for( const char *prgm = strtok_r( prgms, ",", &buf ); + prgm != NULL; + prgm = strtok_r( NULL, ",", &buf ) ) { + vlc_value_t val = { .i_int = atoi( prgm ) }; + INSERT_ELEM( list.p_values, list.i_count, list.i_count, val ); + } + + if( list.i_count > 0 ) i_es_out_mode = ES_OUT_MODE_PARTIAL; /* Note : we should remove the "program" callback. */ - } - else - { - var_FreeList( &val, NULL ); - } + + free( prgms ); } } es_out_SetMode( p_input->p->p_es_out, i_es_out_mode ); @@ -1181,12 +1188,13 @@ static void InitPrograms( input_thread_t * p_input ) else if( i_es_out_mode == ES_OUT_MODE_PARTIAL ) { demux_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, -1, - val.p_list ); + &list ); + TAB_CLEAN( list.i_count, list.p_values ); } else { demux_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, - (int) var_GetInteger( p_input, "program" ), NULL ); + es_out_GetGroupForced( p_input->p->p_es_out ), NULL ); } } @@ -1303,6 +1311,8 @@ error: input_resource_RequestSout( p_input->p->p_resource, p_input->p->p_sout, NULL ); input_resource_SetInput( p_input->p->p_resource, NULL ); + if( p_input->p->p_resource_private ) + input_resource_Terminate( p_input->p->p_resource_private ); } if( !p_input->b_preparsing && libvlc_stats( p_input ) ) @@ -1422,6 +1432,8 @@ static void End( input_thread_t * p_input ) input_resource_RequestSout( p_input->p->p_resource, p_input->p->p_sout, NULL ); input_resource_SetInput( p_input->p->p_resource, NULL ); + if( p_input->p->p_resource_private ) + input_resource_Terminate( p_input->p->p_resource_private ); } /***************************************************************************** @@ -1769,63 +1781,10 @@ static bool Control( input_thread_t *p_input, break; case INPUT_CONTROL_SET_RATE: - case INPUT_CONTROL_SET_RATE_SLOWER: - case INPUT_CONTROL_SET_RATE_FASTER: { - int i_rate; - int i_rate_sign; - /* Get rate and direction */ - if( i_type == INPUT_CONTROL_SET_RATE ) - { - i_rate = abs( val.i_int ); - i_rate_sign = val.i_int < 0 ? -1 : 1; - } - else - { - static const int ppi_factor[][2] = { - {1,64}, {1,32}, {1,16}, {1,8}, {1,4}, {1,3}, {1,2}, {2,3}, - {1,1}, - {3,2}, {2,1}, {3,1}, {4,1}, {8,1}, {16,1}, {32,1}, {64,1}, - {0,0} - }; - int i_error; - int i_idx; - int i; - - i_rate_sign = p_input->p->i_rate < 0 ? -1 : 1; - - i_error = INT_MAX; - i_idx = -1; - for( i = 0; ppi_factor[i][0] != 0; i++ ) - { - const int i_test_r = INPUT_RATE_DEFAULT * ppi_factor[i][0] / ppi_factor[i][1]; - const int i_test_e = abs( abs( p_input->p->i_rate ) - i_test_r ); - if( i_test_e < i_error ) - { - i_idx = i; - i_error = i_test_e; - } - } - - assert( i_idx >= 0 && ppi_factor[i_idx][0] != 0 ); - - if( i_type == INPUT_CONTROL_SET_RATE_SLOWER ) - { - if( ppi_factor[i_idx+1][0] > 0 ) - i_rate = INPUT_RATE_DEFAULT * ppi_factor[i_idx+1][0] / ppi_factor[i_idx+1][1]; - else - i_rate = INPUT_RATE_MAX+1; - } - else - { - assert( i_type == INPUT_CONTROL_SET_RATE_FASTER ); - if( i_idx > 0 ) - i_rate = INPUT_RATE_DEFAULT * ppi_factor[i_idx-1][0] / ppi_factor[i_idx-1][1]; - else - i_rate = INPUT_RATE_MIN-1; - } - } + int i_rate = abs( val.i_int ); + int i_rate_sign = val.i_int < 0 ? -1 : 1; /* Check rate bound */ if( i_rate < INPUT_RATE_MIN ) @@ -1920,13 +1879,11 @@ static bool Control( input_thread_t *p_input, break; case INPUT_CONTROL_SET_AUDIO_DELAY: - es_out_SetDelay( p_input->p->p_es_out_display, AUDIO_ES, val.i_time ); input_SendEventAudioDelay( p_input, val.i_time ); UpdatePtsDelay( p_input ); break; case INPUT_CONTROL_SET_SPU_DELAY: - es_out_SetDelay( p_input->p->p_es_out_display, SPU_ES, val.i_time ); input_SendEventSubtitleDelay( p_input, val.i_time ); UpdatePtsDelay( p_input ); break; @@ -2179,7 +2136,7 @@ static bool Control( input_thread_t *p_input, if( bookmark.i_time_offset < 0 && bookmark.i_byte_offset < 0 ) { - msg_Err( p_input, "invalid bookmark %d", val.i_int ); + msg_Err( p_input, "invalid bookmark %"PRId64, val.i_int ); break; } @@ -2380,46 +2337,6 @@ 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-decode 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 ) @@ -2635,26 +2552,11 @@ static int InputSourceInit( input_thread_t *p_input, psz_demux = in->p_access->psz_demux; } - { - /* Take access/stream redirections into account */ - char *psz_real_path; - char *psz_buf = NULL; - if( in->p_stream->psz_path ) - { - const char *psz_a, *psz_d; - psz_buf = strdup( in->p_stream->psz_path ); - input_SplitMRL( &psz_a, &psz_d, &psz_real_path, psz_buf ); - } - else - { - psz_real_path = psz_path; - } - 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 ); - free( psz_buf ); - } + 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_input->b_preparsing ); if( in->p_demux == NULL ) { @@ -3091,11 +2993,11 @@ 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 **ppsz_access, const char **ppsz_demux, + char **ppsz_path, char *psz_dup ) { - char *psz_access = NULL; - char *psz_demux = NULL; + const char *psz_access; + const char *psz_demux = ""; char *psz_path; /* Either there is an access/demux specification before :// @@ -3106,24 +3008,39 @@ void input_SplitMRL( const char **ppsz_access, const char **ppsz_demux, char **p *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'; - /* We really don't want module name substitution here! */ if( psz_access[0] == '$' ) psz_access++; - if( psz_demux && psz_demux[0] == '$' ) - psz_demux++; + + /* Separate access from demux (/://) */ + char *p = strchr( psz_access, '/' ); + if( p ) + { + *p = '\0'; + psz_demux = p + 1; + if( psz_demux[0] == '$' ) + psz_demux++; + } + + /* Remove HTML anchor if present (not supported). + * The hash symbol itself should be URI-encoded. */ + p = strchr( psz_path, '#' ); + if( p ) + *p = '\0'; } else { +#ifndef NDEBUG + fprintf( stderr, "%s(\"%s\"): not a valid URI!\n", __func__, + psz_dup ); +#endif psz_path = psz_dup; + psz_access = ""; } - *ppsz_access = psz_access ? psz_access : ""; - *ppsz_demux = psz_demux ? psz_demux : ""; + + *ppsz_access = psz_access; + *ppsz_demux = psz_demux; *ppsz_path = psz_path; } @@ -3251,14 +3168,19 @@ static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_for 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 || InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) ) + if( !sub || !url + || InputSourceInit( p_input, sub, url, "subtitle" ) ) { free( sub ); + free( url ); return; } + free( url ); TAB_APPEND( p_input->p->i_slave, p_input->p->slave, sub ); /* Select the ES */