X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput.c;h=dcb7b66dae1d33fa4fed096f13a23f18cec1c3db;hb=b941c1e48ddf3de05bde370ab6495f4580587dda;hp=867fc2010249c3948f13579ef5b8832be1d6884b;hpb=7a2a1077bd2946a6037dcd98ccccfdd26d5828a7;p=vlc diff --git a/src/input/input.c b/src/input/input.c index 867fc20102..dcb7b66dae 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -25,11 +25,16 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include +#include +#include +#include + #include "input_internal.h" #include @@ -76,7 +81,6 @@ static int InputSourceInit( input_thread_t *, input_source_t *, static void InputSourceClean( input_source_t * ); /* TODO */ //static void InputGetAttachments( input_thread_t *, input_source_t * ); - static void SlaveDemux( input_thread_t *p_input ); static void SlaveSeek( input_thread_t *p_input ); @@ -86,6 +90,10 @@ static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta ); static sout_instance_t *SoutFind( vlc_object_t *p_parent, input_item_t *p_item, vlc_bool_t * ); static void SoutKeep( sout_instance_t * ); +static void DemuxMeta( input_thread_t *p_input, vlc_meta_t *p_meta, demux_t *p_demux ); +static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment, + int i_new, input_attachment_t **pp_new ); + /***************************************************************************** * This function creates a new input, and returns a pointer * to its description. On error, it returns NULL. @@ -105,6 +113,7 @@ static void SoutKeep( sout_instance_t * ); * - 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 * TODO explain when Callback is called @@ -147,6 +156,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, p_input->p->i_start = 0; p_input->i_time = 0; p_input->p->i_stop = 0; + p_input->p->i_run = 0; p_input->p->i_title = 0; p_input->p->title = NULL; p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0; @@ -170,12 +180,12 @@ 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; vlc_mutex_lock( &p_item->lock ); - if( !p_input->p->input.p_item->p_meta ) - p_input->p->input.p_item->p_meta = vlc_meta_New(); if( !p_item->p_stats ) p_item->p_stats = stats_NewInputStats( p_input ); @@ -227,7 +237,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, *psz_end = 0; if( !strncmp( psz_start, "name=", 5 ) ) { - p_seekpoint->psz_name = psz_start + 5; + p_seekpoint->psz_name = strdup(psz_start + 5); } else if( !strncmp( psz_start, "bytes=", 6 ) ) { @@ -252,10 +262,10 @@ 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_Control( p_input, INPUT_DEL_INFO, _(VLC_META_INFO_CAT), VLC_META_NOW_PLAYING ); - vlc_mutex_lock( &p_item->lock ); - vlc_meta_SetNowPlaying( p_item->p_meta, NULL ); - vlc_mutex_unlock( &p_item->lock ); + input_Control( p_input, INPUT_DEL_INFO, + _(VLC_META_INFO_CAT), + _(VLC_META_NOW_PLAYING) ); + input_item_SetNowPlaying( p_item, NULL ); /* */ if( p_input->b_preparsing ) @@ -274,23 +284,23 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, static void Destroy( input_thread_t *p_input, sout_instance_t **pp_sout ) { vlc_object_detach( p_input ); + input_thread_private_t *priv = p_input->p; if( pp_sout ) *pp_sout = NULL; - if( p_input->p->p_sout ) + if( priv->p_sout ) { if( pp_sout ) - *pp_sout = p_input->p->p_sout; - else if( p_input->p->b_sout_keep ) - SoutKeep( p_input->p->p_sout ); + *pp_sout = priv->p_sout; + else if( priv->b_sout_keep ) + SoutKeep( priv->p_sout ); else - sout_DeleteInstance( p_input->p->p_sout ); + sout_DeleteInstance( priv->p_sout ); } - vlc_mutex_destroy( &p_input->p->lock_control ); - free( p_input->p ); - vlc_object_destroy( p_input ); + vlc_mutex_destroy( &priv->lock_control ); + free( priv ); } /** @@ -573,6 +583,7 @@ exit: *****************************************************************************/ static void MainLoop( input_thread_t *p_input ) { + int64_t i_start_mdate = mdate(); int64_t i_intf_update = 0; int i_updates = 0; @@ -586,10 +597,11 @@ static void MainLoop( input_thread_t *p_input ) /* Do the read */ if( p_input->i_state != PAUSE_S ) { - if( p_input->p->i_stop <= 0 || p_input->i_time < p_input->p->i_stop ) - i_ret=p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux); + if( ( p_input->p->i_stop > 0 && p_input->i_time >= p_input->p->i_stop ) || + ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) ) + i_ret = 0; /* EOF */ else - i_ret = 0; /* EOF */ + i_ret = p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux); if( i_ret > 0 ) { @@ -659,6 +671,9 @@ static void MainLoop( input_thread_t *p_input ) input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val ); } + + /* */ + i_start_mdate = mdate(); } } else if( i_ret < 0 ) @@ -758,6 +773,20 @@ static int Init( input_thread_t * p_input ) 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 ) ) + { + msg_Dbg( p_input, "Input is a meta file: disabling unneeded options" ); + var_SetString( p_input, "sout", "" ); + var_SetBool( p_input, "sout-all", VLC_FALSE ); + var_SetString( p_input, "input-slave", "" ); + var_SetInteger( p_input, "input-repeat", 0 ); + var_SetString( p_input, "sub-file", "" ); + var_SetBool( p_input, "sub-autodetect-file", VLC_FALSE ); + } + } + if( !p_input->b_preparsing ) { /* Prepare statistics */ @@ -787,8 +816,8 @@ static int Init( input_thread_t * p_input ) } /* Find a usable sout and attach it to p_input */ - psz = var_GetString( p_input, "sout" ); - if( *psz && strncasecmp( p_input->p->input.p_item->psz_uri, "vlc:", 4 ) ) + psz = var_GetNonEmptyString( p_input, "sout" ); + if( psz && strncasecmp( p_input->p->input.p_item->psz_uri, "vlc:", 4 ) ) { /* Check the validity of the provided sout */ if( p_input->p->p_sout ) @@ -814,7 +843,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 ); @@ -846,7 +874,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 ); @@ -876,6 +904,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 ) @@ -900,6 +929,15 @@ static int Init( input_thread_t * p_input ) var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL ); UpdateItemLength( p_input, val.i_time ); } + else + { + val.i_time = input_item_GetDuration( p_input->p->input.p_item ); + if( val.i_time > 0 ) + { /* fallback: gets length from metadata */ + var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL ); + UpdateItemLength( p_input, val.i_time ); + } + } /* Start title/chapter */ if( !p_input->b_preparsing ) @@ -915,10 +953,14 @@ static int Init( input_thread_t * p_input ) /* Start time*/ /* Set start time */ - p_input->p->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) * - I64C(1000000); - p_input->p->i_stop = (int64_t)var_GetInteger( p_input, "stop-time" ) * - I64C(1000000); + p_input->p->i_start = I64C(1000000) * var_GetInteger( p_input, "start-time" ); + p_input->p->i_stop = I64C(1000000) * var_GetInteger( p_input, "stop-time" ); + p_input->p->i_run = I64C(1000000) * var_GetInteger( p_input, "run-time" ); + if( p_input->p->i_run < 0 ) + { + msg_Warn( p_input, "invalid run-time ignored" ); + p_input->p->i_run = 0; + } if( p_input->p->i_start > 0 ) { @@ -969,8 +1011,8 @@ static int Init( input_thread_t * p_input ) } /* Look for and add subtitle files */ - psz_subtitle = var_GetString( p_input, "sub-file" ); - if( *psz_subtitle ) + psz_subtitle = var_GetNonEmptyString( p_input, "sub-file" ); + if( psz_subtitle != NULL ) { msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle ); input_AddSubtitles( p_input, psz_subtitle, VLC_FALSE ); @@ -979,15 +1021,17 @@ static int Init( input_thread_t * p_input ) var_Get( p_input, "sub-autodetect-file", &val ); if( val.b_bool ) { - char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" ); + char *psz_autopath = var_GetNonEmptyString( p_input, "sub-autodetect-path" ); char **subs = subtitles_Detect( p_input, psz_autopath, p_input->p->input.p_item->psz_uri ); input_source_t *sub; i = 0; + if( psz_autopath == NULL ) + psz_autopath = strdup(""); /* Try to autoselect the first autodetected subtitles file * if no subtitles file was specified */ - if( *psz_subtitle == 0 && subs && subs[0] ) + if( ( psz_subtitle == NULL ) && subs && subs[0] ) { input_AddSubtitles( p_input, subs[0], VLC_FALSE ); free( subs[0] ); @@ -997,7 +1041,7 @@ static int Init( input_thread_t * p_input ) /* Then, just add the following subtitles files */ for( ; subs && subs[i]; i++ ) { - if( strcmp( psz_subtitle, subs[i] ) ) + if( !psz_subtitle || strcmp( psz_subtitle, subs[i] ) ) { sub = InputSourceNew( p_input ); if( !InputSourceInit( p_input, sub, subs[i], "subtitle" ) ) @@ -1014,8 +1058,8 @@ static int Init( input_thread_t * p_input ) free( psz_subtitle ); /* Look for slave */ - psz = var_GetString( p_input, "input-slave" ); - if( *psz ) + psz = var_GetNonEmptyString( p_input, "input-slave" ); + if( psz != NULL ) { char *psz_delim; input_source_t *slave; @@ -1043,8 +1087,8 @@ static int Init( input_thread_t * p_input ) else free( slave ); psz = psz_delim; } + free( psz ); } - if( psz ) free( psz ); } else { @@ -1125,7 +1169,7 @@ static int Init( input_thread_t * p_input ) InputMetaUser( p_input, p_meta ); /* Get meta data from master input */ - demux2_Control( p_input->p->input.p_demux, DEMUX_GET_META, p_meta ); + DemuxMeta( p_input, p_meta, p_input->p->input.p_demux ); /* Access_file does not give any meta, and there are no slave */ if( !p_input->b_preparsing ) @@ -1137,8 +1181,7 @@ static int Init( input_thread_t * p_input ) /* Get meta data from slave input */ for( i = 0; i < p_input->p->i_slave; i++ ) { - demux2_Control( p_input->p->slave[i]->p_demux, - DEMUX_GET_META, p_meta ); + DemuxMeta( p_input, p_meta, p_input->p->slave[i]->p_demux ); if( p_input->p->slave[i]->p_access ) { access2_Control( p_input->p->slave[i]->p_access, @@ -1218,10 +1261,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 ); } } @@ -1487,8 +1530,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, if( f_pos < 0.0 ) f_pos = 0.0; if( f_pos > 1.0 ) f_pos = 1.0; /* Reset the decoders states and clock sync (before calling the demuxer */ - es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); - input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE ); + input_EsOutChangePosition( p_input->p->p_es_out ); if( demux2_Control( p_input->p->input.p_demux, DEMUX_SET_POSITION, f_pos ) ) { @@ -1525,8 +1567,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, if( i_time < 0 ) i_time = 0; /* Reset the decoders states and clock sync (before calling the demuxer */ - es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); - input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE ); + input_EsOutChangePosition( p_input->p->p_es_out ); i_ret = demux2_Control( p_input->p->input.p_demux, DEMUX_SET_TIME, i_time ); @@ -1587,8 +1628,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, val.i_int = PLAYING_S; var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL ); - /* Reset clock */ - es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); + /* */ + if( !i_ret ) + input_EsOutChangeState( p_input->p->p_es_out ); } else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S && p_input->p->b_can_pause ) @@ -1617,9 +1659,9 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, p_input->i_state = val.i_int; var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL ); - /* Send discontinuity to decoders (it will allow them to flush - * if implemented */ - input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE, VLC_FALSE ); + /* */ + if( !i_ret ) + input_EsOutChangeState( p_input->p->p_es_out ); } else if( val.i_int == PAUSE_S && !p_input->p->b_can_pause ) { @@ -1641,12 +1683,52 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, { int i_rate; - if( i_type == INPUT_CONTROL_SET_RATE_SLOWER ) - i_rate = p_input->p->i_rate * 2; - else if( i_type == INPUT_CONTROL_SET_RATE_FASTER ) - i_rate = p_input->p->i_rate / 2; - else + if( i_type == INPUT_CONTROL_SET_RATE ) + { i_rate = val.i_int; + } + 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_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(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; + } + } if( i_rate < INPUT_RATE_MIN ) { @@ -1659,25 +1741,39 @@ 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 ); - /* We will not send audio data if new rate != default */ - if( i_rate != INPUT_RATE_DEFAULT && p_input->p->i_rate == INPUT_RATE_DEFAULT ) - input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_TRUE ); - p_input->p->i_rate = i_rate; - /* Reset clock */ - es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); + /* 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; } @@ -1732,8 +1828,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, if( i_title >= 0 && i_title < p_input->p->input.i_title ) { - es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); - input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE ); + input_EsOutChangePosition( p_input->p->p_es_out ); demux2_Control( p_demux, DEMUX_SET_TITLE, i_title ); input_ControlVarTitle( p_input, i_title ); @@ -1753,8 +1848,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, if( i_title >= 0 && i_title < p_input->p->input.i_title ) { - es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); - input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE ); + input_EsOutChangePosition( p_input->p->p_es_out ); access2_Control( p_access, ACCESS_SET_TITLE, i_title ); stream_AccessReset( p_input->p->input.p_stream ); @@ -1794,8 +1888,8 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, if( i_seekpoint >= 0 && i_seekpoint < p_input->p->input.title[p_demux->info.i_title]->i_seekpoint ) { - es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); - input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE ); + + input_EsOutChangePosition( p_input->p->p_es_out ); demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint ); } @@ -1822,7 +1916,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, else i_seekpoint--; } - else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) + else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) i_seekpoint = p_access->info.i_seekpoint + 1; else i_seekpoint = val.i_int; @@ -1830,8 +1924,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type, if( i_seekpoint >= 0 && i_seekpoint < p_input->p->input.title[p_access->info.i_title]->i_seekpoint ) { - es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR ); - input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE ); + input_EsOutChangePosition( p_input->p->p_es_out ); access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint ); @@ -1985,7 +2078,7 @@ static int UpdateFromAccess( input_thread_t *p_input ) vlc_meta_t *p_meta = vlc_meta_New(); access2_Control( p_input->p->input.p_access,ACCESS_GET_META, p_meta ); InputUpdateMeta( p_input, p_meta ); - var_SetBool( p_input, "item-change", p_input->p->input.p_item->i_id ); + var_SetInteger( pl_Get( p_input ), "item-change", p_input->p->input.p_item->i_id ); p_access->info.i_update &= ~INPUT_UPDATE_META; } @@ -2023,16 +2116,14 @@ static int UpdateFromAccess( input_thread_t *p_input ) *****************************************************************************/ static void UpdateItemLength( input_thread_t *p_input, int64_t i_length ) { - vlc_mutex_lock( &p_input->p->input.p_item->lock ); - p_input->p->input.p_item->i_duration = i_length; - vlc_mutex_unlock( &p_input->p->input.p_item->lock ); + input_item_SetDuration( p_input->p->input.p_item, (mtime_t) i_length ); if( !p_input->b_preparsing ) { 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 ); } } @@ -2055,8 +2146,12 @@ 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; return in; @@ -2076,6 +2171,7 @@ static int InputSourceInit( input_thread_t *p_input, char *psz_tmp; char *psz; vlc_value_t val; + double f_fps; strcpy( psz_dup, psz_mrl ); @@ -2108,9 +2204,9 @@ 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_GetString( p_input, "demux" ); + char *psz_var_demux = var_GetNonEmptyString( p_input, "demux" ); - if( *psz_var_demux != '\0' && + if( psz_var_demux != NULL && !strchr(psz_var_demux, ',' ) && !strchr(psz_var_demux, ':' ) ) { @@ -2118,10 +2214,6 @@ static int InputSourceInit( input_thread_t *p_input, msg_Dbg( p_input, "enforced demux ` %s'", psz_demux ); } - else if( psz_var_demux ) - { - free( psz_var_demux ); - } } /* Try access_demux if no demux given */ @@ -2158,15 +2250,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; - /* FIXME todo - demux2_Control( in->p_demux, DEMUX_CAN_SEEK, + 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 ); + + 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 { @@ -2190,7 +2301,17 @@ static int InputSourceInit( input_thread_t *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 = "" ; + in->p_access = access2_New( p_input, + "", "", psz_mrl, + p_input->b_preparsing ); + } if( in->p_access == NULL ) { msg_Err( p_input, "open of `%s' failed: %s", psz_mrl, @@ -2203,7 +2324,7 @@ static int InputSourceInit( input_thread_t *p_input, } /* */ - psz_tmp = psz = var_GetString( p_input, "access-filter" ); + psz_tmp = psz = var_GetNonEmptyString( p_input, "access-filter" ); while( psz && *psz ) { access_t *p_access = in->p_access; @@ -2222,7 +2343,7 @@ static int InputSourceInit( input_thread_t *p_input, psz = end; } - if( psz_tmp ) free( psz_tmp ); + free( psz_tmp ); /* Get infos from access */ if( !p_input->b_preparsing ) @@ -2242,8 +2363,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 ); @@ -2292,8 +2417,8 @@ static int InputSourceInit( input_thread_t *p_input, msg_Err( p_input, "no suitable demux module for `%s/%s://%s'", psz_access, psz_demux, psz_path ); intf_UserFatal( VLC_OBJECT( p_input ), VLC_FALSE, - _("Can't recognize the input's format"), - _("The format of '%s' can't be detected. " + _("VLC can't recognize the input's format"), + _("The format of '%s' cannot be detected. " "Have a look the log for details."), psz_mrl ); goto error; } @@ -2312,27 +2437,29 @@ static int InputSourceInit( input_thread_t *p_input, in->b_title_demux = VLC_TRUE; } } - /* get attachment - * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */ - if( 1 || !p_input->b_preparsing ) + } + + /* get attachment + * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */ + if( 1 || !p_input->b_preparsing ) + { + int i_attachment; + input_attachment_t **attachment; + if( !demux2_Control( in->p_demux, DEMUX_GET_ATTACHMENTS, + &attachment, &i_attachment ) ) { - int i_attachment; - input_attachment_t **attachment; - if( !demux2_Control( in->p_demux, DEMUX_GET_ATTACHMENTS, - &attachment, &i_attachment ) ) - { - int i; - vlc_mutex_lock( &p_input->p->input.p_item->lock ); - p_input->p->attachment = realloc( p_input->p->attachment, - sizeof(input_attachment_t**) * ( p_input->p->i_attachment + i_attachment ) ); - for( i = 0; i < i_attachment; i++ ) - p_input->p->attachment[p_input->p->i_attachment++] = attachment[i]; - if( attachment ) - free( attachment ); - vlc_mutex_unlock( &p_input->p->input.p_item->lock ); - } + vlc_mutex_lock( &p_input->p->input.p_item->lock ); + AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, + i_attachment, attachment ); + vlc_mutex_unlock( &p_input->p->input.p_item->lock ); } } + if( !demux2_Control( in->p_demux, DEMUX_GET_FPS, &f_fps ) ) + { + vlc_mutex_lock( &p_input->p->input.p_item->lock ); + in->f_fps = f_fps; + vlc_mutex_unlock( &p_input->p->input.p_item->lock ); + } if( var_GetInteger( p_input, "clock-synchro" ) != -1 ) in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" ); @@ -2467,19 +2594,17 @@ static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta ) /* Get meta information from user */ #define GET_META( field, s ) \ var_Get( p_input, (s), &val ); \ - if( *val.psz_string ) { \ - if( p_meta->psz_ ## field ) free ( p_meta->psz_ ## field ); \ - p_meta->psz_ ## field = strdup( val.psz_string ); \ - } \ + if( *val.psz_string ) \ + vlc_meta_Set( p_meta, vlc_meta_ ## field, val.psz_string ); \ free( val.psz_string ) - GET_META( title, "meta-title" ); - GET_META( artist, "meta-artist" ); - GET_META( genre, "meta-genre" ); - GET_META( copyright, "meta-copyright" ); - GET_META( description, "meta-description" ); - GET_META( date, "meta-date" ); - GET_META( url, "meta-url" ); + GET_META( Title, "meta-title" ); + GET_META( Artist, "meta-artist" ); + GET_META( Genre, "meta-genre" ); + GET_META( Copyright, "meta-copyright" ); + GET_META( Description, "meta-description" ); + GET_META( Date, "meta-date" ); + GET_META( URL, "meta-url" ); #undef GET_META } @@ -2490,50 +2615,85 @@ 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->input.p_item; + char * psz_arturl = NULL; char *psz_title = NULL; + int i; + int i_arturl_event = VLC_FALSE; if( !p_meta ) return; - vlc_mutex_lock( &p_item->lock ); - if( p_meta->psz_title && !p_item->b_fixed_name ) - psz_title = strdup( p_meta->psz_title ); + psz_arturl = input_item_GetArtURL( p_item ); - if( p_item->p_meta ) - { - char *psz_arturl = p_item->p_meta->psz_arturl; - p_item->p_meta->psz_arturl = NULL; - - vlc_meta_Merge( p_item->p_meta, p_meta ); + 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 ) ); - if( psz_arturl && *psz_arturl ) - vlc_meta_SetArtURL( p_item->p_meta, psz_arturl ); + vlc_meta_Merge( p_item->p_meta, p_meta ); - vlc_meta_Delete( p_meta ); - } - else + if( psz_arturl && *psz_arturl ) { - p_item->p_meta = p_meta; + vlc_meta_Set( p_item->p_meta, vlc_meta_ArtworkURL, psz_arturl ); + i_arturl_event = VLC_TRUE; } - if( p_item->p_meta->psz_arturl && !strncmp( p_item->p_meta->psz_arturl, "attachment://", strlen("attachment") ) ) + + vlc_meta_Delete( p_meta ); + + if( psz_arturl && !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 ) - vlc_meta_SetArtURL( p_item->p_meta, "" ); + { + vlc_meta_Set( p_item->p_meta, vlc_meta_ArtworkURL, "" ); + i_arturl_event = VLC_TRUE; + + } else input_ExtractAttachmentAndCacheArt( p_input ); } + free( psz_arturl ); - p_item->p_meta->i_status |= ITEM_PREPARSED; + /* A bit ugly */ + p_meta = NULL; + if( vlc_dictionary_keys_count( &p_item->p_meta->extra_tags ) > 0 ) + { + p_meta = vlc_meta_New(); + vlc_meta_Merge( p_meta, input_item_GetMetaObject( p_item ) ); + } vlc_mutex_unlock( &p_item->lock ); + input_item_SetPreparsed( p_item, VLC_TRUE ); + + if( i_arturl_event == VLC_TRUE ) + { + vlc_event_t event; + + /* Notify interested third parties */ + event.type = vlc_InputItemMetaChanged; + event.u.input_item_meta_changed.meta_type = vlc_meta_ArtworkURL; + vlc_event_send( &p_item->event_manager, &event ); + } + if( psz_title ) { input_Control( p_input, INPUT_SET_NAME, psz_title ); free( psz_title ); } + if( p_meta ) + { + char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags ); + for( i = 0; ppsz_all_keys[i]; i++ ) + { + input_Control( p_input, INPUT_ADD_INFO, _(VLC_META_INFO_CAT), _(ppsz_all_keys[i]), + vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) ); + free( ppsz_all_keys[i] ); + } + free( ppsz_all_keys ); + vlc_meta_Delete( p_meta ); + } + /** \todo handle sout meta */ } @@ -2547,7 +2707,7 @@ static inline vlc_bool_t IsValidAccess( const char *psz ) if( c == ':' ) return VLC_TRUE; - if( !isascii( c ) && !isalnum( c ) && c != '/' ) + if( ( !isascii( c ) || !isalnum( c ) ) && c != '-' && ( c != '/' ) ) return VLC_FALSE; psz++; } @@ -2555,6 +2715,76 @@ static inline vlc_bool_t IsValidAccess( const char *psz ) return VLC_FALSE; } +static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment, + int i_new, input_attachment_t **pp_new ) +{ + int i_attachment = *pi_attachment; + input_attachment_t **attachment = *ppp_attachment; + int i; + + attachment = realloc( attachment, + 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 ); + + /* */ + *pi_attachment = i_attachment; + *ppp_attachment = attachment; +} + +static void DemuxMeta( input_thread_t *p_input, vlc_meta_t *p_meta, demux_t *p_demux ) +{ + vlc_bool_t b_bool; + module_t *p_id3; + + +#if 0 + /* XXX I am not sure it is a great idea, besides, there is more than that + * if we want to do it right */ + vlc_mutex_lock( &p_item->lock ); + if( p_item->p_meta && (p_item->p_meta->i_status & ITEM_PREPARSED ) ) + { + vlc_mutex_unlock( &p_item->lock ); + return; + } + vlc_mutex_unlock( &p_item->lock ); +#endif + + demux2_Control( p_demux, DEMUX_GET_META, p_meta ); + if( demux2_Control( p_demux, DEMUX_HAS_UNSUPPORTED_META, &b_bool ) ) + return; + if( !b_bool ) + return; + + p_demux->p_private = malloc( sizeof( demux_meta_t ) ); + if(! p_demux->p_private ) + return; + + p_id3 = module_Need( p_demux, "meta reader", NULL, 0 ); + if( p_id3 ) + { + demux_meta_t *p_demux_meta = (demux_meta_t *)p_demux->p_private; + + if( p_demux_meta->p_meta ) + { + vlc_meta_Merge( p_meta, p_demux_meta->p_meta ); + vlc_meta_Delete( p_demux_meta->p_meta ); + } + + if( p_demux_meta->i_attachments > 0 ) + { + vlc_mutex_lock( &p_input->p->input.p_item->lock ); + AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment, + p_demux_meta->i_attachments, p_demux_meta->attachments ); + vlc_mutex_unlock( &p_input->p->input.p_item->lock ); + } + module_Unneed( p_demux, p_id3 ); + } + free( p_demux->p_private ); +} + /***************************************************************************** * MRLSplit: parse the access, demux and url part of the