Reworked/improved the way sout-keep works. (VLM sout-keep does not
authorLaurent Aimar <fenrir@videolan.org>
Wed, 28 Feb 2007 22:45:02 +0000 (22:45 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Wed, 28 Feb 2007 22:45:02 +0000 (22:45 +0000)
work again yet )

src/input/input.c
src/input/input_internal.h
src/input/vlm.c
src/playlist/engine.c
src/stream_output/stream_output.c

index 4b14a3d..9e438ad 100644 (file)
@@ -52,11 +52,12 @@ static  int Run  ( 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 * );
@@ -80,6 +81,9 @@ 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,9 +193,7 @@ 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 */
@@ -257,21 +260,38 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     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 )
+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
@@ -283,27 +303,35 @@ static void Destroy( input_thread_t *p_input )
 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;
 
     /* 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" );
-        Destroy( p_input );
+        Destroy( p_input, &p_sout );
         return NULL;
     }
 
@@ -322,11 +350,17 @@ 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;
+    }
+    p_input->p->b_sout_keep = b_sout_keep;
 
     if( b_block )
     {
@@ -340,7 +374,7 @@ int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
         {
             input_ChangeState( p_input, ERROR_S );
             msg_Err( p_input, "cannot create input thread" );
-            Destroy( p_input );
+            Destroy( p_input, NULL );
             return VLC_EGENERIC;
         }
     }
@@ -357,17 +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;
 
     Init( p_input );
     End( p_input );
 
-    Destroy( p_input );
+    Destroy( p_input, NULL );
 
     return VLC_SUCCESS;
 }
@@ -422,12 +456,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 );
 
     /* */
-    Destroy( p_input );
+    Destroy( p_input, pp_sout );
 }
 
 /*****************************************************************************
@@ -523,7 +562,7 @@ static int RunAndDestroy( input_thread_t *p_input )
 
 exit:
     /* Release memory */
-    Destroy( p_input );
+    Destroy( p_input, NULL );
     return 0;
 }
 
@@ -534,6 +573,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;
@@ -744,19 +784,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 )
+            {
+                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
             {
-                input_ChangeState( p_input, ERROR_S );
-                msg_Err( p_input, "cannot start stream output instance, " \
-                                  "aborting" );
-                free( psz );
-                return VLC_EGENERIC;
+                /* 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 );
@@ -767,6 +833,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 );
     }
 
@@ -1093,7 +1166,7 @@ error:
         input_EsOutDelete( p_input->p->p_es_out );
 
     if( p_input->p->p_sout )
-        sout_DeleteInstance( p_input->p->p_sout );
+        vlc_object_detach( p_input->p->p_sout );
 
     /* Mark them deleted */
     p_input->p->input.p_demux = NULL;
@@ -1178,35 +1251,87 @@ static void End( input_thread_t * p_input )
         /* Close optional stream output instance */
         if( p_input->p->p_sout )
         {
-            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 )
-            {
-                playlist_t  *p_playlist = pl_Yield( p_input );
+            vlc_object_detach( p_input->p->p_sout );
+        }
+#undef CL_CO
+    }
+
+    vlc_mutex_destroy( &p_input->p->counters.counters_lock );
+
+    /* Tell we're dead */
+    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++;
 
-                /* attach sout to the playlist */
-                vlc_object_detach( p_input->p->p_sout );
-                vlc_object_attach( p_input->p->p_sout, p_playlist );
-                pl_Release( p_input );
-                msg_Dbg( p_input, "kept sout" );
+        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
             {
-                sout_DeleteInstance( p_input->p->p_sout );
-                msg_Dbg( p_input, "destroyed sout" );
+                vlc_object_detach( p_sout );    /* Remove it from the GC */
+
+                vlc_object_release( p_sout );
             }
         }
-#undef CL_CO
+        vlc_mutex_unlock( &p_playlist->gc_lock );
+
+        pl_Release( p_parent );
     }
 
-    vlc_mutex_destroy( &p_input->p->counters.counters_lock );
+    if( pb_sout_keep )
+        *pb_sout_keep = b_keep_sout;
 
-    /* Tell we're dead */
-    p_input->b_dead = VLC_TRUE;
+    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 );
 }
 
 /*****************************************************************************
index 77c4169..c3ac9ba 100644 (file)
@@ -93,6 +93,7 @@ struct input_thread_private_t
     /* Output */
     es_out_t    *p_es_out;
     sout_instance_t *p_sout;            /* XXX Move it to es_out ? */
+    vlc_bool_t      b_sout_keep;
     vlc_bool_t      b_out_pace_control; /*     idem ? */
 
     /* Main input properties */
@@ -225,8 +226,10 @@ int         input_DownloadAndCacheArt ( playlist_t *, input_item_t * );
  ***************************************************************************/
 
 /* input.c */
-#define input_CreateThread2(a,b,c) __input_CreateThread2(VLC_OBJECT(a),b,c)
-input_thread_t *__input_CreateThread2 ( vlc_object_t *, input_item_t *, const char * );
+#define input_CreateThreadExtended(a,b,c,d) __input_CreateThreadExtended(VLC_OBJECT(a),b,c,d)
+input_thread_t *__input_CreateThreadExtended ( vlc_object_t *, input_item_t *, const char *, sout_instance_t * );
+
+void input_DestroyThreadExtended( input_thread_t *p_input, sout_instance_t ** );
 
 /* var.c */
 void input_ControlVarInit ( input_thread_t * );
index 95eb590..2129832 100644 (file)
@@ -1140,14 +1140,13 @@ int vlm_MediaSetup( vlm_t *vlm, vlm_media_t *media, const char *psz_cmd,
 
             asprintf( &psz_header, _("Media: %s"), media->psz_name );
 
-            if( (p_input = input_CreateThread2( vlm, &media->item, psz_header
-                                              ) ) )
+            if( (p_input = input_CreateThreadExtended( vlm, &media->item, psz_header, NULL ) ) )
             {
                 while( !p_input->b_eof && !p_input->b_error )
                     msleep( 100000 );
 
                 input_StopThread( p_input );
-                input_DestroyThread( p_input );
+                input_DestroyThreadExtended( p_input, NULL );
             }
             free( psz_output );
             free( psz_header );
@@ -1242,12 +1241,11 @@ int vlm_MediaControl( vlm_t *vlm, vlm_media_t *media, const char *psz_id,
         if( p_instance->p_input )
         {
             input_StopThread( p_instance->p_input );
-            input_DestroyThread( p_instance->p_input );
+            input_DestroyThreadExtended( p_instance->p_input, NULL );
         }
 
         asprintf( &psz_header, _("Media: %s"), media->psz_name );
-        p_instance->p_input = input_CreateThread2( vlm, &p_instance->item,
-                                                   psz_header );
+        p_instance->p_input = input_CreateThreadExtended( vlm, &p_instance->item, psz_header, NULL );
         if( !p_instance->p_input )
         {
             TAB_REMOVE( media->i_instance, media->instance, p_instance );
@@ -1361,7 +1359,7 @@ int vlm_MediaControl( vlm_t *vlm, vlm_media_t *media, const char *psz_id,
         if( p_instance->p_input )
         {
             input_StopThread( p_instance->p_input );
-            input_DestroyThread( p_instance->p_input );
+            input_DestroyThreadExtended( p_instance->p_input, NULL );
         }
 
         input_ItemClean( &p_instance->item );
@@ -2502,7 +2500,7 @@ static int Manage( vlc_object_t* p_object )
                     char buffer[12];
 
                     input_StopThread( p_instance->p_input );
-                    input_DestroyThread( p_instance->p_input );
+                    input_DestroyThreadExtended( p_instance->p_input, NULL );
                     p_instance->p_input = NULL;
 
                     /* FIXME, find a way to select the right instance */
index 85bd955..d405e41 100644 (file)
@@ -210,6 +210,8 @@ static void ObjectGarbageCollector( playlist_t *p_playlist )
             vlc_object_release( p_obj );
             break;
         }
+        msg_Dbg( p_playlist, "garbage collector destroying 1 sout" );
+        vlc_object_detach( p_obj );
         vlc_object_release( p_obj );
         sout_DeleteInstance( (sout_instance_t*)p_obj );
     }
@@ -409,6 +411,7 @@ void playlist_LastLoop( playlist_t *p_playlist )
     while( ( p_obj = vlc_object_find( p_playlist,
                                       VLC_OBJECT_SOUT, FIND_CHILD ) ) )
     {
+        vlc_object_detach( p_obj );
         vlc_object_release( p_obj );
         sout_DeleteInstance( (sout_instance_t*)p_obj );
     }
index dc58641..1db9d60 100644 (file)
@@ -73,45 +73,6 @@ static void mrl_Clean( mrl_t *p_mrl );
 sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
 {
     sout_instance_t *p_sout;
-    vlc_value_t keep;
-
-    if( var_Get( p_parent, "sout-keep", &keep ) >= 0 && keep.b_bool )
-    {
-        /* 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 && p_sout->p_parent != (vlc_object_t *)p_playlist )
-        {
-            vlc_object_release( p_sout );
-            p_sout = NULL;
-        }
-        if( p_sout )
-            vlc_object_detach( p_sout );    /* Remove it from the GC */
-        vlc_mutex_unlock( &p_playlist->gc_lock );
-
-        pl_Release( p_parent );
-
-        /* */
-
-        if( p_sout )
-        {
-            if( !strcmp( p_sout->psz_sout, psz_dest ) )
-            {
-                msg_Dbg( p_parent, "sout keep: reusing sout" );
-                msg_Dbg( p_parent, "sout keep: you probably want to use "
-                          "gather stream_out" );
-                vlc_object_attach( p_sout, p_parent );
-                vlc_object_release( p_sout );
-                return p_sout;
-            }
-
-            msg_Dbg( p_parent, "sout keep: destroying unusable sout" );
-            vlc_object_release( p_sout );
-            sout_DeleteInstance( p_sout );
-        }
-    }
 
     /* *** Allocate descriptor *** */
     p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
@@ -164,9 +125,6 @@ sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
  *****************************************************************************/
 void sout_DeleteInstance( sout_instance_t * p_sout )
 {
-    /* Unlink object */
-    vlc_object_detach( p_sout );
-
     /* remove the stream out chain */
     sout_StreamDelete( p_sout->p_stream );