]> git.sesse.net Git - vlc/blobdiff - src/input/input.c
Use vlc_object_kill(). Needs triple checking.
[vlc] / src / input / input.c
index 9f6c1b98d81aa14fa43c61859394bfb4681d34f7..570bb8dc53292d57548b530d3bb5354e5ccc516b 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * input.c: input thread
  *****************************************************************************
- * Copyright (C) 1998-2004 the VideoLAN team
+ * Copyright (C) 1998-2007 the VideoLAN team
  * $Id$
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  * Local prototypes
  *****************************************************************************/
 static  int Run  ( input_thread_t *p_input );
-static  int RunAndClean  ( input_thread_t *p_input );
+static  int RunAndDestroy  ( input_thread_t *p_input );
 
 static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
-                                  const char *, vlc_bool_t );
+                                  const char *, vlc_bool_t, sout_instance_t * );
 static  int             Init    ( input_thread_t *p_input );
 static void             Error   ( input_thread_t *p_input );
 static void             End     ( input_thread_t *p_input );
 static void             MainLoop( input_thread_t *p_input );
+static void             Destroy( input_thread_t *p_input, sout_instance_t **pp_sout );
 
 static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
 static void       ControlReduce( input_thread_t * );
@@ -73,13 +74,16 @@ static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
 static input_source_t *InputSourceNew( input_thread_t *);
 static int  InputSourceInit( input_thread_t *, input_source_t *,
                              const char *, const char *psz_forced_demux );
-static void InputSourceClean( input_thread_t *, input_source_t * );
+static void InputSourceClean( input_source_t * );
 
 static void SlaveDemux( input_thread_t *p_input );
 static void SlaveSeek( input_thread_t *p_input );
 
 static void InputMetaUser( input_thread_t *p_input );
 
+static sout_instance_t *SoutFind( vlc_object_t *p_parent, input_item_t *p_item, vlc_bool_t * );
+static void SoutKeep( sout_instance_t * );
+
 /*****************************************************************************
  * This function creates a new input, and returns a pointer
  * to its description. On error, it returns NULL.
@@ -105,7 +109,7 @@ static void InputMetaUser( input_thread_t *p_input );
  * TODO complete this list (?)
  *****************************************************************************/
 static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
-                               const char *psz_header, vlc_bool_t b_quick )
+                               const char *psz_header, vlc_bool_t b_quick, sout_instance_t *p_sout )
 {
     input_thread_t *p_input = NULL;                 /* thread descriptor */
     vlc_value_t val;
@@ -151,6 +155,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     p_input->p->p_meta  = NULL;
     p_input->p->p_es_out = NULL;
     p_input->p->p_sout  = NULL;
+    p_input->p->b_sout_keep  = VLC_FALSE;
     p_input->p->b_out_pace_control = VLC_FALSE;
     p_input->i_pts_delay = 0;
 
@@ -188,17 +193,14 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     /* Parse input options */
     vlc_mutex_lock( &p_item->lock );
     for( i = 0; i < p_item->i_options; i++ )
-    {
         var_OptionParse( p_input, p_item->ppsz_options[i] );
-    }
     vlc_mutex_unlock( &p_item->lock );
 
     /* Create Object Variables for private use only */
     input_ConfigVarInit( p_input );
 
     /* Create Objects variables for public Get and Set */
-    if( !p_input->b_preparsing )
-        input_ControlVarInit( p_input );
+    input_ControlVarInit( p_input );
 
     p_input->p->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
 
@@ -251,12 +253,45 @@ 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 );     /* ? Don't translate as it might has been copied ? */
+    input_Control( p_input, INPUT_DEL_INFO, _(VLC_META_INFO_CAT), VLC_META_NOW_PLAYING );
+    vlc_meta_SetNowPlaying( p_item->p_meta, NULL );
+
+    /* */
+    if( p_input->b_preparsing )
+        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;
+
+    /* */
+    if( p_sout )
+        p_input->p->p_sout = p_sout;
+
+    /* Attach only once we are ready */
+    vlc_object_attach( p_input, p_parent );
 
     return p_input;
 }
 
+static void Destroy( input_thread_t *p_input, sout_instance_t **pp_sout )
+{
+    vlc_object_detach( p_input );
+
+    if( pp_sout )
+        *pp_sout = NULL;
+    if( p_input->p->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 );
+        else
+            sout_DeleteInstance( p_input->p->p_sout );
+    }
+
+    vlc_mutex_destroy( &p_input->p->lock_control );
+    free( p_input->p );
+
+    vlc_object_destroy( p_input );
+}
+
 /**
  * Initialize an input thread and run it. You will need to monitor the
  * thread to clean up after it is done
@@ -268,32 +303,35 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                       input_item_t *p_item )
 {
-    return __input_CreateThread2( p_parent, p_item, NULL );
+    vlc_bool_t b_sout_keep;
+    sout_instance_t *p_sout = SoutFind( p_parent, p_item, &b_sout_keep );
+    input_thread_t *p_input =  __input_CreateThreadExtended( p_parent, p_item, NULL, p_sout );
+
+    if( !p_input && p_sout )
+        SoutKeep( p_sout );
+
+    p_input->p->b_sout_keep = b_sout_keep;
+    return p_input;
 }
 
-/* Gruik ! */
-input_thread_t *__input_CreateThread2( vlc_object_t *p_parent,
-                                       input_item_t *p_item,
-                                       const char *psz_header )
+/* */
+input_thread_t *__input_CreateThreadExtended( vlc_object_t *p_parent,
+                                              input_item_t *p_item,
+                                              const char *psz_log, sout_instance_t *p_sout )
 {
-    input_thread_t *p_input = NULL;      /* thread descriptor */
+    input_thread_t *p_input;
 
-    p_input = Create( p_parent, p_item, psz_header, VLC_FALSE );
+    p_input = Create( p_parent, p_item, psz_log, VLC_FALSE, p_sout );
     if( !p_input )
         return NULL;
 
-    /* Now we can attach our new input */
-    vlc_object_attach( p_input, p_parent );
-
     /* Create thread and wait for its readiness. */
     if( vlc_thread_create( p_input, "input", Run,
-                            VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
+                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
     {
         input_ChangeState( p_input, ERROR_S );
         msg_Err( p_input, "cannot create input thread" );
-        vlc_object_detach( p_input );
-        free( p_input->p );
-        vlc_object_destroy( p_input );
+        Destroy( p_input, &p_sout );
         return NULL;
     }
 
@@ -312,30 +350,31 @@ input_thread_t *__input_CreateThread2( vlc_object_t *p_parent,
 int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
                    vlc_bool_t b_block )
 {
-    input_thread_t *p_input = NULL;         /* thread descriptor */
+    vlc_bool_t b_sout_keep;
+    sout_instance_t *p_sout = SoutFind( p_parent, p_item, &b_sout_keep );
+    input_thread_t *p_input;
 
-    p_input = Create( p_parent, p_item, NULL, VLC_FALSE );
-    if( !p_input )
+    p_input = Create( p_parent, p_item, NULL, VLC_FALSE, p_sout );
+    if( !p_input && p_sout )
+    {
+        SoutKeep( p_sout );
         return VLC_EGENERIC;
-
-    /* Now we can attach our new input */
-    vlc_object_attach( p_input, p_parent );
+    }
+    p_input->p->b_sout_keep = b_sout_keep;
 
     if( b_block )
     {
-        RunAndClean( p_input );
+        RunAndDestroy( p_input );
         return VLC_SUCCESS;
     }
     else
     {
-        if( vlc_thread_create( p_input, "input", RunAndClean,
+        if( vlc_thread_create( p_input, "input", RunAndDestroy,
                                VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
         {
             input_ChangeState( p_input, ERROR_S );
             msg_Err( p_input, "cannot create input thread" );
-            vlc_object_detach( p_input );
-           free( p_input->p );
-            vlc_object_destroy( p_input );
+            Destroy( p_input, NULL );
             return VLC_EGENERIC;
         }
     }
@@ -352,30 +391,17 @@ int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
  */
 int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
 {
-    input_thread_t *p_input = NULL;           /* thread descriptor */
+    input_thread_t *p_input;
 
     /* Allocate descriptor */
-    p_input = Create( p_parent, p_item, NULL, VLC_TRUE );
+    p_input = Create( p_parent, p_item, NULL, VLC_TRUE, NULL );
     if( !p_input )
         return VLC_EGENERIC;
 
-    p_input->i_flags |= OBJECT_FLAGS_QUIET;
-    p_input->i_flags |= OBJECT_FLAGS_NOINTERACT;
-
-    /* Now we can attach our new input */
-    vlc_object_attach( p_input, p_parent );
-
-    Init( p_input );
-
-    /* Clean up master */
-    InputSourceClean( p_input, &p_input->p->input );
-
-    /* Unload all modules */
-    if( p_input->p->p_es_out ) input_EsOutDelete( p_input->p->p_es_out );
+    if( !Init( p_input ) )
+        End( p_input );
 
-    vlc_object_detach( p_input );
-    free( p_input->p );
-    vlc_object_destroy( p_input );
+    Destroy( p_input, NULL );
 
     return VLC_SUCCESS;
 }
@@ -391,7 +417,8 @@ void input_StopThread( input_thread_t *p_input )
     int i;
 
     /* Set die for input */
-    p_input->b_die = VLC_TRUE;
+    vlc_object_kill( p_input );
+    /* FIXME: seems to be duplicated in ControlPush(INPUT_CONTROL_SET_DIE) */
 
     /* We cannot touch p_input fields directly (we come from another thread),
      * so use the vlc_object_find way, it's perfectly safe */
@@ -400,7 +427,7 @@ void input_StopThread( input_thread_t *p_input )
     p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
     for( i = 0; i < p_list->i_count; i++ )
     {
-        p_list->p_values[i].p_object->b_die = VLC_TRUE;
+        vlc_object_kill( p_list->p_values[i].p_object );
     }
     vlc_list_release( p_list );
 
@@ -408,7 +435,7 @@ void input_StopThread( input_thread_t *p_input )
     p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
     for( i = 0; i < p_list->i_count; i++ )
     {
-        p_list->p_values[i].p_object->b_die = VLC_TRUE;
+        vlc_object_kill( p_list->p_values[i].p_object );
     }
     vlc_list_release( p_list );
 
@@ -416,7 +443,7 @@ void input_StopThread( input_thread_t *p_input )
     p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
     for( i = 0; i < p_list->i_count; i++ )
     {
-        p_list->p_values[i].p_object->b_die = VLC_TRUE;
+        vlc_object_kill( p_list->p_values[i].p_object );
     }
     vlc_list_release( p_list );
 
@@ -430,15 +457,17 @@ void input_StopThread( input_thread_t *p_input )
  * \param the input thread to kill
  */
 void input_DestroyThread( input_thread_t *p_input )
+{
+    input_DestroyThreadExtended( p_input, NULL );
+}
+
+void input_DestroyThreadExtended( input_thread_t *p_input, sout_instance_t **pp_sout )
 {
     /* Join the thread */
     vlc_thread_join( p_input );
 
-    /* Delete input lock (only after thread joined) */
-    vlc_mutex_destroy( &p_input->p->lock_control );
-
-    /* TODO: maybe input_DestroyThread should also delete p_input instead
-     * of the playlist but I'm not sure if it's possible */
+    /* */
+    Destroy( p_input, pp_sout );
 }
 
 /*****************************************************************************
@@ -498,20 +527,17 @@ static int Run( input_thread_t *p_input )
 }
 
 /*****************************************************************************
- * RunAndClean: main thread loop
+ * RunAndDestroy: main thread loop
  * This is the "just forget me" thread that spawns the input processing chain,
  * reads the stream, cleans up and releases memory
  *****************************************************************************/
-static int RunAndClean( input_thread_t *p_input )
+static int RunAndDestroy( input_thread_t *p_input )
 {
     /* Signal that the thread is launched */
     vlc_thread_ready( p_input );
 
     if( Init( p_input ) )
-    {
-        /* If we failed, just exit */
-        return 0;
-    }
+        goto exit;
 
     MainLoop( p_input );
 
@@ -535,11 +561,9 @@ static int RunAndClean( input_thread_t *p_input )
     /* Clean up */
     End( p_input );
 
+exit:
     /* Release memory */
-    vlc_object_detach( p_input );
-    free( p_input->p );
-    vlc_object_destroy( p_input );
-
+    Destroy( p_input, NULL );
     return 0;
 }
 
@@ -550,6 +574,7 @@ static void MainLoop( input_thread_t *p_input )
 {
     int64_t i_intf_update = 0;
     int i_updates = 0;
+
     while( !p_input->b_die && !p_input->b_error && !p_input->p->input.b_eof )
     {
         vlc_bool_t b_force_update = VLC_FALSE;
@@ -760,19 +785,45 @@ static int Init( input_thread_t * p_input )
                 p_input->p->counters.p_input_bitrate->update_interval = 1000000;
         }
 
-        /* handle sout */
+        /* 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 ) )
         {
-            p_input->p->p_sout = sout_NewInstance( p_input, psz );
-            if( p_input->p->p_sout == NULL )
+            /* Check the validity of the provided sout */
+            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;
+                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 )
+            {
+                /* 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;
+                }
+            }
+
             if( p_input->p_libvlc->b_stats )
             {
                 INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
@@ -783,6 +834,13 @@ static int Init( input_thread_t * p_input )
                              1000000;
             }
         }
+        else if( p_input->p->p_sout )
+        {
+            msg_Dbg( p_input, "destroying useless sout" );
+
+            sout_DeleteInstance( p_input->p->p_sout );
+            p_input->p->p_sout = NULL;
+        }
         free( psz );
     }
 
@@ -1109,7 +1167,38 @@ error:
         input_EsOutDelete( p_input->p->p_es_out );
 
     if( p_input->p->p_sout )
+    {
+        vlc_object_detach( p_input->p->p_sout );
         sout_DeleteInstance( p_input->p->p_sout );
+    }
+
+
+    if( !p_input->b_preparsing && p_input->p_libvlc->b_stats )
+    {
+#define EXIT_COUNTER( c ) do { if( p_input->p->counters.p_##c ) \
+                                   stats_CounterClean( p_input->p->counters.p_##c );\
+                               p_input->p->counters.p_##c = NULL; } while(0)
+        EXIT_COUNTER( read_bytes );
+        EXIT_COUNTER( read_packets );
+        EXIT_COUNTER( demux_read );
+        EXIT_COUNTER( input_bitrate );
+        EXIT_COUNTER( demux_bitrate );
+        EXIT_COUNTER( played_abuffers );
+        EXIT_COUNTER( lost_abuffers );
+        EXIT_COUNTER( displayed_pictures );
+        EXIT_COUNTER( lost_pictures );
+        EXIT_COUNTER( decoded_audio );
+        EXIT_COUNTER( decoded_video );
+        EXIT_COUNTER( decoded_sub );
+
+        if( p_input->p->p_sout )
+        {
+            EXIT_COUNTER( sout_sent_packets );
+            EXIT_COUNTER (sout_sent_bytes );
+            EXIT_COUNTER( sout_send_bitrate );
+        }
+#undef EXIT_COUNTER
+    }
 
     /* Mark them deleted */
     p_input->p->input.p_demux = NULL;
@@ -1143,22 +1232,19 @@ static void End( input_thread_t * p_input )
 {
     int i;
 
-    msg_Dbg( p_input, "closing input" );
-
     /* We are at the end */
     input_ChangeState( p_input, END_S );
 
     /* Clean control variables */
-    if( !p_input->b_preparsing )
-        input_ControlVarClean( p_input );
+    input_ControlVarClean( p_input );
 
     /* Clean up master */
-    InputSourceClean( p_input, &p_input->p->input );
+    InputSourceClean( &p_input->p->input );
 
     /* Delete slave */
     for( i = 0; i < p_input->p->i_slave; i++ )
     {
-        InputSourceClean( p_input, p_input->p->slave[i] );
+        InputSourceClean( p_input->p->slave[i] );
         free( p_input->p->slave[i] );
     }
     if( p_input->p->slave ) free( p_input->p->slave );
@@ -1167,54 +1253,44 @@ static void End( input_thread_t * p_input )
     if( p_input->p->p_es_out )
         input_EsOutDelete( p_input->p->p_es_out );
 
-#define CL_CO( c ) stats_CounterClean( p_input->p->counters.p_##c ); p_input->p->counters.p_##c = NULL;
-    if( p_input->p_libvlc->b_stats )
-    {
-        /* make sure we are up to date */
-        stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats );
-        if( p_input->p_libvlc->p_playlist->p_stats_computer == p_input )
-        {
-            stats_ComputeGlobalStats( p_input->p_libvlc->p_playlist,
-                                      p_input->p_libvlc->p_playlist->p_stats );
-            p_input->p_libvlc->p_playlist->p_stats_computer = NULL;
-        }
-        CL_CO( read_bytes );
-        CL_CO( read_packets );
-        CL_CO( demux_read );
-        CL_CO( input_bitrate );
-        CL_CO( demux_bitrate );
-        CL_CO( played_abuffers );
-        CL_CO( lost_abuffers );
-        CL_CO( displayed_pictures );
-        CL_CO( lost_pictures );
-        CL_CO( decoded_audio) ;
-        CL_CO( decoded_video );
-        CL_CO( decoded_sub) ;
-    }
-
-    /* Close optional stream output instance */
-    if( p_input->p->p_sout )
+    if( !p_input->b_preparsing )
     {
-        vlc_value_t keep;
-
-        CL_CO( sout_sent_packets );
-        CL_CO( sout_sent_bytes );
-        CL_CO( sout_send_bitrate );
-
-        if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool )
+#define CL_CO( c ) stats_CounterClean( p_input->p->counters.p_##c ); p_input->p->counters.p_##c = NULL;
+        if( p_input->p_libvlc->b_stats )
         {
-            /* attach sout to the playlist */
-            msg_Dbg( p_input, "keeping sout" );
-            vlc_object_detach( p_input->p->p_sout );
-            vlc_object_attach( p_input->p->p_sout, p_input->p_libvlc->p_playlist );
+            /* make sure we are up to date */
+            stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats );
+            if( p_input->p_libvlc->p_playlist->p_stats_computer == p_input )
+            {
+                stats_ComputeGlobalStats( p_input->p_libvlc->p_playlist,
+                                          p_input->p_libvlc->p_playlist->p_stats );
+                p_input->p_libvlc->p_playlist->p_stats_computer = NULL;
+            }
+            CL_CO( read_bytes );
+            CL_CO( read_packets );
+            CL_CO( demux_read );
+            CL_CO( input_bitrate );
+            CL_CO( demux_bitrate );
+            CL_CO( played_abuffers );
+            CL_CO( lost_abuffers );
+            CL_CO( displayed_pictures );
+            CL_CO( lost_pictures );
+            CL_CO( decoded_audio) ;
+            CL_CO( decoded_video );
+            CL_CO( decoded_sub) ;
         }
-        else
+
+        /* Close optional stream output instance */
+        if( p_input->p->p_sout )
         {
-            msg_Dbg( p_input, "destroying sout" );
-            sout_DeleteInstance( p_input->p->p_sout );
+            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
+    }
 
     vlc_mutex_destroy( &p_input->p->counters.counters_lock );
 
@@ -1222,6 +1298,74 @@ static void End( input_thread_t * p_input )
     p_input->b_dead = VLC_TRUE;
 }
 
+static sout_instance_t *SoutFind( vlc_object_t *p_parent, input_item_t *p_item, vlc_bool_t *pb_sout_keep )
+{
+    vlc_bool_t b_keep_sout = var_CreateGetBool( p_parent, "sout-keep" );
+    sout_instance_t *p_sout = NULL;
+    int i;
+
+    /* Search sout-keep options
+     * XXX it has to be done here, but it is duplicated work :( */
+    vlc_mutex_lock( &p_item->lock );
+    for( i = 0; i < p_item->i_options; i++ )
+    {
+        const char *psz_option = p_item->ppsz_options[i];
+        if( !psz_option )
+            continue;
+        if( *psz_option == ':' )
+            psz_option++;
+
+        if( !strcmp( psz_option, "sout-keep" ) )
+            b_keep_sout = VLC_TRUE;
+        else if( !strcmp( psz_option, "no-sout-keep" ) || !strcmp( psz_option, "nosout-keep" ) )
+            b_keep_sout = VLC_FALSE;
+    }
+    vlc_mutex_unlock( &p_item->lock );
+
+    /* Find a potential sout to reuse
+     * XXX it might be unusable but this will be checked later */
+    if( b_keep_sout )
+    {
+        /* Remove the sout from the playlist garbage collector */
+        playlist_t *p_playlist = pl_Yield( p_parent );
+
+        vlc_mutex_lock( &p_playlist->gc_lock );
+        p_sout = vlc_object_find( p_playlist, VLC_OBJECT_SOUT, FIND_CHILD );
+        if( p_sout )
+        {
+            if( p_sout->p_parent != VLC_OBJECT(p_playlist) )
+            {
+                vlc_object_release( p_sout );
+                p_sout = NULL;
+            }
+            else
+            {
+                vlc_object_detach( p_sout );    /* Remove it from the GC */
+
+                vlc_object_release( p_sout );
+            }
+        }
+        vlc_mutex_unlock( &p_playlist->gc_lock );
+
+        pl_Release( p_parent );
+    }
+
+    if( pb_sout_keep )
+        *pb_sout_keep = b_keep_sout;
+
+    return p_sout;
+}
+static void SoutKeep( sout_instance_t *p_sout )
+{
+    /* attach sout to the playlist */
+    playlist_t  *p_playlist = pl_Yield( p_sout );
+
+    msg_Dbg( p_sout, "sout has been kept" );
+    vlc_object_attach( p_sout, p_playlist );
+
+    pl_Release( p_sout );
+}
+
 /*****************************************************************************
  * Control
  *****************************************************************************/
@@ -1309,12 +1453,12 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
             msg_Dbg( p_input, "control: stopping input" );
             /* Mark all submodules to die */
             if( p_input->p->input.p_access )
-                p_input->p->input.p_access->b_die = VLC_TRUE;
+                vlc_object_kill( p_input->p->input.p_access );
             if( p_input->p->input.p_stream )
-                p_input->p->input.p_stream->b_die = VLC_TRUE;
-            p_input->p->input.p_demux->b_die = VLC_TRUE;
+                vlc_object_kill( p_input->p->input.p_stream );
+            vlc_object_kill( p_input->p->input.p_demux );
 
-            p_input->b_die = VLC_TRUE;
+            vlc_object_kill( p_input );
             break;
 
         case INPUT_CONTROL_SET_POSITION:
@@ -1437,7 +1581,6 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
 
                 /* Reset clock */
                 es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
-                input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE );
             }
             else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S &&
                      p_input->p->b_can_pause )
@@ -1465,6 +1608,10 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                 /* Switch to new state */
                 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 );
             }
             else if( val.i_int == PAUSE_S && !p_input->p->b_can_pause )
             {
@@ -1512,14 +1659,15 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
             }
             if( i_rate != p_input->p->i_rate )
             {
-                p_input->p->i_rate  = i_rate;
                 val.i_int = i_rate;
                 var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
 
-                /* We haven't send data to decoder when rate != default */
-                if( i_rate == INPUT_RATE_DEFAULT )
+                /* 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 );
 
+                p_input->p->i_rate  = i_rate;
+
                 /* Reset clock */
                 es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
 
@@ -1703,7 +1851,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                                         DEMUX_GET_TIME, &i_time ) )
                     {
                         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
-                        InputSourceClean( p_input, slave );
+                        InputSourceClean( slave );
                         free( slave );
                         break;
                     }
@@ -1711,7 +1859,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                                         DEMUX_SET_TIME, i_time ) )
                     {
                         msg_Err( p_input, "seek failed for new slave" );
-                        InputSourceClean( p_input, slave );
+                        InputSourceClean( slave );
                         free( slave );
                         break;
                     }
@@ -1938,7 +2086,7 @@ static int InputSourceInit( input_thread_t *p_input,
     char *psz;
     vlc_value_t val;
 
-    strcpy (psz_dup, psz_mrl);
+    strcpy( psz_dup, psz_mrl );
 
     if( !in ) return VLC_EGENERIC;
     if( !p_input ) return VLC_EGENERIC;
@@ -2125,14 +2273,33 @@ static int InputSourceInit( input_thread_t *p_input,
         {
             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->p_es_out,
-                                  p_input->b_preparsing );
+
+        {
+            /* Take access redirections into account */
+            char *psz_real_path;
+            char *psz_buf = NULL;
+            if( in->p_access->psz_path )
+            {
+                psz_buf = strdup( in->p_access->psz_path );
+                char *psz_a, *psz_d;
+                MRLSplit( p_input, psz_buf, &psz_a, &psz_d, &psz_real_path );
+            }
+            else
+            {
+                psz_real_path = psz_path;
+            }
+            in->p_demux = demux2_New( p_input, psz_access, psz_demux,
+                                      psz_real_path,
+                                      in->p_stream, p_input->p->p_es_out,
+                                      p_input->b_preparsing );
+            free( psz_buf );
+        }
+
         if( in->p_demux == NULL )
         {
             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, 
+            intf_UserFatal( VLC_OBJECT( p_input ), VLC_FALSE,
                             _("Can't recognize the input's format"),
                             _("The format of '%s' can't be detected. "
                             "Have a look the log for details."), psz_mrl );
@@ -2179,7 +2346,7 @@ error:
 /*****************************************************************************
  * InputSourceClean:
  *****************************************************************************/
-static void InputSourceClean( input_thread_t *p_input, input_source_t *in )
+static void InputSourceClean( input_source_t *in )
 {
     if( in->p_demux )
         demux2_Delete( in->p_demux );
@@ -2333,6 +2500,8 @@ void MRLSplit( vlc_object_t *p_input, char *psz_dup,
         psz_path = psz_dup;
     }
     else
+#else
+    (void)p_input;
 #endif
 
     if( psz )