+ msg_Dbg( p_input, " - '%s' = '%s'", _(tk->name[j]),
+ tk->value[j] );
+
+ input_Control( p_input, INPUT_ADD_INFO, psz_cat,
+ _(tk->name[j]), "%s", tk->value[j] );
+ }
+ }
+ }
+
+ if( p_input->p_sout && p_input->p_sout->p_meta == NULL )
+ {
+ p_input->p_sout->p_meta = p_meta;
+ }
+ else
+ {
+ vlc_meta_Delete( p_meta );
+ }
+ }
+ else if( p_meta ) vlc_meta_Delete( p_meta );
+
+ 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->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;
+}
+
+/*****************************************************************************
+ * Error: RunThread() error loop
+ *****************************************************************************
+ * This function is called when an error occurred during thread main's loop.
+ *****************************************************************************/
+static void Error( input_thread_t *p_input )
+{
+ while( !p_input->b_die )
+ {
+ /* Sleep a while */
+ msleep( INPUT_IDLE_SLEEP );
+ }
+}
+
+/*****************************************************************************
+ * End: end the input thread
+ *****************************************************************************/
+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 );
+
+ /* We are at the end */
+ p_input->i_state = END_S;
+
+ val.i_int = END_S;
+ var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+
+ /* Clean control variables */
+ input_ControlVarClean( p_input );
+
+ /* Clean up master */
+ InputSourceClean( p_input, &p_input->input );
+
+ /* 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 );
+
+ /* Close optional stream output instance */
+ if( p_input->p_sout )
+ {
+ vlc_object_t *p_pl =
+ vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
+ vlc_value_t keep;
+
+ if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
+ {
+ /* attach sout to the playlist */
+ msg_Warn( p_input, "keeping sout" );
+ vlc_object_detach( p_input->p_sout );
+ vlc_object_attach( p_input->p_sout, p_pl );
+ }
+ else
+ {
+ msg_Warn( p_input, "destroying sout" );
+ sout_DeleteInstance( p_input->p_sout );
+ }
+ if( p_pl )
+ vlc_object_release( p_pl );
+ }
+
+ /* Tell we're dead */
+ p_input->b_dead = VLC_TRUE;
+}
+
+/*****************************************************************************
+ * Control
+ *****************************************************************************/
+static inline int ControlPopNoLock( input_thread_t *p_input,
+ int *pi_type, vlc_value_t *p_val )
+{
+ if( p_input->i_control <= 0 )
+ {
+ return VLC_EGENERIC;
+ }
+
+ *pi_type = p_input->control[0].i_type;
+ *p_val = p_input->control[0].val;
+
+ p_input->i_control--;
+ if( p_input->i_control > 0 )
+ {
+ int i;
+
+ for( i = 0; i < p_input->i_control; i++ )
+ {
+ p_input->control[i].i_type = p_input->control[i+1].i_type;
+ p_input->control[i].val = p_input->control[i+1].val;
+ }
+ }
+
+ return VLC_SUCCESS;
+}
+
+static void ControlReduce( input_thread_t *p_input )
+{
+ int i;
+ for( i = 1; i < p_input->i_control; i++ )
+ {
+ const int i_lt = p_input->control[i-1].i_type;
+ 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 );
+ if( i_lt == i_ct &&
+ ( i_ct == INPUT_CONTROL_SET_STATE ||
+ i_ct == INPUT_CONTROL_SET_RATE ||
+ i_ct == INPUT_CONTROL_SET_POSITION ||
+ i_ct == INPUT_CONTROL_SET_TIME ||
+ i_ct == INPUT_CONTROL_SET_PROGRAM ||
+ i_ct == INPUT_CONTROL_SET_TITLE ||
+ i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
+ i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
+ {
+ int j;
+ msg_Dbg( p_input, "merged at %d", i );
+ /* Remove the i-1 */
+ for( j = i; j < p_input->i_control; j++ )
+ p_input->control[j-1] = p_input->control[j];
+ p_input->i_control--;
+ }
+ else
+ {
+ /* TODO but that's not that important
+ - merge SET_X with SET_X_CMD
+ - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
+ - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
+ - ?
+ */
+ }
+ }
+}
+
+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;
+
+ switch( i_type )
+ {
+ case INPUT_CONTROL_SET_DIE:
+ msg_Dbg( p_input, "control: INPUT_CONTROL_SET_DIE proceed" );
+ /* Mark all submodules to die */
+ if( p_input->input.p_access )
+ p_input->input.p_access->b_die = VLC_TRUE;
+ if( p_input->input.p_stream )
+ p_input->input.p_stream->b_die = VLC_TRUE;
+ p_input->input.p_demux->b_die = VLC_TRUE;
+
+ p_input->b_die = VLC_TRUE;
+ break;
+
+ case INPUT_CONTROL_SET_POSITION:
+ case INPUT_CONTROL_SET_POSITION_OFFSET:
+ {
+ double f_pos;
+ if( i_type == INPUT_CONTROL_SET_POSITION )
+ {
+ f_pos = val.f_float;
+ }
+ else
+ {
+ /* Should not fail */
+ 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 ) )
+ {
+ 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;
+ }
+ break;
+ }
+
+ case INPUT_CONTROL_SET_TIME:
+ case INPUT_CONTROL_SET_TIME_OFFSET:
+ {
+ int64_t i_time;
+ int i_ret;
+
+ if( i_type == INPUT_CONTROL_SET_TIME )
+ {
+ i_time = val.i_time;
+ }
+ else
+ {
+ /* Should not fail */
+ demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_TIME, &i_time );
+ i_time += val.i_time;
+ }
+ if( i_time < 0 ) i_time = 0;
+ i_ret = demux2_Control( p_input->input.p_demux,
+ DEMUX_SET_TIME, i_time );
+ if( i_ret )
+ {
+ int64_t i_length;
+ /* Emulate it with a SET_POS */