* 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>
#include <vlc/input.h>
#include "vlc_playlist.h"
#include "vlc_interaction.h"
-
-#undef PLAYLIST_DEBUG
+#include "playlist_internal.h"
/*****************************************************************************
* Local prototypes
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 );
msg_Err( p_parent, "out of memory" );
return NULL;
}
+ p_parent->p_libvlc->p_playlist = p_playlist;
VariablesInit( p_playlist );
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;
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;
p_playlist->i_order = ORDER_NORMAL;
vlc_object_attach( p_playlist, p_parent );
+
+ playlist_MLLoad( p_playlist );
return 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" );
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 );
}
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 );
}
}
{
int i_activity;
input_thread_t *p_input;
+ PL_DEBUG( "dead input" );
p_input = p_playlist->p_input;
p_playlist->p_input = NULL;
/* 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;
}
/* 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
}
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
}
}
( 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 );
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;
}
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
}
{
playlist_t *p_playlist = (playlist_t *)p_obj->p_parent;
int i_activity;
+ uint32_t i_m, i_o;
vlc_mutex_lock( &p_obj->object_lock );
if( p_obj->i_waiting > 0 )
{
- input_item_t *p_current = p_playlist->p_preparse->pp_waiting[0];
+ input_item_t *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;
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 );
}
- vlc_gc_decref( p_current );
+ 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);
+ }
+ else
+ vlc_gc_decref( p_current );
+ PL_UNLOCK;
}
else
- {
- vlc_mutex_unlock( &p_playlist->object_lock );
- }
+ PL_UNLOCK;
+
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 );
msleep( (i_activity+1) * 1000 );
vlc_mutex_unlock( &p_obj->object_lock );
}
+/** 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_mutex_lock( &p_obj->object_lock );
+
+ if( p_obj->i_waiting > 0 )
+ {
+ vlc_bool_t b_fetch_art = p_obj->p_waiting->b_fetch_art;
+ input_item_t *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 );
+ }
+ return;
+ }
+ vlc_mutex_unlock( &p_obj->object_lock );
+}
+
static void VariablesInit( playlist_t *p_playlist )
{
vlc_value_t val;
/* 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" );