]> git.sesse.net Git - vlc/blobdiff - src/input/input.c
Privatized p_input->b_can_pace_control.
[vlc] / src / input / input.c
index adbd75de0735369312566d96653e66b10ea2890c..53dcdbed86671122a6f91f724a4747e26c447fe2 100644 (file)
@@ -43,6 +43,7 @@
 #include "demux.h"
 #include "stream.h"
 #include "item.h"
+#include "ressource.h"
 
 #include <vlc_sout.h>
 #include "../stream_output/stream_output.h"
@@ -65,9 +66,8 @@ static  void *Run            ( vlc_object_t *p_this );
 static  void *RunAndDestroy  ( vlc_object_t *p_this );
 
 static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
-                                  const char *, bool, sout_instance_t * );
+                                  const char *, bool, input_ressource_t * );
 static  int             Init    ( input_thread_t *p_input );
-static void             WaitDie   ( input_thread_t *p_input );
 static void             End     ( input_thread_t *p_input );
 static void             MainLoop( input_thread_t *p_input );
 
@@ -98,8 +98,9 @@ static void SlaveSeek( input_thread_t *p_input );
 
 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 );
-static char *InputGetExtraFiles( input_thread_t *p_input,
-                                 const char *psz_access, const char *psz_path );
+static void InputGetExtraFiles( input_thread_t *p_input,
+                                int *pi_list, char ***pppsz_list,
+                                const char *psz_access, const char *psz_path );
 
 static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment,
                               int i_new, input_attachment_t **pp_new );
@@ -116,7 +117,7 @@ static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO f
  *****************************************************************************/
 static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
                                const char *psz_header, bool b_quick,
-                               sout_instance_t *p_sout )
+                               input_ressource_t *p_ressource )
 {
     static const char input_name[] = "input";
     input_thread_t *p_input = NULL;                 /* thread descriptor */
@@ -162,23 +163,17 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     p_input->b_preparsing = b_quick;
     p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
 
-    /* Init events */
-    vlc_event_manager_t * p_em = &p_input->p->event_manager;
-    vlc_event_manager_init_with_vlc_object( p_em, p_input );
-    vlc_event_manager_register_event_type( p_em, vlc_InputStateChanged );
-    vlc_event_manager_register_event_type( p_em, vlc_InputSelectedStreamChanged );
-
     /* Init Common fields */
     p_input->b_eof = false;
-    p_input->b_can_pace_control = true;
+    p_input->p->b_can_pace_control = true;
     p_input->p->i_start = 0;
-    p_input->i_time     = 0;
+    p_input->p->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;
-    p_input->i_state = INIT_S;
+    p_input->p->i_state = INIT_S;
     p_input->p->i_rate = INPUT_RATE_DEFAULT;
     p_input->p->b_recording = false;
     memset( &p_input->p->bookmark, 0, sizeof(p_input->p->bookmark) );
@@ -188,7 +183,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     p_input->p->p_es_out = NULL;
     p_input->p->p_sout   = NULL;
     p_input->p->b_out_pace_control = false;
-    p_input->i_pts_delay = 0;
+    p_input->p->i_pts_delay = 0;
     p_input->p->i_cr_average = 0;
 
     vlc_gc_incref( p_item ); /* Released in Destructor() */
@@ -217,6 +212,13 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     p_input->p->i_slave = 0;
     p_input->p->slave   = NULL;
 
+    /* */
+    if( p_ressource )
+        p_input->p->p_ressource = p_ressource;
+    else
+        p_input->p->p_ressource = input_ressource_New();
+    input_ressource_SetInput( p_input->p->p_ressource, p_input );
+
     /* Init control buffer */
     vlc_mutex_init( &p_input->p->lock_control );
     vlc_cond_init( &p_input->p->wait_control );
@@ -298,9 +300,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
         p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;
 
     /* */
-    if( p_sout )
-        p_input->p->p_sout = p_sout;
-
     memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
     vlc_mutex_init( &p_input->p->counters.counters_lock );
 
@@ -324,14 +323,12 @@ static void Destructor( input_thread_t * p_input )
     free( psz_name );
 #endif
 
-    vlc_event_manager_fini( &p_input->p->event_manager );
-
     stats_TimerDump( p_input, STATS_TIMER_INPUT_LAUNCHING );
     stats_TimerClean( p_input, STATS_TIMER_INPUT_LAUNCHING );
-#ifdef ENABLE_SOUT
-    if( p_input->p->p_sout )
-        sout_DeleteInstance( p_input->p->p_sout );
-#endif
+
+    if( p_input->p->p_ressource )
+        input_ressource_Delete( p_input->p->p_ressource );
+
     vlc_gc_decref( p_input->p->p_item );
 
     vlc_mutex_destroy( &p_input->p->counters.counters_lock );
@@ -358,11 +355,11 @@ input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
 /* */
 input_thread_t *__input_CreateThreadExtended( vlc_object_t *p_parent,
                                               input_item_t *p_item,
-                                              const char *psz_log, sout_instance_t *p_sout )
+                                              const char *psz_log, input_ressource_t *p_ressource )
 {
     input_thread_t *p_input;
 
-    p_input = Create( p_parent, p_item, psz_log, false, p_sout );
+    p_input = Create( p_parent, p_item, psz_log, false, p_ressource );
     if( !p_input )
         return NULL;
 
@@ -458,13 +455,17 @@ void input_StopThread( input_thread_t *p_input )
     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
 }
 
-sout_instance_t *input_DetachSout( input_thread_t *p_input )
+input_ressource_t *input_DetachRessource( input_thread_t *p_input )
 {
     assert( p_input->b_dead );
-    sout_instance_t *p_sout = p_input->p->p_sout;
-    vlc_object_detach( p_sout );
+
+    input_ressource_t *p_ressource = p_input->p->p_ressource;
+    input_ressource_SetInput( p_ressource, NULL );
+
+    p_input->p->p_ressource = NULL;
     p_input->p->p_sout = NULL;
-    return p_sout;
+
+    return p_ressource;
 }
 
 /**
@@ -487,9 +488,12 @@ static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj )
     vlc_list_t *p_list;
     int i;
 
+    /* FIXME ObjectKillChildrens seems a very bad idea in fact */
     if( p_obj->i_object_type == VLC_OBJECT_VOUT ||
         p_obj->i_object_type == VLC_OBJECT_AOUT ||
-        p_obj == VLC_OBJECT(p_input->p->p_sout) )
+        p_obj == VLC_OBJECT(p_input->p->p_sout) ||
+        p_obj->i_object_type == VLC_OBJECT_DECODER ||
+        p_obj->i_object_type == VLC_OBJECT_PACKETIZER )
         return;
 
     vlc_object_kill( p_obj );
@@ -511,23 +515,16 @@ static void *Run( vlc_object_t *p_this )
     const int canc = vlc_savecancel();
 
     if( Init( p_input ) )
-    {
-        /* If we failed, wait before we are killed, and exit */
-        WaitDie( p_input );
         goto exit;
-    }
 
     MainLoop( p_input );
 
-    /* Wait until we are asked to die */
-    if( !p_input->b_die )
-        WaitDie( p_input );
-
     /* Clean up */
     End( p_input );
 
 exit:
-    p_input->b_dead = true;
+    /* Tell we're dead */
+    input_SendEventDead( p_input );
     vlc_restorecancel( canc );
     return NULL;
 }
@@ -571,7 +568,7 @@ static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, mtime_t *p
 
     *pb_changed = false;
 
-    if( ( p_input->p->i_stop > 0 && p_input->i_time >= p_input->p->i_stop ) ||
+    if( ( p_input->p->i_stop > 0 && p_input->p->i_time >= p_input->p->i_stop ) ||
         ( p_input->p->i_run > 0 && *pi_start_mdate+p_input->p->i_run < mdate() ) )
         i_ret = 0; /* EOF */
     else
@@ -685,6 +682,7 @@ static void MainLoopInterface( input_thread_t *p_input )
     if( demux_Control( p_input->p->input.p_demux,
                        DEMUX_GET_TIME, &i_time ) )
         i_time = 0;
+    p_input->p->i_time = i_time;
 
     if( demux_Control( p_input->p->input.p_demux,
                        DEMUX_GET_LENGTH, &i_length ) )
@@ -742,10 +740,10 @@ static void MainLoop( input_thread_t *p_input )
         /* Demux data */
         b_force_update = false;
         i_wakeup = 0;
-        /* FIXME if p_input->i_state == PAUSE_S the access/access_demux
+        /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
          * is paused -> this may cause problem with some of them
          * The same problem can be seen when seeking while paused */
-        b_paused = p_input->i_state == PAUSE_S &&
+        b_paused = p_input->p->i_state == PAUSE_S &&
                    !es_out_GetBuffering( p_input->p->p_es_out );
 
         if( !b_paused )
@@ -847,46 +845,21 @@ static void InitStatistics( input_thread_t * p_input )
 #ifdef ENABLE_SOUT
 static int InitSout( input_thread_t * p_input )
 {
-    char *psz;
-
-    if( p_input->b_preparsing ) return VLC_SUCCESS;
+    if( p_input->b_preparsing )
+        return VLC_SUCCESS;
 
     /* Find a usable sout and attach it to p_input */
-    psz = var_GetNonEmptyString( p_input, "sout" );
+    char *psz = var_GetNonEmptyString( p_input, "sout" );
     if( psz && strncasecmp( p_input->p->p_item->psz_uri, "vlc:", 4 ) )
     {
-        /* Check the validity of the provided sout */
-        if( p_input->p->p_sout )
-        {
-            if( strcmp( p_input->p->p_sout->psz_sout, psz ) )
-            {
-                msg_Dbg( p_input, "destroying unusable sout" );
-
-                sout_DeleteInstance( p_input->p->p_sout );
-                p_input->p->p_sout = NULL;
-            }
-        }
-
-        if( p_input->p->p_sout )
+        p_input->p->p_sout  = input_ressource_RequestSout( p_input->p->p_ressource, NULL, psz );
+        if( !p_input->p->p_sout )
         {
-            /* Reuse it */
-            msg_Dbg( p_input, "sout keep: reusing sout" );
-            msg_Dbg( p_input, "sout keep: you probably want to use "
-                              "gather stream_out" );
-            vlc_object_attach( p_input->p->p_sout, p_input );
-        }
-        else
-        {
-            /* 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 );
-                msg_Err( p_input, "cannot start stream output instance, " \
-                                  "aborting" );
-                free( psz );
-                return VLC_EGENERIC;
-            }
+            input_ChangeState( p_input, ERROR_S );
+            msg_Err( p_input, "cannot start stream output instance, " \
+                              "aborting" );
+            free( psz );
+            return VLC_EGENERIC;
         }
         if( libvlc_stats( p_input ) )
         {
@@ -898,12 +871,9 @@ static int InitSout( input_thread_t * p_input )
                          1000000;
         }
     }
-    else if( p_input->p->p_sout )
+    else
     {
-        msg_Dbg( p_input, "destroying useless sout" );
-
-        sout_DeleteInstance( p_input->p->p_sout );
-        p_input->p->p_sout = NULL;
+        input_ressource_RequestSout( p_input->p->p_ressource, NULL, NULL );
     }
     free( psz );
 
@@ -931,22 +901,22 @@ static void InitTitle( input_thread_t * p_input )
     }
 
     /* Global flag */
-    p_input->b_can_pace_control    = p_master->b_can_pace_control;
+    p_input->p->b_can_pace_control    = p_master->b_can_pace_control;
     p_input->p->b_can_pause        = p_master->b_can_pause;
     p_input->p->b_can_rate_control = p_master->b_can_rate_control;
 
     /* Fix pts delay */
-    if( p_input->i_pts_delay < 0 )
-        p_input->i_pts_delay = 0;
+    if( p_input->p->i_pts_delay < 0 )
+        p_input->p->i_pts_delay = 0;
 
     /* If the desynchronisation requested by the user is < 0, we need to
      * cache more data. */
     const int i_desynch = var_GetInteger( p_input, "audio-desync" );
     if( i_desynch < 0 )
-        p_input->i_pts_delay -= i_desynch * 1000;
+        p_input->p->i_pts_delay -= i_desynch * 1000;
 
     /* Update cr_average depending on the caching */
-    p_input->p->i_cr_average *= (10 * p_input->i_pts_delay / 200000);
+    p_input->p->i_cr_average *= (10 * p_input->p->i_pts_delay / 200000);
     p_input->p->i_cr_average /= 10;
     if( p_input->p->i_cr_average < 10 )
         p_input->p->i_cr_average = 10;
@@ -1080,7 +1050,7 @@ static void LoadSlaves( input_thread_t *p_input )
         msg_Dbg( p_input, "adding slave input '%s'", psz );
 
         input_source_t *p_slave = InputSourceNew( p_input );
-        if( !InputSourceInit( p_input, p_slave, psz, NULL ) )
+        if( p_slave && !InputSourceInit( p_input, p_slave, psz, NULL ) )
             TAB_APPEND( p_input->p->i_slave, p_input->p->slave, p_slave );
         else
             free( p_slave );
@@ -1178,6 +1148,7 @@ static int Init( input_thread_t * p_input )
 
     /* */
     input_ChangeState( p_input, OPENING_S );
+    input_SendEventCache( p_input, 0.0 );
 
     /* */
     if( InputSourceInit( p_input, &p_input->p->input,
@@ -1210,7 +1181,7 @@ static int Init( input_thread_t * p_input )
     {
         p_input->p->b_out_pace_control = (p_input->p->p_sout->i_out_pace_nocontrol > 0);
 
-        if( p_input->b_can_pace_control && p_input->p->b_out_pace_control )
+        if( p_input->p->b_can_pace_control && p_input->p->b_out_pace_control )
         {
             /* We don't want a high input priority here or we'll
              * end-up sucking up all the CPU time */
@@ -1257,13 +1228,13 @@ error:
         es_out_Delete( p_input->p->p_es_out );
     if( p_input->p->p_es_out_display )
         es_out_Delete( p_input->p->p_es_out_display );
-#ifdef ENABLE_SOUT
-    if( p_input->p->p_sout )
+    if( p_input->p->p_ressource )
     {
-        vlc_object_detach( p_input->p->p_sout );
-        sout_DeleteInstance( p_input->p->p_sout );
+        if( p_input->p->p_sout )
+            input_ressource_RequestSout( p_input->p->p_ressource,
+                                         p_input->p->p_sout, NULL );
+        input_ressource_SetInput( p_input->p->p_ressource, NULL );
     }
-#endif
 
     if( !p_input->b_preparsing && libvlc_stats( p_input ) )
     {
@@ -1303,22 +1274,6 @@ error:
     return VLC_EGENERIC;
 }
 
-/*****************************************************************************
- * WaitDie: Wait until we are asked to die.
- *****************************************************************************
- * This function is called when an error occurred during thread main's loop.
- *****************************************************************************/
-static void WaitDie( input_thread_t *p_input )
-{
-    input_ChangeState( p_input, p_input->b_error ? ERROR_S : END_S );
-
-    /* Wait a die order */
-    vlc_object_lock( p_input );
-    while( vlc_object_alive( p_input ) )
-        vlc_object_wait( p_input );
-    vlc_object_unlock( p_input );
-}
-
 /*****************************************************************************
  * End: end the input thread
  *****************************************************************************/
@@ -1389,8 +1344,6 @@ static void End( input_thread_t * p_input )
             CL_CO( sout_sent_packets );
             CL_CO( sout_sent_bytes );
             CL_CO( sout_send_bitrate );
-
-            vlc_object_detach( p_input->p->p_sout );
         }
 #undef CL_CO
     }
@@ -1402,8 +1355,10 @@ static void End( input_thread_t * p_input )
         TAB_CLEAN( p_input->p->i_attachment, p_input->p->attachment );
     }
 
-    /* Tell we're dead */
-    p_input->b_dead = true;
+    /* */
+    input_ressource_RequestSout( p_input->p->p_ressource,
+                                 p_input->p->p_sout, NULL );
+    input_ressource_SetInput( p_input->p->p_ressource, NULL );
 }
 
 /*****************************************************************************
@@ -1537,7 +1492,7 @@ static void ControlPause( input_thread_t *p_input, mtime_t i_control_date )
         if( i_ret )
         {
             msg_Warn( p_input, "cannot set pause state" );
-            i_state = p_input->i_state;
+            i_state = p_input->p->i_state;
         }
     }
 
@@ -1548,7 +1503,7 @@ static void ControlPause( input_thread_t *p_input, mtime_t i_control_date )
         if( i_ret )
         {
             msg_Warn( p_input, "cannot set pause state at es_out level" );
-            i_state = p_input->i_state;
+            i_state = p_input->p->i_state;
         }
     }
 
@@ -1697,14 +1652,14 @@ static bool Control( input_thread_t *p_input, int i_type,
         }
 
         case INPUT_CONTROL_SET_STATE:
-            if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
-                ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
+            if( ( val.i_int == PLAYING_S && p_input->p->i_state == PAUSE_S ) ||
+                ( val.i_int == PAUSE_S && p_input->p->i_state == PAUSE_S ) )
             {
                 ControlUnpause( p_input, i_control_date );
 
                 b_force_update = true;
             }
-            else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S /* &&
+            else if( val.i_int == PAUSE_S && p_input->p->i_state == PLAYING_S /* &&
                      p_input->p->b_can_pause */ )
             {
                 ControlPause( p_input, i_control_date );
@@ -1716,7 +1671,7 @@ static bool Control( input_thread_t *p_input, int i_type,
                 b_force_update = true;
 
                 /* Correct "state" value */
-                input_ChangeState( p_input, p_input->i_state );
+                input_ChangeState( p_input, p_input->p->i_state );
             }
             else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
             {
@@ -1818,7 +1773,7 @@ static bool Control( input_thread_t *p_input, int i_type,
                 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 )
+                !p_input->p->b_can_pace_control && p_input->p->b_can_rate_control )
             {
                 int i_ret;
                 if( p_input->p->input.p_access )
@@ -1848,7 +1803,7 @@ static bool Control( input_thread_t *p_input, int i_type,
 
                 if( p_input->p->input.b_rescale_ts )
                 {
-                    const int i_rate_source = (p_input->b_can_pace_control || p_input->p->b_can_rate_control ) ? i_rate : INPUT_RATE_DEFAULT;
+                    const int i_rate_source = (p_input->p->b_can_pace_control || p_input->p->b_can_rate_control ) ? i_rate : INPUT_RATE_DEFAULT;
                     es_out_SetRate( p_input->p->p_es_out, i_rate_source, i_rate );
                 }
 
@@ -1932,8 +1887,8 @@ static bool Control( input_thread_t *p_input, int i_type,
                 {
                     es_out_SetTime( p_input->p->p_es_out, -1 );
 
-                    access_Control( p_access, ACCESS_SET_TITLE, i_title );
-                    stream_AccessReset( p_input->p->input.p_stream );
+                    stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS,
+                                    ACCESS_SET_TITLE, i_title );
                 }
             }
             break;
@@ -2011,9 +1966,8 @@ static bool Control( input_thread_t *p_input, int i_type,
                 {
                     es_out_SetTime( p_input->p->p_es_out, -1 );
 
-                    access_Control( p_access, ACCESS_SET_SEEKPOINT,
-                                    i_seekpoint );
-                    stream_AccessReset( p_input->p->input.p_stream );
+                    stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS,
+                                    ACCESS_SET_SEEKPOINT, i_seekpoint );
                 }
             }
             break;
@@ -2031,7 +1985,7 @@ static bool Control( input_thread_t *p_input, int i_type,
             {
                 input_source_t *slave = InputSourceNew( p_input );
 
-                if( !InputSourceInit( p_input, slave, val.psz_string, NULL ) )
+                if( slave && !InputSourceInit( p_input, slave, val.psz_string, NULL ) )
                 {
                     vlc_meta_t *p_meta;
                     int64_t i_time;
@@ -2103,11 +2057,11 @@ static bool Control( input_thread_t *p_input, int i_type,
             break;
 
         case INPUT_CONTROL_SET_FRAME_NEXT:
-            if( p_input->i_state == PAUSE_S )
+            if( p_input->p->i_state == PAUSE_S )
             {
                 es_out_SetFrameNext( p_input->p->p_es_out );
             }
-            else if( p_input->i_state == PLAYING_S )
+            else if( p_input->p->i_state == PLAYING_S )
             {
                 ControlPause( p_input, i_control_date );
             }
@@ -2255,7 +2209,7 @@ static int UpdateTitleSeekpointFromAccess( input_thread_t *p_input )
     {
         input_SendEventTitle( p_input, p_access->info.i_title );
 
-        stream_AccessUpdate( p_input->p->input.p_stream );
+        stream_Control( p_input->p->input.p_stream, STREAM_UPDATE_SIZE );
 
         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
     }
@@ -2321,22 +2275,15 @@ static int InputSourceInit( input_thread_t *p_input,
                             input_source_t *in, const char *psz_mrl,
                             const char *psz_forced_demux )
 {
-    const bool b_master = in == &p_input->p->input;
-
     char psz_dup[strlen(psz_mrl) + 1];
     const char *psz_access;
     const char *psz_demux;
     char *psz_path;
-    char *psz_tmp;
-    char *psz;
     vlc_value_t val;
     double f_fps;
 
     strcpy( psz_dup, psz_mrl );
 
-    if( !in ) return VLC_EGENERIC;
-    if( !p_input ) return VLC_EGENERIC;
-
     /* Split uri */
     input_SplitMRL( &psz_access, &psz_demux, &psz_path, psz_dup );
 
@@ -2394,14 +2341,10 @@ static int InputSourceInit( input_thread_t *p_input,
     {
         int64_t i_pts_delay;
 
-        /* */
-        if( b_master )
-            input_ChangeState( p_input, BUFFERING_S );
-
         /* Get infos from access_demux */
         demux_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 );
+        p_input->p->i_pts_delay = __MAX( p_input->p->i_pts_delay, i_pts_delay );
 
         in->b_title_demux = true;
         if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
@@ -2470,34 +2413,12 @@ static int InputSourceInit( input_thread_t *p_input,
             goto error;
         }
 
-        /* */
-        psz_tmp = psz = var_GetNonEmptyString( p_input, "access-filter" );
-        while( psz && *psz )
-        {
-            access_t *p_access = in->p_access;
-            char *end = strchr( psz, ':' );
-
-            if( end )
-                *end++ = '\0';
-
-            in->p_access = access_FilterNew( in->p_access, psz );
-            if( in->p_access == NULL )
-            {
-                in->p_access = p_access;
-                msg_Warn( p_input, "failed to insert access filter %s",
-                          psz );
-            }
-
-            psz = end;
-        }
-        free( psz_tmp );
-
         /* Get infos from access */
         if( !p_input->b_preparsing )
         {
             access_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 );
+            p_input->p->i_pts_delay = __MAX( p_input->p->i_pts_delay, i_pts_delay );
 
             in->b_title_demux = false;
             if( access_Control( in->p_access, ACCESS_GET_TITLE_INFO,
@@ -2523,26 +2444,55 @@ static int InputSourceInit( input_thread_t *p_input,
             var_Set( p_input, "can-seek", val );
         }
 
+        /* */
+        int  i_input_list;
+        char **ppsz_input_list;
+
+        TAB_INIT( i_input_list, ppsz_input_list );
+
+        /* On master stream only, use input-list */
+        if( &p_input->p->input == in )
+        {
+            char *psz_list;
+            char *psz_parser;
+
+            psz_list =
+            psz_parser = var_CreateGetNonEmptyString( p_input, "input-list" );
+
+            while( psz_parser && *psz_parser )
+            {
+                char *p = strchr( psz_parser, ',' );
+                if( p )
+                    *p++ = '\0';
+
+                if( *psz_parser )
+                {
+                    char *psz_name = strdup( psz_parser );
+                    if( psz_name )
+                        TAB_APPEND( i_input_list, ppsz_input_list, psz_name );
+                }
+
+                psz_parser = p;
+            }
+            free( psz_list );
+        }
         /* Autodetect extra files if none specified */
-        char *psz_input_list = var_CreateGetNonEmptyString( p_input, "input-list" );
-        if( !psz_input_list )
+        if( i_input_list <= 0 )
         {
-            char *psz_extra_files = InputGetExtraFiles( p_input, psz_access, psz_path );
-            if( psz_extra_files )
-                var_SetString( p_input, "input-list", psz_extra_files );
-            free( psz_extra_files );
+            InputGetExtraFiles( p_input, &i_input_list, &ppsz_input_list,
+                                psz_access, psz_path );
         }
+        if( i_input_list > 0 )
+            TAB_APPEND( i_input_list, ppsz_input_list, NULL );
 
         /* Create the stream_t */
-        if( b_master )
-            input_ChangeState( p_input, BUFFERING_S );
-
-        in->p_stream = stream_AccessNew( in->p_access, p_input->b_preparsing );
-
-        /* Restor old value */
-        if( !psz_input_list )
-            var_SetString( p_input, "input-list", "" );
-        free( psz_input_list );
+        in->p_stream = stream_AccessNew( in->p_access, ppsz_input_list );
+        if( ppsz_input_list )
+        {
+            for( int i = 0; ppsz_input_list[i] != NULL; i++ )
+                free( ppsz_input_list[i] );
+            TAB_CLEAN( i_input_list, ppsz_input_list );
+        }
 
         if( in->p_stream == NULL )
         {
@@ -2550,6 +2500,14 @@ static int InputSourceInit( input_thread_t *p_input,
             goto error;
         }
 
+        /* Add stream filters */
+        char *psz_stream_filter = var_GetNonEmptyString( p_input,
+                                                         "stream-filter" );
+        in->p_stream = stream_FilterChainNew( in->p_stream,
+                                              psz_stream_filter,
+                                              var_GetBool( p_input, "input-record-native" ) );
+        free( psz_stream_filter );
+
         /* Open a demuxer */
         if( *psz_demux == '\0' && *in->p_access->psz_demux )
         {
@@ -2608,7 +2566,7 @@ static int InputSourceInit( input_thread_t *p_input,
     if( demux_Control( in->p_demux, DEMUX_CAN_RECORD, &in->b_can_stream_record ) )
         in->b_can_stream_record = false;
 #ifdef ENABLE_SOUT
-    if( !var_CreateGetBool( p_input, "input-record-native" ) )
+    if( !var_GetBool( p_input, "input-record-native" ) )
         in->b_can_stream_record = false;
     var_SetBool( p_input, "can-record", true );
 #else
@@ -2643,9 +2601,6 @@ static int InputSourceInit( input_thread_t *p_input,
     return VLC_SUCCESS;
 
 error:
-    if( b_master )
-        input_ChangeState( p_input, ERROR_S );
-
     if( in->p_demux )
         demux_Delete( in->p_demux );
 
@@ -2712,7 +2667,7 @@ static void InputSourceMeta( input_thread_t *p_input,
     if( !p_demux_meta )
         return;
 
-    module_t *p_id3 = module_need( p_demux, "meta reader", NULL, 0 );
+    module_t *p_id3 = module_need( p_demux, "meta reader", NULL, false );
     if( p_id3 )
     {
         if( p_demux_meta->p_meta )
@@ -2738,12 +2693,11 @@ static void SlaveDemux( input_thread_t *p_input )
 {
     int64_t i_time;
     int i;
-    bool b_set_time = true;
 
     if( demux_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) )
     {
-        /* msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" ); */
-        b_set_time = false;
+        msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
+        return;
     }
 
     for( i = 0; i < p_input->p->i_slave; i++ )
@@ -2754,7 +2708,7 @@ static void SlaveDemux( input_thread_t *p_input )
         if( in->b_eof )
             continue;
 
-        if( b_set_time && demux_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
+        if( demux_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
         {
             for( ;; )
             {
@@ -2910,64 +2864,101 @@ static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_atta
  * InputGetExtraFiles
  *  Autodetect extra input list
  *****************************************************************************/
-static char *InputGetExtraFiles( input_thread_t *p_input,
-                                 const char *psz_access, const char *psz_path )
+static void InputGetExtraFilesPattern( input_thread_t *p_input,
+                                       int *pi_list, char ***pppsz_list,
+                                       const char *psz_path,
+                                       const char *psz_match,
+                                       const char *psz_format,
+                                       int i_start, int i_stop )
 {
-    char *psz_list = NULL;
-
-    if( ( psz_access && *psz_access && strcmp( psz_access, "file" ) ) || !psz_path )
-        return NULL;
+    int i_list;
+    char **ppsz_list;
 
+    TAB_INIT( i_list, ppsz_list );
 
-    const char *psz_ext = strrchr( psz_path, '.' );
-    if( !psz_ext || strcmp( psz_ext, ".001" ) )
-        return NULL;
+    char *psz_base = strdup( psz_path );
+    if( !psz_base )
+        goto exit;
 
-    char *psz_file = strdup( psz_path );
-    if( !psz_file )
-        return NULL;
+    /* Remove the extension */
+    char *psz_end = &psz_base[strlen(psz_base)-strlen(psz_match)];
+    assert( psz_end >= psz_base);
+    *psz_end = '\0';
 
-    /* Try to list .xyz files */
-    for( int i = 2; i < 999; i++ )
+    /* Try to list files */
+    for( int i = i_start; i <= i_stop; i++ )
     {
-        char *psz_ext = strrchr( psz_file, '.' );
         struct stat st;
+        char *psz_file;
 
-        snprintf( psz_ext, 5, ".%.3d", i );
+        if( asprintf( &psz_file, psz_format, psz_base, i ) < 0 )
+            break;
 
-        if( utf8_stat( psz_file, &st )
-         || !S_ISREG( st.st_mode ) || !st.st_size )
-            continue;
+        if( utf8_stat( psz_file, &st ) || !S_ISREG( st.st_mode ) || !st.st_size )
+        {
+            free( psz_file );
+            break;
+        }
 
         msg_Dbg( p_input, "Detected extra file `%s'", psz_file );
+        TAB_APPEND( i_list, ppsz_list, psz_file );
+    }
+    free( psz_base );
+exit:
+    *pi_list = i_list;
+    *pppsz_list = ppsz_list;
+}
 
-        if( psz_list )
-        {
-            char *psz_old = psz_list;
-            /* FIXME how to handle file with ',' ?*/
-            if( asprintf( &psz_list, "%s,%s", psz_old, psz_file ) < 0 )
-            {
-                psz_list = psz_old;
-                break;
-            }
-        }
-        else
+static void InputGetExtraFiles( input_thread_t *p_input,
+                                int *pi_list, char ***pppsz_list,
+                                const char *psz_access, const char *psz_path )
+{
+    static const struct
+    {
+        const char *psz_match;
+        const char *psz_format;
+        int i_start;
+        int i_stop;
+    } p_pattern[] = {
+        /* XXX the order is important */
+        { ".001",         "%s.%.3d",        2, 999 },
+        { ".part1.rar",   "%s.part%.1d.rar",2, 9 },
+        { ".part01.rar",  "%s.part%.2d.rar",2, 99, },
+        { ".part001.rar", "%s.part%.3d.rar",2, 999 },
+        { ".rar",         "%s.r%.2d",       1, 99 },
+        { NULL, NULL, 0, 0 }
+    };
+
+    TAB_INIT( *pi_list, *pppsz_list );
+
+    if( ( psz_access && *psz_access && strcmp( psz_access, "file" ) ) || !psz_path )
+        return;
+
+    const size_t i_path = strlen(psz_path);
+
+    for( int i = 0; p_pattern[i].psz_match != NULL; i++ )
+    {
+        const size_t i_ext = strlen(p_pattern[i].psz_match );
+
+        if( i_path < i_ext )
+            continue;
+        if( !strcmp( &psz_path[i_path-i_ext], p_pattern[i].psz_match ) )
         {
-            psz_list = strdup( psz_file );
+            InputGetExtraFilesPattern( p_input, pi_list, pppsz_list,
+                                       psz_path,
+                                       p_pattern[i].psz_match, p_pattern[i].psz_format,
+                                       p_pattern[i].i_start, p_pattern[i].i_stop );
+            return;
         }
     }
-    free( psz_file );
-
-    return psz_list;
 }
 
-
 /* */
 static void input_ChangeState( input_thread_t *p_input, int i_state )
 {
-    const bool b_changed = p_input->i_state != i_state;
+    const bool b_changed = p_input->p->i_state != i_state;
 
-    p_input->i_state = i_state;
+    p_input->p->i_state = i_state;
     if( i_state == ERROR_S )
         p_input->b_error = true;
     else if( i_state == END_S )
@@ -3148,7 +3139,7 @@ static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_for
     var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
 
     sub = InputSourceNew( p_input );
-    if( InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) )
+    if( !sub || InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) )
     {
         free( sub );
         return;
@@ -3173,29 +3164,13 @@ static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_for
     }
 }
 
-bool input_AddSubtitles( input_thread_t *p_input, char *psz_subtitle,
-                               bool b_check_extension )
-{
-    vlc_value_t val;
-
-    if( b_check_extension && !subtitles_Filter( psz_subtitle ) )
-        return false;
-
-    assert( psz_subtitle != NULL );
-
-    val.psz_string = strdup( psz_subtitle );
-    if( val.psz_string )
-        input_ControlPush( p_input, INPUT_CONTROL_ADD_SUBTITLE, &val );
-    return true;
-}
-
 /*****************************************************************************
  * Statistics
  *****************************************************************************/
 void input_UpdateStatistic( input_thread_t *p_input,
                             input_statistic_t i_type, int i_delta )
 {
-    assert( p_input->i_state != INIT_S );
+    assert( p_input->p->i_state != INIT_S );
 
     vlc_mutex_lock( &p_input->p->counters.counters_lock);
     switch( i_type )
@@ -3228,13 +3203,6 @@ void input_UpdateStatistic( input_thread_t *p_input,
     }
     vlc_mutex_unlock( &p_input->p->counters.counters_lock);
 }
-/*****************************************************************************
- * input_get_event_manager
- *****************************************************************************/
-vlc_event_manager_t *input_get_event_manager( input_thread_t *p_input )
-{
-    return &p_input->p->event_manager;
-}
 
 /**/
 /* TODO FIXME nearly the same logic that snapshot code */