static void ParseOption( input_thread_t *p_input, const char *psz_option );
static void DecodeUrl ( char * );
+static void MRLSplit( input_thread_t *, char *, char **, char **, char ** );
+
+static input_source_t *InputSourceNew( input_thread_t *);
+static int InputSourceInit( input_thread_t *, input_source_t *,
+ char *, char *psz_forced_demux );
+static void InputSourceClean( input_thread_t *, input_source_t * );
+
+static void SlaveDemux( input_thread_t *p_input );
+static void SlaveSeek( input_thread_t *p_input );
+
+static vlc_meta_t *InputMetaUser( input_thread_t *p_input );
/*****************************************************************************
* input_CreateThread: creates a new input thread
* - title,title-next,title-prev
* - chapter,chapter-next, chapter-prev
* - program, audio-es, video-es, spu-es
+ * - audio-delay, spu-delay
* - bookmark
* * Get only:
* - 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)
* * For intf callback upon changes
* - intf-change
* TODO explain when Callback is called
p_input->input.b_eof = VLC_FALSE;
p_input->input.i_cr_average = 0;
+ /* No slave */
+ p_input->i_slave = 0;
+ p_input->slave = NULL;
+
/* Init control buffer */
vlc_mutex_init( p_input, &p_input->lock_control );
p_input->i_control = 0;
- p_input->p_sys = NULL;
/* Parse input options */
vlc_mutex_lock( &p_item->lock );
* Run: main thread loop
*****************************************************************************
* Thread in charge of processing the network packets and demultiplexing.
+ *
+ * TODO:
+ * read subtitle support (XXX take care of spu-delay in the right way).
+ * multi-input support (XXX may be done with subs)
*****************************************************************************/
static int Run( input_thread_t *p_input )
{
}
/* Main loop */
- while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
+ while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof )
{
vlc_bool_t b_force_update = VLC_FALSE;
int i_ret;
/* 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->b_eof = VLC_TRUE;
p_input->input.b_eof = VLC_TRUE;
}
else
{
- msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
+ msg_Dbg( p_input, "repeating the same input (%d)",
+ repeat.i_int );
if( repeat.i_int > 0 )
{
repeat.i_int--;
{
p_input->b_error = VLC_TRUE;
}
+
+ if( i_ret > 0 && p_input->i_slave > 0 )
+ {
+ SlaveDemux( p_input );
+ }
}
else
{
double f_pos;
int64_t i_time, i_length;
/* update input status variables */
- if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos ) )
+ if( !demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_POSITION, &f_pos ) )
{
val.f_float = (float)f_pos;
var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
}
- if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
+ if( !demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_TIME, &i_time ) )
{
p_input->i_time = i_time;
val.i_time = i_time;
var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
}
- if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &i_length ) )
+ if( !demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_LENGTH, &i_length ) )
{
vlc_value_t old_val;
var_Get( p_input, "length", &old_val );
if( old_val.i_time != val.i_time )
{
- /* TODO */
-#if 0
char psz_buffer[MSTRTIME_MAX_SIZE];
- vlc_mutex_lock( &p_input->p_item->lock );
- p_input->p_item->i_duration = i_length;
- vlc_mutex_unlock( &p_input->p_item->lock );
+ vlc_mutex_lock( &p_input->input.p_item->lock );
+ p_input->input.p_item->i_duration = i_length;
+ vlc_mutex_unlock( &p_input->input.p_item->lock );
- input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
- msecstotimestr( psz_buffer, i_length / 1000 ) );
-#endif
+ input_Control( p_input, INPUT_ADD_INFO,
+ _("General"), _("Duration"),
+ msecstotimestr( psz_buffer, i_length / 1000 ) );
}
}
}
}
- /* Wait we are asked to die */
- if( !p_input->b_die )
- {
- Error( p_input );
- }
-
- /* Clean up */
- End( p_input );
-
- return 0;
-
-#if 0
- while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
+ if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
{
- if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
+ /* We have finish to demux data but not to play them */
+ while( !p_input->b_die )
{
- if( p_input->stream.p_selected_area->i_size > 0 )
- {
- unsigned int i;
- mtime_t i_time;
- double f = (double)p_input->stream.p_selected_area->i_seek /
- (double)p_input->stream.p_selected_area->i_size;
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- demux_Control( p_input, DEMUX_SET_POSITION, f );
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- /* Escape all decoders for the stream discontinuity they
- * will encounter. */
- input_EscapeDiscontinuity( p_input );
-
- for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
- {
- pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
-
- /* Reinitialize synchro. */
- p_pgrm->i_synchro_state = SYNCHRO_REINIT;
- }
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
- {
- int i;
- vlc_value_t val;
+ if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
+ break;
- /* Help in bar display */
- val.i_time = i_time;
- var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
+ msg_Dbg( p_input, "waiting decoder fifos to empty" );
- /* Seek subs */
- for( i = 0; i < p_input->p_sys->i_sub; i++ )
- {
- subtitle_Seek( p_input->p_sys->sub[i], i_time );
- }
- }
- if( !demux_Control( p_input, DEMUX_GET_POSITION, &f ) )
- {
- val.f_float = (float)f;
- var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
- }
- vlc_mutex_lock( &p_input->stream.stream_lock );
- }
- p_input->stream.p_selected_area->i_seek = NO_SEEK;
+ msleep( INPUT_IDLE_SLEEP );
}
- /* Read and demultiplex some data. */
- i_count = p_input->pf_demux( p_input );
-
- XXXXX
-
- if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
- {
- int i;
- mtime_t i_time;
- mtime_t i_length;
- double d_pos;
-
- /* update input status variables */
- if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
- {
- val.f_float = (float)d_pos;
- var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
- }
- if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
- {
- val.i_time = i_time;
- var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
- }
- if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
- {
- vlc_value_t old_val;
- var_Get( p_input, "length", &old_val );
- val.i_time = i_length;
- var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
- if( old_val.i_time != val.i_time )
- {
- char psz_buffer[MSTRTIME_MAX_SIZE];
-
- vlc_mutex_lock( &p_input->p_item->lock );
- p_input->p_item->i_duration = i_length;
- vlc_mutex_unlock( &p_input->p_item->lock );
-
- input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
- msecstotimestr( psz_buffer, i_length / 1000 ) );
- }
- }
-
- /* Check stop-time */
- if( p_input->p_sys->i_stop_time > 0 && p_input->p_sys->i_stop_time < i_time )
- {
- msg_Warn( p_input, "EOF reached because of stop-time" );
- p_input->b_eof = 1;
- }
-
- /* update subs */
- for( i = 0; i < p_input->p_sys->i_sub; i++ )
- {
- subtitle_Demux( p_input->p_sys->sub[i], i_time );
- }
-
- i_update_next = mdate() + I64C(150000);
- }
+ /* We have finished */
+ p_input->b_eof = VLC_TRUE;
}
- if( p_input->b_error || p_input->b_eof )
+ /* Wait we are asked to die */
+ if( !p_input->b_die )
{
- ErrorThread( p_input );
+ Error( p_input );
}
- EndThread( p_input );
+ /* Clean up */
+ End( p_input );
return 0;
-#endif
}
/*****************************************************************************
*****************************************************************************/
static int Init( input_thread_t * p_input )
{
- char *psz_dup = strdup( p_input->input.p_item->psz_uri );
- char *psz_access = NULL;
- char *psz_demux = NULL;
- char *psz_path = NULL;
char *psz;
+ char *psz_subtitle;
vlc_value_t val;
-
- /* Open access/stream/demux */
- psz = strchr( psz_dup, ':' );
-#if defined( WIN32 ) || defined( UNDER_CE )
- if( psz - psz_dup == 1 )
- {
- msg_Warn( p_input, "drive letter %c: found in source string", psz_dup[0] );
- }
- else
-#endif
- if( psz )
- {
- *psz++ = '\0';
- if( psz[0] == '/' && psz[1] == '/' )
- psz += 2;
-
- psz_path = psz;
-
- psz = strchr( psz_dup, '/' );
- if( psz )
- {
- *psz++ = '\0';
- psz_demux = psz;
- }
-
- psz_access = psz_dup;
- }
- else
- {
- psz_path = psz_dup;
- }
-
- if( psz_access == NULL ) psz_access = "";
- if( psz_demux == NULL ) psz_demux = "";
- if( psz_path == NULL ) psz_path = "";
-
- msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
- p_input->input.p_item->psz_uri,
- psz_access, psz_demux, psz_path );
+ double f_fps;
+ vlc_meta_t *p_meta, *p_meta_user;
+ int i;
/* Initialize optional stream output. (before access/demuxer) */
psz = var_GetString( p_input, "sout" );
{
msg_Err( p_input, "cannot start stream output instance, aborting" );
free( psz );
- free( psz_dup );
-
return VLC_EGENERIC;
}
}
es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
- /* Try access_demux if no demux given */
- if( *psz_access && *psz_demux == '\0' )
+ if( InputSourceInit( p_input, &p_input->input,
+ p_input->input.p_item->psz_uri, NULL ) )
{
- p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
- NULL, p_input->p_es_out );
+ goto error;
}
- if( p_input->input.p_demux )
- {
- /* Get infos from access_demux */
- demux2_Control( p_input->input.p_demux,
- DEMUX_GET_PTS_DELAY, &p_input->i_pts_delay );
- p_input->input.b_title_demux = VLC_TRUE;
- if( demux2_Control( p_input->input.p_demux,
- DEMUX_GET_TITLE_INFO,
- &p_input->input.title, &p_input->input.i_title ) )
- {
- p_input->input.i_title = 0;
- p_input->input.title = NULL;
- }
- demux2_Control( p_input->input.p_demux, DEMUX_CAN_CONTROL_PACE,
- &p_input->input.b_can_pace_control );
- demux2_Control( p_input->input.p_demux, DEMUX_CAN_PAUSE,
- &p_input->input.b_can_pause );
- }
- else
- {
- /* Now try a real access */
- p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
-
- /* Access failed, URL encoded ? */
- if( p_input->input.p_access == NULL && strchr( psz_path, '%' ) )
- {
- DecodeUrl( psz_path );
-
- msg_Dbg( p_input, "retying with access `%s' demux `%s' path `%s'",
- psz_access, psz_demux, psz_path );
-
- p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
- }
-#ifndef WIN32 /* Remove this gross hack from the win32 build as colons
- * are forbidden in filenames on Win32. */
-
- /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
- if( p_input->input.p_access == NULL &&
- *psz_access == '\0' && ( *psz_demux || *psz_path ) )
- {
- free( psz_dup );
- psz_dup = strdup( p_input->input.p_item->psz_uri );
- psz_access = "";
- psz_demux = "";
- psz_path = psz_dup;
-
- p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
- }
-#endif
-
- if( p_input->input.p_access == NULL )
- {
- msg_Err( p_input, "no suitable access module for `%s'",
- p_input->input.p_item->psz_uri );
- goto error;
- }
-
- /* Get infos from access */
- access2_Control( p_input->input.p_access,
- ACCESS_GET_PTS_DELAY, &p_input->i_pts_delay );
- p_input->input.b_title_demux = VLC_FALSE;
- if( access2_Control( p_input->input.p_access,
- ACCESS_GET_TITLE_INFO,
- &p_input->input.title, &p_input->input.i_title ) )
- {
- p_input->input.i_title = 0;
- p_input->input.title = NULL;
- }
- access2_Control( p_input->input.p_access, ACCESS_CAN_CONTROL_PACE,
- &p_input->input.b_can_pace_control );
- access2_Control( p_input->input.p_access, ACCESS_CAN_PAUSE,
- &p_input->input.b_can_pace_control );
-
- /* Create the stream_t */
- p_input->input.p_stream = stream_AccessNew( p_input->input.p_access );
- if( p_input->input.p_stream == NULL )
- {
- msg_Warn( p_input, "cannot create a stream_t from access" );
- goto error;
- }
-
- /* Open a demuxer */
- if( *psz_demux == '\0' && *p_input->input.p_access->psz_demux )
- {
- psz_demux = p_input->input.p_access->psz_demux;
- }
- p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
- p_input->input.p_stream,
- p_input->p_es_out );
- if( p_input->input.p_demux == NULL )
- {
- msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
- psz_access, psz_demux, psz_path );
- goto error;
- }
-
- /* TODO get title from demux */
- if( p_input->input.i_title <= 0 )
- {
- if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TITLE_INFO,
- &p_input->input.title, &p_input->input.i_title ) )
- {
- p_input->input.i_title = 0;
- p_input->input.title = NULL;
- }
- else
- {
- p_input->input.b_title_demux = VLC_TRUE;
- }
- }
- }
- /* Create global title (for now, just a copy) */
+ /* Create global title (from master) */
p_input->i_title = p_input->input.i_title;
+ p_input->title = p_input->input.title;
if( p_input->i_title > 0 )
{
- int i;
- p_input->title = malloc( sizeof( input_title_t *) * p_input->i_title );
- for( i = 0; i < p_input->i_title; i++ )
- {
- p_input->title[i] = vlc_input_title_Duplicate( p_input->input.title[i] );
- }
-
/* Setup variables */
input_ControlVarNavigation( p_input );
input_ControlVarTitle( p_input, 0 );
}
+
/* Global flag */
p_input->b_can_pace_control = p_input->input.b_can_pace_control;
p_input->b_can_pause = p_input->input.b_can_pause;
if( val.i_int < 0 )
p_input->i_pts_delay -= (val.i_int * 1000);
- /* Init input_thread_sys_t */
- p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
- p_input->p_sys->i_sub = 0;
- p_input->p_sys->sub = NULL;
-
- /* TODO: check meta data from users */
-
- /* TODO: get meta data from demuxer */
-
+ /* Load master infos */
/* Init length */
- if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &val.i_time ) && val.i_time > 0 )
+ if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH,
+ &val.i_time ) && val.i_time > 0 )
{
var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
/* TODO update playlist meta data */
}
- /* TODO: do subtitle loading */
+ /* Load subtitles */
+ /* Get fps and set it if not already set */
+ if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) &&
+ f_fps > 1.0 )
+ {
+ vlc_value_t fps;
+ if( var_Get( p_input, "sub-fps", &fps ) )
+ {
+ var_Create( p_input, "sub-fps", VLC_VAR_FLOAT| VLC_VAR_DOINHERIT );
+ var_SetFloat( p_input, "sub-fps", f_fps );
+ }
+ }
+
+ /* Look for and add subtitle files */
+ psz_subtitle = var_GetString( p_input, "sub-file" );
+ if( *psz_subtitle )
+ {
+ input_source_t *sub;
+ vlc_value_t count;
+ vlc_value_t list;
+
+ msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
+
+ var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
+
+ /* */
+ sub = InputSourceNew( p_input );
+ if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) )
+ {
+ TAB_APPEND( p_input->i_slave, p_input->slave, sub );
+
+ /* Select the ES */
+ if( !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 )
+ {
+ input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
+ &list.p_list->p_values[count.i_int] );
+ }
+ var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list, NULL );
+ }
+ }
+ }
+
+ var_Get( p_input, "sub-autodetect-file", &val );
+ if( val.b_bool )
+ {
+ char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" );
+ char **subs = subtitles_Detect( p_input, psz_autopath,
+ p_input->input.p_item->psz_uri );
+ input_source_t *sub;
+
+ for( i = 0; subs[i] != NULL; i++ )
+ {
+ if( strcmp( psz_subtitle, subs[i] ) )
+ {
+ sub = InputSourceNew( p_input );
+ if( !InputSourceInit( p_input, sub, subs[i], "subtitle" ) )
+ {
+ TAB_APPEND( p_input->i_slave, p_input->slave, sub );
+ }
+ }
+ free( subs[i] );
+ }
+ free( subs );
+ free( psz_autopath );
+ }
+ free( psz_subtitle );
+
+ /* Look for slave */
+ psz = var_GetString( p_input, "input-slave" );
+ if( *psz )
+ {
+ char *psz_delim = strchr( psz, '#' );
+
+ for( ;; )
+ {
+ input_source_t *slave;
+
+ if( psz_delim )
+ {
+ *psz_delim++ = '\0';
+ }
+
+ if( *psz == '\0' )
+ {
+ if( psz_delim )
+ continue;
+ else
+ break;
+ }
+
+ msg_Dbg( p_input, "adding slave '%s'", psz );
+ slave = InputSourceNew( p_input );
+ if( !InputSourceInit( p_input, slave, psz, NULL ) )
+ {
+ TAB_APPEND( p_input->i_slave, p_input->slave, slave );
+ }
+ if( !psz_delim )
+ break;
+ }
+ }
+ free( psz );
/* Set up es_out */
es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
- /* TODO select forced subs */
-#if 0
- if( p_sub_toselect )
- {
- es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
- p_sub_toselect->p_es, VLC_TRUE );
- }
-#endif
-
if( p_input->p_sout )
{
if( p_input->p_sout->i_out_pace_nocontrol > 0 )
p_input->b_out_pace_control ? "asynch" : "synch" );
}
- msg_Dbg( p_input, "`%s' sucessfully opened",
- p_input->input.p_item->psz_uri );
-
- /* initialization is complete */
- p_input->i_state = PLAYING_S;
-
- val.i_int = PLAYING_S;
- var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
-
- return VLC_SUCCESS;
-
-error:
- if( p_input->input.p_demux )
- demux2_Delete( p_input->input.p_demux );
-
- if( p_input->input.p_stream )
- stream_AccessDelete( p_input->input.p_stream );
-
- if( p_input->input.p_access )
- access2_Delete( p_input->input.p_access );
-
- if( p_input->p_es_out )
- input_EsOutDelete( p_input->p_es_out );
-
- if( p_input->p_sout )
- sout_DeleteInstance( p_input->p_sout );
-
- /* Mark them deleted */
- p_input->input.p_demux = NULL;
- p_input->input.p_stream = NULL;
- p_input->input.p_access = NULL;
- p_input->p_es_out = NULL;
- p_input->p_sout = NULL;
-
- return VLC_EGENERIC;
-
-#if 0
- vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
-// float f_fps;
- double f_fps;
- mtime_t i_length;
+ /* Get meta data from users */
+ p_meta_user = InputMetaUser( p_input );
- FIXME
- p_input->input.i_cr_average = config_GetInt( p_input, "cr-average" );
- p_input->stream.control.i_status = INIT_S;
- p_input->stream.control.i_rate = DEFAULT_RATE;
+ /* Get meta data from master input */
+ if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
+ p_meta = NULL;
-
- /* Init input_thread_sys_t */
- p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
- p_input->p_sys->i_sub = 0;
- p_input->p_sys->sub = NULL;
-
- /* Get meta information from user */
- var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Create( p_input, "meta-artist", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Create( p_input, "meta-genre", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Create( p_input, "meta-copyright", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
- var_Create( p_input, "meta-description", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
- var_Create( p_input, "meta-date", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Create( p_input, "meta-url", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- if( (p_meta_user = vlc_meta_New()) )
+ /* Merge them */
+ if( p_meta == NULL )
{
- vlc_value_t val;
-
- var_Get( p_input, "meta-title", &val );
- if( *val.psz_string )
- vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
- free( val.psz_string );
- var_Get( p_input, "meta-author", &val );
- if( *val.psz_string )
- vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
- free( val.psz_string );
- var_Get( p_input, "meta-artist", &val );
- if( *val.psz_string )
- vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
- free( val.psz_string );
- var_Get( p_input, "meta-genre", &val );
- if( *val.psz_string )
- vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
- free( val.psz_string );
- var_Get( p_input, "meta-copyright", &val );
- if( *val.psz_string )
- vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
- free( val.psz_string );
- var_Get( p_input, "meta-description", &val );
- if( *val.psz_string )
- vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
- free( val.psz_string );
- var_Get( p_input, "meta-date", &val );
- if( *val.psz_string )
- vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
- free( val.psz_string );
- var_Get( p_input, "meta-url", &val );
- if( *val.psz_string )
- vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
- free( val.psz_string );
+ p_meta = p_meta_user;
}
-
- /* Get meta informations from demuxer */
- if( !demux_Control( p_input, DEMUX_GET_META, &p_meta ) ||
- ( p_meta_user && p_meta_user->i_meta ) )
+ else if( p_meta_user )
{
- int i;
+ vlc_meta_Merge( p_meta, p_meta_user );
+ vlc_meta_Delete( p_meta_user );
+ }
- /* Merge demux and user metadata */
- if( !p_meta ){ p_meta = p_meta_user; p_meta_user = NULL; }
- else if( p_meta && p_meta_user ) vlc_meta_Merge( p_meta, p_meta_user );
+ /* Get meta data from slave input */
+ for( i = 0; i < p_input->i_slave; i++ )
+ {
+ vlc_meta_t *p_meta_slave;
- msg_Dbg( p_input, "meta informations:" );
- if( p_meta->i_meta > 0 )
+ if( !demux2_Control( p_input->slave[i]->p_demux, DEMUX_GET_META, &p_meta_slave ) )
{
- for( i = 0; i < p_meta->i_meta; i++ )
+ if( p_meta == NULL )
+ {
+ p_meta = p_meta_slave;
+ }
+ else if( p_meta_slave )
{
- msg_Dbg( p_input, " - '%s' = '%s'", _(p_meta->name[i]),
- p_meta->value[i] );
- if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
- p_meta->value[i] )
- input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );
-
- if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
- input_Control( p_input, INPUT_ADD_INFO, _("General"),
- _("Author"), p_meta->value[i] );
-
- input_Control( p_input, INPUT_ADD_INFO, _("File"),
- _(p_meta->name[i]), "%s", p_meta->value[i] );
+ vlc_meta_Merge( p_meta, p_meta_slave );
+ vlc_meta_Delete( p_meta_slave );
}
}
+ }
+
+ if( p_meta && p_meta->i_meta > 0 )
+ {
+ msg_Dbg( p_input, "meta information:" );
+ for( i = 0; i < p_meta->i_meta; i++ )
+ {
+ msg_Dbg( p_input, " - '%s' = '%s'",
+ _(p_meta->name[i]), p_meta->value[i] );
+
+ if( !strcmp(p_meta->name[i], VLC_META_TITLE) && p_meta->value[i] )
+ input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );
+
+ if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
+ input_Control( p_input, INPUT_ADD_INFO, _("General"),
+ _("Author"), p_meta->value[i] );
+
+ input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"),
+ _(p_meta->name[i]), "%s", p_meta->value[i] );
+ }
+
for( i = 0; i < p_meta->i_track; i++ )
{
vlc_meta_t *tk = p_meta->track[i];
int j;
- msg_Dbg( p_input, " - track[%d]:", i );
if( tk->i_meta > 0 )
{
char *psz_cat = malloc( strlen(_("Stream")) + 10 );
- sprintf( psz_cat, "%s %d", _("Stream"), i );
+ msg_Dbg( p_input, " - track[%d]:", i );
+
+ sprintf( psz_cat, "%s %d", _("Stream"), i );
for( j = 0; j < tk->i_meta; j++ )
{
msg_Dbg( p_input, " - '%s' = '%s'", _(tk->name[j]),
}
}
- if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
+ if( p_input->p_sout && p_input->p_sout->p_meta == NULL )
{
- p_input->stream.p_sout->p_meta = p_meta;
+ p_input->p_sout->p_meta = p_meta;
}
else
{
vlc_meta_Delete( p_meta );
}
}
- if( p_meta_user ) vlc_meta_Delete( p_meta_user );
- /* Get length */
- if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
- i_length > 0 )
- {
- char psz_buffer[MSTRTIME_MAX_SIZE];
-
- vlc_mutex_lock( &p_input->p_item->lock );
- p_input->p_item->i_duration = i_length;
- vlc_mutex_unlock( &p_input->p_item->lock );
-
- input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
- msecstotimestr( psz_buffer, i_length / 1000 ) );
-
- /* Set start time */
- var_Get( p_input, "start-time", &val );
- if( val.i_int > 0 )
- {
- double f_pos = val.i_int * I64C(1000000) / (double)i_length;
+ msg_Dbg( p_input, "`%s' sucessfully opened",
+ p_input->input.p_item->psz_uri );
- if( f_pos >= 1.0 )
- {
- msg_Warn( p_input, "invalid start-time, ignored (start-time "
- ">= media length)" );
- }
- else
- {
- p_input->stream.p_selected_area->i_seek =
- (int64_t)( f_pos * (double)p_input->stream.p_selected_area->i_size );
+ /* initialization is complete */
+ p_input->i_state = PLAYING_S;
- msg_Dbg( p_input, "start-time %ds (%2.2f)", val.i_int, f_pos );
- }
- }
- }
+ val.i_int = PLAYING_S;
+ var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
- /* Get fps */
- if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
- {
- i_microsecondperframe = 0;
- }
- else
- {
- i_microsecondperframe = (int64_t)( (double)1000000.0 / (double)f_fps );
- }
+ return VLC_SUCCESS;
- /* Look for and add subtitle files */
- var_Get( p_input, "sub-file", &val );
- if( val.psz_string && *val.psz_string )
- {
- subtitle_demux_t *p_sub;
+error:
+ if( p_input->p_es_out )
+ input_EsOutDelete( p_input->p_es_out );
- msg_Dbg( p_input, "force subtitle: %s", val.psz_string );
- if( ( p_sub = subtitle_New( p_input, strdup(val.psz_string),
- i_microsecondperframe ) ) )
- {
- p_sub_toselect = p_sub;
- TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
- }
- }
- psz_sub_file = val.psz_string;
+ if( p_input->p_sout )
+ sout_DeleteInstance( p_input->p_sout );
- var_Get( p_input, "sub-autodetect-file", &val );
- var_Get( p_input, "sub-autodetect-path", &val1 );
- if( val.b_bool )
- {
- subtitle_demux_t *p_sub;
- int i;
- char **tmp = subtitles_Detect( p_input, val1.psz_string, p_input->psz_name );
- char **tmp2 = tmp;
- for( i = 0; *tmp2 != NULL; i++ )
- {
- if( psz_sub_file == NULL || strcmp( psz_sub_file, *tmp2 ) )
- {
- if( ( p_sub = subtitle_New( p_input, *tmp2,
- i_microsecondperframe ) ) )
- {
- TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub,
- p_sub );
- }
- }
- free( *tmp2++ );
- }
- free( tmp );
- free( val1.psz_string );
- }
- if( psz_sub_file ) free( psz_sub_file );
+ /* Mark them deleted */
+ p_input->input.p_demux = NULL;
+ p_input->input.p_stream = NULL;
+ p_input->input.p_access = NULL;
+ p_input->p_es_out = NULL;
+ p_input->p_sout = NULL;
- es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
- val.b_bool = VLC_FALSE;
- if( p_input->stream.p_sout )
- {
- var_Get( p_input, "sout-all", &val );
- }
- es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
- val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
- if( p_sub_toselect )
- {
- es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
- p_sub_toselect->p_es, VLC_TRUE );
- }
-#endif
+ return VLC_EGENERIC;
}
/*****************************************************************************
static void End( input_thread_t * p_input )
{
vlc_value_t val;
+ int i;
msg_Dbg( p_input, "closing `%s'",
p_input->input.p_item->psz_uri );
/* Clean control variables */
input_ControlVarClean( p_input );
- /* Unload all modules */
- if( p_input->input.p_demux )
- demux2_Delete( p_input->input.p_demux );
-
- if( p_input->input.p_stream )
- stream_AccessDelete( p_input->input.p_stream );
+ /* Clean up master */
+ InputSourceClean( p_input, &p_input->input );
- if( p_input->input.p_access )
- access2_Delete( p_input->input.p_access );
+ /* Delete slave */
+ for( i = 0; i < p_input->i_slave; i++ )
+ {
+ InputSourceClean( p_input, p_input->slave[i] );
+ free( p_input->slave[i] );
+ }
+ if( p_input->slave ) free( p_input->slave );
+ /* Unload all modules */
if( p_input->p_es_out )
input_EsOutDelete( p_input->p_es_out );
vlc_object_release( p_pl );
}
- /* TODO subs */
-#if 0
- /* Destroy subtitles demuxers */
- if( p_input->p_sys )
- {
- for( i = 0; i < p_input->p_sys->i_sub; i++ )
- {
- subtitle_Close( p_input->p_sys->sub[i] );
- }
- if( p_input->p_sys->i_sub > 0 )
- {
- free( p_input->p_sys->sub );
- }
-
- }
-#endif
-
- /* Free input_thread_sys_t */
- free( p_input->p_sys );
-
/* Tell we're dead */
p_input->b_dead = VLC_TRUE;
}
const int i_ct = p_input->control[i].i_type;
/* XXX We can't merge INPUT_CONTROL_SET_ES */
- msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control, i_lt, i_ct );
+ msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control,
+ i_lt, i_ct );
if( i_lt == i_ct &&
( i_ct == INPUT_CONTROL_SET_STATE ||
i_ct == INPUT_CONTROL_SET_RATE ||
}
}
-static vlc_bool_t Control( input_thread_t *p_input, int i_type, vlc_value_t val )
+static vlc_bool_t Control( input_thread_t *p_input, int i_type,
+ vlc_value_t val )
{
vlc_bool_t b_force_update = VLC_FALSE;
else
{
/* Should not fail */
- demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos );
+ demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_POSITION, &f_pos );
f_pos += val.f_float;
}
if( f_pos < 0.0 ) f_pos = 0.0;
if( f_pos > 1.0 ) f_pos = 1.0;
- if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION, f_pos ) )
+ if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
+ f_pos ) )
{
- msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) %2.1f%% failed",
- f_pos * 100 );
+ msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
+ "%2.1f%% failed", f_pos * 100 );
}
else
{
+ if( p_input->i_slave > 0 )
+ SlaveSeek( p_input );
+
input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
b_force_update = VLC_TRUE;
}
if( i_ret )
{
- msg_Err( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) %lld failed",
- i_time );
+ msg_Err( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) "I64Fd
+ " failed", i_time );
}
else
{
+ if( p_input->i_slave > 0 )
+ SlaveSeek( p_input );
+
input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
/* Reset clock */
es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
}
- else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S && p_input->b_can_pause )
+ else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S &&
+ p_input->b_can_pause )
{
int i_ret;
if( p_input->input.p_access )
i_rate = INPUT_RATE_MAX;
}
if( i_rate != INPUT_RATE_DEFAULT &&
- ( !p_input->b_can_pace_control || !p_input->b_out_pace_control ) )
+ ( !p_input->b_can_pace_control ||
+ !p_input->b_out_pace_control ) )
{
msg_Dbg( p_input, "cannot change rate" );
i_rate = INPUT_RATE_DEFAULT;
case INPUT_CONTROL_SET_ES:
/* No need to force update, es_out does it if needed */
- es_out_Control( p_input->p_es_out,
- ES_OUT_SET_ES, input_EsOutGetFromID( p_input->p_es_out, val.i_int ) );
+ es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
+ input_EsOutGetFromID( p_input->p_es_out,
+ val.i_int ) );
+ break;
+
+ case INPUT_CONTROL_SET_AUDIO_DELAY:
+ input_EsOutSetDelay( p_input->p_es_out,
+ AUDIO_ES, val.i_time );
+ var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
+ break;
+
+ case INPUT_CONTROL_SET_SPU_DELAY:
+ input_EsOutSetDelay( p_input->p_es_out,
+ SPU_ES, val.i_time );
+ var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
break;
case INPUT_CONTROL_SET_TITLE:
if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
i_seekpoint = p_demux->info.i_seekpoint - 1;
- else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+ 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->input.title[p_demux->info.i_title]->i_seekpoint )
+ if( i_seekpoint >= 0 && i_seekpoint <
+ p_input->input.title[p_demux->info.i_title]->i_seekpoint )
{
demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
else
i_seekpoint = val.i_int;
- if( i_seekpoint >= 0 &&
- i_seekpoint < p_input->input.title[p_access->info.i_title]->i_seekpoint )
+ if( i_seekpoint >= 0 && i_seekpoint <
+ p_input->input.title[p_access->info.i_title]->i_seekpoint )
{
access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint );
stream_AccessReset( p_input->input.p_stream );
p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
}
+/*****************************************************************************
+ * InputSourceNew:
+ *****************************************************************************/
+static input_source_t *InputSourceNew( input_thread_t *p_input )
+{
+ input_source_t *in = malloc( sizeof( input_source_t ) );
+
+ in->p_item = NULL;
+ in->p_access = NULL;
+ in->p_stream = NULL;
+ in->p_demux = NULL;
+ in->b_title_demux = VLC_FALSE;
+ in->i_title = 0;
+ in->title = NULL;
+ in->b_can_pace_control = VLC_TRUE;
+ in->b_eof = VLC_FALSE;
+ in->i_cr_average = 0;
+
+ return in;
+}
+
+/*****************************************************************************
+ * InputSourceInit:
+ *****************************************************************************/
+static int InputSourceInit( input_thread_t *p_input,
+ input_source_t *in, char *psz_mrl,
+ char *psz_forced_demux )
+{
+ char *psz_dup = strdup( psz_mrl );
+ char *psz_access;
+ char *psz_demux;
+ char *psz_path;
+ vlc_value_t val;
+
+ /* Split uri */
+ MRLSplit( 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 );
+
+ if( psz_forced_demux && *psz_forced_demux )
+ psz_demux = psz_forced_demux;
+
+ /* Try access_demux if no demux given */
+ if( *psz_access && *psz_demux == '\0' )
+ {
+ in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
+ NULL, p_input->p_es_out );
+ }
+
+ if( in->p_demux )
+ {
+ int64_t i_pts_delay;
+
+ /* Get infos from access_demux */
+ demux2_Control( in->p_demux,
+ DEMUX_GET_PTS_DELAY, &i_pts_delay );
+ p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
+
+ in->b_title_demux = VLC_TRUE;
+ if( demux2_Control( in->p_demux,
+ DEMUX_GET_TITLE_INFO,
+ &in->title, &in->i_title ) )
+ {
+ 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 );
+
+ /* FIXME todo
+ demux2_Control( in->p_demux, DEMUX_CAN_SEEK,
+ &val.b_bool );
+ */
+ }
+ else
+ {
+ int64_t i_pts_delay;
+
+ /* Now try a real access */
+ 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, '%' ) )
+ {
+ DecodeUrl( psz_path );
+
+ msg_Dbg( p_input, "retying with access `%s' demux `%s' path `%s'",
+ psz_access, psz_demux, psz_path );
+
+ in->p_access = access2_New( p_input,
+ psz_access, psz_demux, psz_path );
+ }
+#ifndef WIN32 /* Remove this gross hack from the win32 build as colons
+ * are forbidden in filenames on Win32. */
+
+ /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
+ if( in->p_access == NULL &&
+ *psz_access == '\0' && ( *psz_demux || *psz_path ) )
+ {
+ free( psz_dup );
+ psz_dup = strdup( psz_mrl );
+ psz_access = "";
+ psz_demux = "";
+ psz_path = psz_dup;
+
+ in->p_access = access2_New( p_input,
+ psz_access, psz_demux, psz_path );
+ }
+#endif
+
+ if( in->p_access == NULL )
+ {
+ msg_Err( p_input, "no suitable access module for `%s'", psz_mrl );
+ goto error;
+ }
+
+ /* Get infos from access */
+ access2_Control( in->p_access,
+ ACCESS_GET_PTS_DELAY, &i_pts_delay );
+ p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
+
+ in->b_title_demux = VLC_FALSE;
+ if( access2_Control( in->p_access,
+ ACCESS_GET_TITLE_INFO,
+ &in->title, &in->i_title ) )
+ {
+ in->i_title = 0;
+ in->title = NULL;
+ }
+ access2_Control( in->p_access, ACCESS_CAN_CONTROL_PACE,
+ &in->b_can_pace_control );
+ access2_Control( in->p_access, ACCESS_CAN_PAUSE,
+ &in->b_can_pause );
+ access2_Control( in->p_access, ACCESS_CAN_SEEK,
+ &val.b_bool );
+ var_Set( p_input, "seekable", val );
+
+ /* Create the stream_t */
+ in->p_stream = stream_AccessNew( in->p_access );
+ if( in->p_stream == NULL )
+ {
+ msg_Warn( p_input, "cannot create a stream_t from access" );
+ goto error;
+ }
+
+ /* Open a demuxer */
+ if( *psz_demux == '\0' && *in->p_access->psz_demux )
+ {
+ psz_demux = in->p_access->psz_demux;
+ }
+ in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
+ in->p_stream, p_input->p_es_out );
+ if( in->p_demux == NULL )
+ {
+ msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
+ psz_access, psz_demux, psz_path );
+ goto error;
+ }
+
+ /* TODO get title from demux */
+ if( in->i_title <= 0 )
+ {
+ if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
+ &in->title, &in->i_title ) )
+ {
+ in->i_title = 0;
+ in->title = NULL;
+ }
+ else
+ {
+ in->b_title_demux = VLC_TRUE;
+ }
+ }
+ }
+ free( psz_dup );
+ return VLC_SUCCESS;
+
+error:
+ if( in->p_demux )
+ demux2_Delete( in->p_demux );
+
+ if( in->p_stream )
+ stream_AccessDelete( in->p_stream );
+
+ if( in->p_access )
+ access2_Delete( in->p_access );
+ free( psz_dup );
+
+ return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * InputSourceClean:
+ *****************************************************************************/
+static void InputSourceClean( input_thread_t *p_input, input_source_t *in )
+{
+ if( in->p_demux )
+ demux2_Delete( in->p_demux );
+
+ if( in->p_stream )
+ stream_AccessDelete( in->p_stream );
+
+ if( in->p_access )
+ access2_Delete( in->p_access );
+
+ if( in->i_title > 0 )
+ {
+ int i;
+ for( i = 0; i < in->i_title; i++ )
+ {
+ vlc_input_title_Delete( in->title[i] );
+ }
+ free( in->title );
+ }
+}
+
+static void SlaveDemux( input_thread_t *p_input )
+{
+ int64_t i_time;
+ int i;
+ if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
+ {
+ msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
+ return;
+ }
+
+ for( i = 0; i < p_input->i_slave; i++ )
+ {
+ input_source_t *in = p_input->slave[i];
+ int i_ret = 1;
+
+ if( in->b_eof )
+ continue;
+
+ if( demux2_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
+ {
+ for( ;; )
+ {
+ int64_t i_stime;
+ if( demux2_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
+ {
+ msg_Err( p_input, "slave[%d] doesn't like "
+ "DEMUX_GET_TIME -> EOF", i );
+ i_ret = 0;
+ break;
+ }
+
+ if( i_stime >= i_time )
+ break;
+
+ if( ( i_ret = in->p_demux->pf_demux( in->p_demux ) ) <= 0 )
+ break;
+ }
+ }
+ else
+ {
+ i_ret = in->p_demux->pf_demux( in->p_demux );
+ }
+
+ if( i_ret <= 0 )
+ {
+ msg_Dbg( p_input, "slave %d EOF", i );
+ in->b_eof = VLC_TRUE;
+ }
+ }
+}
+
+static void SlaveSeek( input_thread_t *p_input )
+{
+ int64_t i_time;
+ int i;
+
+ if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
+ {
+ msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
+ return;
+ }
+
+ for( i = 0; i < p_input->i_slave; i++ )
+ {
+ input_source_t *in = p_input->slave[i];
+
+ if( demux2_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
+ {
+ msg_Err( p_input, "seek failed for slave %d -> EOF", i );
+ in->b_eof = VLC_TRUE;
+ }
+ }
+}
+/*****************************************************************************
+ * InputMetaUser:
+ *****************************************************************************/
+static vlc_meta_t *InputMetaUser( input_thread_t *p_input )
+{
+ vlc_meta_t *p_meta;
+ vlc_value_t val;
+
+ if( ( p_meta = vlc_meta_New() ) == NULL )
+ return NULL;
+
+ /* Get meta information from user */
+#define GET_META( c, s ) \
+ var_Get( p_input, (s), &val ); \
+ if( *val.psz_string ) \
+ vlc_meta_Add( p_meta, c, val.psz_string ); \
+ free( val.psz_string )
+
+ GET_META( VLC_META_TITLE, "meta-title" );
+ GET_META( VLC_META_AUTHOR, "meta-author" );
+ GET_META( VLC_META_ARTIST, "meta-artist" );
+ GET_META( VLC_META_GENRE, "meta-genre" );
+ GET_META( VLC_META_COPYRIGHT, "meta-copyright" );
+ GET_META( VLC_META_DESCRIPTION, "meta-description" );
+ GET_META( VLC_META_DATE, "meta-date" );
+ GET_META( VLC_META_URL, "meta-url" );
+#undef GET_META
+
+ return p_meta;
+}
+
/*****************************************************************************
* DecodeUrl: decode a given encoded url
*****************************************************************************/
return;
}
+static void MRLSplit( input_thread_t *p_input, char *psz_dup,
+ char **ppsz_access, char **ppsz_demux, char **ppsz_path )
+{
+ char *psz_access = NULL;
+ char *psz_demux = NULL;
+ char *psz_path = NULL;
+ char *psz;
+
+ psz = strchr( psz_dup, ':' );
+
+#if defined( WIN32 ) || defined( UNDER_CE )
+ if( psz - psz_dup == 1 )
+ {
+ msg_Warn( p_input, "drive letter %c: found in source string",
+ psz_dup[0] );
+ psz_path = psz_dup;
+ }
+ else
+#endif
+
+ if( psz )
+ {
+ *psz++ = '\0';
+ if( psz[0] == '/' && psz[1] == '/' )
+ psz += 2;
+
+ psz_path = psz;
+
+ psz = strchr( psz_dup, '/' );
+ if( psz )
+ {
+ *psz++ = '\0';
+ psz_demux = psz;
+ }
+
+ psz_access = psz_dup;
+ }
+ else
+ {
+ psz_path = psz_dup;
+ }
+
+ if( psz_access == NULL )
+ *ppsz_access = "";
+ else
+ *ppsz_access = psz_access;
+
+ if( psz_demux == NULL )
+ *ppsz_demux = "";
+ else
+ *ppsz_demux = psz_demux;
+ if( psz_path == NULL )
+ *ppsz_path = "";
+ else
+ *ppsz_path = psz_path;
+}