]> git.sesse.net Git - vlc/blobdiff - src/playlist/engine.c
Don't loop preparse threads when idle
[vlc] / src / playlist / engine.c
index 1443fad7f8be896c12c829661174ce78f9f8ef4e..39b09c17437a9239e3b96bc643b903529f9f47d3 100644 (file)
@@ -2,7 +2,7 @@
  * engine.c : Run the playlist and handle its control
  *****************************************************************************
  * Copyright (C) 1999-2004 the VideoLAN team
- * $Id: /local/vlc/0.8.6-playlist-vlm/src/playlist/playlist.c 13741 2006-03-21T19:29:39.792444Z zorglub  $
+ * $Id$
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *          ClĂ©ment Stenac <zorglub@videolan.org>
@@ -27,8 +27,7 @@
 #include <vlc/input.h>
 #include "vlc_playlist.h"
 #include "vlc_interaction.h"
-
-#undef PLAYLIST_DEBUG
+#include "playlist_internal.h"
 
 /*****************************************************************************
  * Local prototypes
@@ -45,6 +44,7 @@ static void VariablesInit( playlist_t *p_playlist );
 playlist_t * playlist_Create( vlc_object_t *p_parent )
 {
     playlist_t *p_playlist;
+    int i_tree;
 
     /* Allocate structure */
     p_playlist = vlc_object_create( p_parent, VLC_OBJECT_PLAYLIST );
@@ -53,6 +53,7 @@ playlist_t * playlist_Create( vlc_object_t *p_parent )
         msg_Err( p_parent, "out of memory" );
         return NULL;
     }
+    p_parent->p_libvlc->p_playlist = p_playlist;
 
     VariablesInit( p_playlist );
 
@@ -62,6 +63,9 @@ playlist_t * playlist_Create( vlc_object_t *p_parent )
     p_playlist->i_last_input_id = 0;
     p_playlist->p_input = NULL;
 
+    p_playlist->i_vout_destroyed_date = 0;
+    p_playlist->i_sout_destroyed_date = 0;
+
     p_playlist->i_size = 0;
     p_playlist->pp_items = NULL;
     p_playlist->i_all_size = 0;
@@ -70,29 +74,52 @@ playlist_t * playlist_Create( vlc_object_t *p_parent )
     p_playlist->i_input_items = 0;
     p_playlist->pp_input_items = NULL;
 
+    p_playlist->i_random = 0;
+    p_playlist->pp_random = NULL;
+    p_playlist->i_random_index = 0;
+    p_playlist->b_reset_random = VLC_TRUE;
+
+    i_tree = var_CreateGetBool( p_playlist, "playlist-tree" );
+    p_playlist->b_always_tree = (i_tree == 1);
+    p_playlist->b_never_tree = (i_tree == 2);
+
+    p_playlist->b_doing_ml = VLC_FALSE;
+
     p_playlist->p_root_category = playlist_NodeCreate( p_playlist, NULL, NULL);
     p_playlist->p_root_onelevel = playlist_NodeCreate( p_playlist, NULL, NULL);
 
     /* Create playlist and media library */
     p_playlist->p_local_category = playlist_NodeCreate( p_playlist,
                                  _( "Playlist" ),p_playlist->p_root_category );
-    p_playlist->p_ml_category =   playlist_NodeCreate( p_playlist,
-                           _( "Media Library" ), p_playlist->p_root_category );
     p_playlist->p_local_onelevel =  playlist_NodeCreate( p_playlist,
                                 _( "Playlist" ), p_playlist->p_root_onelevel );
-    p_playlist->p_ml_onelevel =  playlist_NodeCreate( p_playlist,
-                           _( "Media Library" ), p_playlist->p_root_onelevel );
+    p_playlist->p_local_category->i_flags |= PLAYLIST_RO_FLAG;
+    p_playlist->p_local_onelevel->i_flags |= PLAYLIST_RO_FLAG;
 
-    /* This is a hack to find it later. Quite ugly, but I haven't found a
-     * better way */
+    /* Link the nodes together. Todo: actually create them from the same input*/
     p_playlist->p_local_onelevel->p_input->i_id =
         p_playlist->p_local_category->p_input->i_id;
-    p_playlist->p_ml_onelevel->p_input->i_id =
-        p_playlist->p_ml_category->p_input->i_id;
+
+    if( config_GetInt( p_playlist, "media-library") )
+    {
+        p_playlist->p_ml_category =   playlist_NodeCreate( p_playlist,
+                           _( "Media Library" ), p_playlist->p_root_category );
+        p_playlist->p_ml_onelevel =  playlist_NodeCreate( p_playlist,
+                           _( "Media Library" ), p_playlist->p_root_onelevel );
+        p_playlist->p_ml_category->i_flags |= PLAYLIST_RO_FLAG;
+        p_playlist->p_ml_onelevel->i_flags |= PLAYLIST_RO_FLAG;
+        p_playlist->p_ml_onelevel->p_input->i_id =
+             p_playlist->p_ml_category->p_input->i_id;
+
+    }
+    else
+    {
+        p_playlist->p_ml_category = p_playlist->p_ml_onelevel = NULL;
+    }
 
     /* Initial status */
     p_playlist->status.p_item = NULL;
-    p_playlist->status.p_node = p_playlist->p_root_onelevel;
+    p_playlist->status.p_node = p_playlist->p_local_onelevel;
     p_playlist->request.b_request = VLC_FALSE;
     p_playlist->status.i_status = PLAYLIST_STOPPED;
 
@@ -100,6 +127,8 @@ playlist_t * playlist_Create( vlc_object_t *p_parent )
     p_playlist->i_order = ORDER_NORMAL;
 
     vlc_object_attach( p_playlist, p_parent );
+
+    playlist_MLLoad( p_playlist );
     return p_playlist;
 }
 
@@ -110,10 +139,15 @@ void playlist_Destroy( playlist_t *p_playlist )
         playlist_ServicesDiscoveryRemove( p_playlist,
                                           p_playlist->pp_sds[0]->psz_module );
     }
+
+    playlist_MLDump( p_playlist );
+
     vlc_thread_join( p_playlist->p_preparse );
+    vlc_thread_join( p_playlist->p_secondary_preparse );
     vlc_thread_join( p_playlist );
 
     vlc_object_detach( p_playlist->p_preparse );
+    vlc_object_detach( p_playlist->p_secondary_preparse );
 
     var_Destroy( p_playlist, "intf-change" );
     var_Destroy( p_playlist, "item-change" );
@@ -121,18 +155,26 @@ void playlist_Destroy( playlist_t *p_playlist )
     var_Destroy( p_playlist, "intf-popmenu" );
     var_Destroy( p_playlist, "intf-show" );
     var_Destroy( p_playlist, "play-and-stop" );
+    var_Destroy( p_playlist, "play-and-exit" );
     var_Destroy( p_playlist, "random" );
     var_Destroy( p_playlist, "repeat" );
     var_Destroy( p_playlist, "loop" );
     var_Destroy( p_playlist, "activity" );
 
-    playlist_LockClear( p_playlist );
+    PL_LOCK;
+    playlist_NodeDelete( p_playlist, p_playlist->p_root_category, VLC_TRUE,
+                         VLC_TRUE );
+    playlist_NodeDelete( p_playlist, p_playlist->p_root_onelevel, VLC_TRUE,
+                         VLC_TRUE );
+    PL_UNLOCK;
 
     if( p_playlist->p_stats )
         free( p_playlist->p_stats );
 
     vlc_mutex_destroy( &p_playlist->gc_lock );
     vlc_object_destroy( p_playlist->p_preparse );
+    vlc_object_destroy( p_playlist->p_secondary_preparse );
+    vlc_object_detach( p_playlist );
     vlc_object_destroy( p_playlist );
 
 }
@@ -182,22 +224,17 @@ static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type,
 void playlist_MainLoop( playlist_t *p_playlist )
 {
     playlist_item_t *p_item = NULL;
-
-    mtime_t    i_vout_destroyed_date = 0;
-    mtime_t    i_sout_destroyed_date = 0;
-
+    vlc_bool_t b_playexit = var_GetBool( p_playlist, "play-and-exit" );
     PL_LOCK
 
     /* First, check if we have something to do */
     /* FIXME : this can be called several times */
     if( p_playlist->request.b_request )
     {
-#ifdef PLAYLIST_DEBUG
-        msg_Dbg(p_playlist, "incoming request - stopping current input" );
-#endif
         /* Stop the existing input */
-        if( p_playlist->p_input )
+        if( p_playlist->p_input && !p_playlist->p_input->b_die )
         {
+            PL_DEBUG( "incoming request - stopping current input" );
             input_StopThread( p_playlist->p_input );
         }
     }
@@ -210,6 +247,7 @@ void playlist_MainLoop( playlist_t *p_playlist )
         {
             int i_activity;
             input_thread_t *p_input;
+            PL_DEBUG( "dead input" );
 
             p_input = p_playlist->p_input;
             p_playlist->p_input = NULL;
@@ -228,13 +266,17 @@ void playlist_MainLoop( playlist_t *p_playlist )
             /* Destroy object */
             vlc_object_destroy( p_input );
 
-            i_vout_destroyed_date = 0;
-            i_sout_destroyed_date = 0;
+            p_playlist->i_vout_destroyed_date = 0;
+            p_playlist->i_sout_destroyed_date = 0;
 
             if( p_playlist->status.p_item->i_flags
                 & PLAYLIST_REMOVE_FLAG )
             {
+                 PL_DEBUG( "%s was marked for deletion, deleting",
+                                 PLI_NAME( p_playlist->status.p_item  ) );
                  playlist_ItemDelete( p_playlist->status.p_item );
+                 if( p_playlist->request.p_item == p_playlist->status.p_item )
+                     p_playlist->request.p_item = NULL;
                  p_playlist->status.p_item = NULL;
             }
 
@@ -247,12 +289,13 @@ void playlist_MainLoop( playlist_t *p_playlist )
         /* This input is dying, let it do */
         else if( p_playlist->p_input->b_die )
         {
-            ;
+            PL_DEBUG( "dying input" );
         }
         /* This input has finished, ask it to die ! */
         else if( p_playlist->p_input->b_error
                   || p_playlist->p_input->b_eof )
         {
+            PL_DEBUG( "finished input" );
             input_StopThread( p_playlist->p_input );
             /* Select the next playlist item */
             PL_UNLOCK
@@ -260,13 +303,13 @@ void playlist_MainLoop( playlist_t *p_playlist )
         }
         else if( p_playlist->p_input->i_state != INIT_S )
         {
-            PL_UNLOCK
-            i_vout_destroyed_date =
+            PL_UNLOCK;
+            p_playlist->i_vout_destroyed_date =
                 ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT,
-                                        i_vout_destroyed_date );
-            i_sout_destroyed_date =
+                                        p_playlist->i_vout_destroyed_date );
+            p_playlist->i_sout_destroyed_date =
                 ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT,
-                                        i_sout_destroyed_date );
+                                        p_playlist->i_sout_destroyed_date );
             PL_LOCK
         }
     }
@@ -283,7 +326,7 @@ void playlist_MainLoop( playlist_t *p_playlist )
               ( p_playlist->request.b_request &&
                 p_playlist->request.i_status != PLAYLIST_STOPPED ) )
          {
-             msg_Dbg( p_playlist, "Starting new item" );
+             msg_Dbg( p_playlist, "starting new item" );
              stats_TimerStart( p_playlist, "Playlist walk",
                                   STATS_TIMER_PLAYLIST_WALK );
              p_item = playlist_NextItem( p_playlist );
@@ -292,6 +335,11 @@ void playlist_MainLoop( playlist_t *p_playlist )
              if( p_item == NULL )
              {
                 msg_Dbg( p_playlist, "nothing to play" );
+                if( b_playexit == VLC_TRUE )
+                {
+                    msg_Info( p_playlist, "end of playlist, exiting" );
+                    p_playlist->p_libvlc->b_die = VLC_TRUE;
+                }
                 p_playlist->status.i_status = PLAYLIST_STOPPED;
                 PL_UNLOCK
                 return;
@@ -300,18 +348,19 @@ void playlist_MainLoop( playlist_t *p_playlist )
          }
          else
          {
-             if( p_item && p_playlist->status.p_item &&
+             if( p_playlist->status.p_item &&
                  p_playlist->status.p_item->i_flags & PLAYLIST_REMOVE_FLAG )
              {
-                 playlist_ItemDelete( p_item );
+                 PL_DEBUG( "deleting item marked for deletion" );
+                 playlist_ItemDelete( p_playlist->status.p_item );
                  p_playlist->status.p_item = NULL;
              }
 
              /* Collect garbage */
              PL_UNLOCK
-             i_sout_destroyed_date =
+             p_playlist->i_sout_destroyed_date =
              ObjectGarbageCollector( p_playlist, VLC_OBJECT_SOUT, mdate() );
-             i_vout_destroyed_date =
+             p_playlist->i_vout_destroyed_date =
              ObjectGarbageCollector( p_playlist, VLC_OBJECT_VOUT, mdate() );
              PL_LOCK
          }
@@ -397,16 +446,28 @@ void playlist_LastLoop( playlist_t *p_playlist )
 void playlist_PreparseLoop( playlist_preparse_t *p_obj )
 {
     playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
+    input_item_t *p_current;
     int i_activity;
+    uint32_t i_m, i_o;
 
-    vlc_mutex_lock( &p_obj->object_lock );
-
-    if( p_obj->i_waiting > 0 )
+    while( !p_playlist->b_die )
     {
-        input_item_t *p_current = p_playlist->p_preparse->pp_waiting[0];
+        vlc_mutex_lock( &p_obj->object_lock );
+        while( p_obj->i_waiting == 0 )
+        {
+            vlc_cond_wait( &p_obj->object_wait, &p_obj->object_lock );
+            if( p_playlist->b_die )
+            {
+                vlc_mutex_unlock( &p_obj->object_lock );
+                return;
+            }
+        }
+
+        p_current = p_obj->pp_waiting[0];
         REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 );
         vlc_mutex_unlock( &p_obj->object_lock );
-        vlc_mutex_lock( &p_playlist->object_lock );
+
+        PL_LOCK;
         if( p_current )
         {
             vlc_bool_t b_preparsed = VLC_FALSE;
@@ -422,29 +483,104 @@ void playlist_PreparseLoop( playlist_preparse_t *p_obj )
                 b_preparsed = VLC_TRUE;
                 stats_TimerStart( p_playlist, "Preparse run",
                                   STATS_TIMER_PREPARSE );
+                PL_UNLOCK;
                 input_Preparse( p_playlist, p_current );
+                PL_LOCK;
                 stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
             }
-            vlc_mutex_unlock( &p_playlist->object_lock );
+            PL_UNLOCK;
             if( b_preparsed )
             {
-                var_SetInteger( p_playlist, "item-change",
-                                p_current->i_id );
+                p_current->p_meta->i_status |= ITEM_PREPARSED;
+                var_SetInteger( p_playlist, "item-change", p_current->i_id );
+            }
+            PL_LOCK;
+
+            /* If we haven't retrieved enough meta, add to secondary queue
+             * which will run the "meta fetchers"
+             * TODO:
+             *  don't do this for things we won't get meta for, like
+             *  videos
+             */
+            if( !input_MetaSatisfied( p_playlist, p_current, &i_m, &i_o,
+                                      VLC_TRUE ) )
+            {
+                preparse_item_t p;
+                p.p_item = p_current;
+                p.b_fetch_art = VLC_FALSE;
+                vlc_mutex_lock( &p_playlist->p_secondary_preparse->object_lock);
+                INSERT_ELEM( p_playlist->p_secondary_preparse->p_waiting,
+                             p_playlist->p_secondary_preparse->i_waiting,
+                             p_playlist->p_secondary_preparse->i_waiting,
+                             p );
+                vlc_mutex_unlock(
+                            &p_playlist->p_secondary_preparse->object_lock);
+                vlc_cond_signal(
+                            &p_playlist->p_secondary_preparse->object_wait );
             }
-            vlc_gc_decref( p_current );
+            else
+                vlc_gc_decref( p_current );
+            PL_UNLOCK;
         }
         else
+            PL_UNLOCK;
+
+        vlc_mutex_lock( &p_obj->object_lock );
+        i_activity = var_GetInteger( p_playlist, "activity" );
+        if( i_activity < 0 ) i_activity = 0;
+        vlc_mutex_unlock( &p_obj->object_lock );
+        /* Sleep at least 1ms */
+        msleep( (i_activity+1) * 1000 );
+    }
+}
+
+/** Main loop for secondary preparser queue */
+void playlist_SecondaryPreparseLoop( playlist_secondary_preparse_t *p_obj )
+{
+    playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
+    vlc_bool_t b_fetch_art;
+    input_item_t *p_item;
+    int i_activity;
+
+    while( !p_playlist->b_die )
+    {
+        vlc_mutex_lock( &p_obj->object_lock );
+        while( p_obj->i_waiting == 0 )
         {
-            vlc_mutex_unlock( &p_playlist->object_lock );
+            vlc_cond_wait( &p_obj->object_wait, &p_obj->object_lock );
+            if( p_playlist->b_die )
+            {
+                vlc_mutex_unlock( &p_obj->object_lock );
+                return;
+            }
+        }
+
+        b_fetch_art = p_obj->p_waiting->b_fetch_art;
+        p_item = p_obj->p_waiting->p_item;
+        REMOVE_ELEM( p_obj->p_waiting, p_obj->i_waiting, 0 );
+        vlc_mutex_unlock( &p_obj->object_lock );
+        if( p_item )
+        {
+            if( !b_fetch_art )
+            {
+                input_MetaFetch( p_playlist, p_item );
+                p_item->p_meta->i_status |= ITEM_META_FETCHED;
+            }
+            else
+            {
+                input_ArtFetch( p_playlist, p_item );
+                p_item->p_meta->i_status |= ITEM_ART_FETCHED;
+            }
+            var_SetInteger( p_playlist, "item-change", p_item->i_id );
+            vlc_gc_decref( p_item );
         }
         vlc_mutex_lock( &p_obj->object_lock );
-        i_activity var_GetInteger( p_playlist, "activity" );
+        i_activity = var_GetInteger( p_playlist, "activity" );
         if( i_activity < 0 ) i_activity = 0;
         vlc_mutex_unlock( &p_obj->object_lock );
+        /* Sleep at least 1ms */
         msleep( (i_activity+1) * 1000 );
-        return;
     }
-    vlc_mutex_unlock( &p_obj->object_lock );
 }
 
 static void VariablesInit( playlist_t *p_playlist )
@@ -480,6 +616,7 @@ static void VariablesInit( playlist_t *p_playlist )
 
     /* Variables to control playback */
     var_CreateGetBool( p_playlist, "play-and-stop" );
+    var_CreateGetBool( p_playlist, "play-and-exit" );
     var_CreateGetBool( p_playlist, "random" );
     var_CreateGetBool( p_playlist, "repeat" );
     var_CreateGetBool( p_playlist, "loop" );