#include "vlc_playlist.h"
+#include "vlc_interaction.h"
+
#define TITLE_CATEGORY N_( "By category" )
#define TITLE_SIMPLE N_( "Manually added" )
#define TITLE_ALL N_( "All items, unsorted" )
static playlist_item_t * NextItem ( playlist_t * );
static int PlayItem ( playlist_t *, playlist_item_t * );
-static int ItemChange( vlc_object_t *, const char *,
- vlc_value_t, vlc_value_t, void * );
-
int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args );
+void playlist_PreparseEnqueueItemSub( playlist_t *, playlist_item_t * );
+
+playlist_item_t *playlist_RecursiveFindLast(playlist_t *p_playlist,
+ playlist_item_t *p_node );
+
+/*****************************************************************************
+ * Helper Function for NextItem
+ *****************************************************************************/
+
+playlist_item_t *playlist_RecursiveFindLast(playlist_t *p_playlist,
+ playlist_item_t *p_node )
+{
+ int i;
+ playlist_item_t *p_item;
+ for ( i = p_node->i_children - 1; i >= 0; i-- )
+ {
+ if( p_node->pp_children[i]->i_children == -1 )
+ return p_node->pp_children[i];
+ else if(p_node->pp_children[i]->i_children > 0)
+ {
+ p_item = playlist_RecursiveFindLast( p_playlist,
+ p_node->pp_children[i] );
+ if ( p_item != NULL )
+ return p_item;
+ }
+ else if( i == 0 )
+ return NULL;
+ }
+ return NULL;
+}
+
/**
* Create playlist
return NULL;
}
+ // Preparse
p_playlist->p_preparse->i_waiting = 0;
p_playlist->p_preparse->pp_waiting = NULL;
+ // Interaction
+ p_playlist->p_interaction = NULL;
+
vlc_object_attach( p_playlist->p_preparse, p_playlist );
if( vlc_thread_create( p_playlist->p_preparse, "preparser",
RunPreparse, VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) )
p_playlist->pp_sds[0]->psz_module );
}
+ if( p_playlist->p_interaction )
+ {
+ intf_InteractionDestroy( p_playlist->p_interaction );
+ }
+
vlc_thread_join( p_playlist->p_preparse );
vlc_thread_join( p_playlist );
case PLAYLIST_STOP:
p_playlist->status.i_status = PLAYLIST_STOPPED;
p_playlist->request.b_request = VLC_TRUE;
+ p_playlist->request.p_item = NULL;
break;
case PLAYLIST_ITEMPLAY:
i_view = (int)va_arg( args,int );
p_node = (playlist_item_t *)va_arg( args, playlist_item_t * );
p_item = (playlist_item_t *)va_arg( args, playlist_item_t * );
- if ( p_node == NULL || (p_item != NULL && p_item->input.psz_uri
- == NULL ))
+ if ( p_node == NULL ) //|| (p_item != NULL && p_item->input.psz_uri
+ // == NULL ))
{
p_playlist->status.i_status = PLAYLIST_STOPPED;
p_playlist->request.b_request = VLC_TRUE;
p_playlist->request.p_node = p_node;
p_playlist->request.p_item = p_item;
- /* If we select a node, play only it.
- * If we select an item, continue */
- if( p_playlist->request.p_item == NULL ||
- ! p_playlist->request.p_node->i_flags & PLAYLIST_SKIP_FLAG )
+ /* Don't go further if the node doesn't want to */
+ if( ! p_playlist->request.p_node->i_flags & PLAYLIST_SKIP_FLAG )
{
p_playlist->b_go_next = VLC_FALSE;
}
case PLAYLIST_AUTOPLAY:
p_playlist->status.i_status = PLAYLIST_RUNNING;
+ p_playlist->status.p_node = p_playlist->p_general;
p_playlist->request.b_request = VLC_FALSE;
break;
break;
case PLAYLIST_SKIP:
+ p_playlist->request.i_view = p_playlist->status.i_view;
if( p_playlist->status.i_view > -1 )
{
- p_playlist->request.i_view = p_playlist->status.i_view;
p_playlist->request.p_node = p_playlist->status.p_node;
p_playlist->request.p_item = p_playlist->status.p_item;
}
+ else
+ {
+ p_playlist->request.p_node = NULL;
+ p_playlist->request.p_item = NULL;
+ }
p_playlist->request.i_skip = (int) va_arg( args, int );
p_playlist->request.b_request = VLC_TRUE;
break;
break;
default:
- msg_Err( p_playlist, "unimplemented playlist query" );
+ msg_Err( p_playlist, "unknown playlist query" );
return VLC_EBADVAR;
break;
}
return VLC_SUCCESS;
}
+/* Should only be called if playlist and preparser are locked */
+void playlist_PreparseEnqueueItemSub( playlist_t *p_playlist,
+ playlist_item_t *p_item )
+{
+ int i;
+ if( p_item->i_children == -1 )
+ {
+ INSERT_ELEM( p_playlist->p_preparse->pp_waiting,
+ p_playlist->p_preparse->i_waiting,
+ p_playlist->p_preparse->i_waiting,
+ &(p_item->input) );
+ }
+ else
+ {
+ for( i = 0; i < p_item->i_children; i++)
+ {
+ playlist_PreparseEnqueueItemSub( p_playlist,
+ p_item->pp_children[i] );
+ }
+ }
+}
+
+int playlist_PreparseEnqueueItem( playlist_t *p_playlist,
+ playlist_item_t *p_item )
+{
+ vlc_mutex_lock( &p_playlist->object_lock );
+ vlc_mutex_lock( &p_playlist->p_preparse->object_lock );
+ playlist_PreparseEnqueueItemSub( p_playlist, p_item );
+ vlc_mutex_unlock( &p_playlist->p_preparse->object_lock );
+ vlc_mutex_unlock( &p_playlist->object_lock );
+ return VLC_SUCCESS;
+}
+
/* Destroy remaining objects */
static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type,
mtime_t i_vout_destroyed_date = 0;
mtime_t i_sout_destroyed_date = 0;
+ int i_loops;
+
playlist_item_t *p_autodelete_item = NULL;
/* Tell above that we're ready */
while( !p_playlist->b_die )
{
+ i_loops++;
+ if( p_playlist->p_interaction )
+ {
+ intf_InteractionManage( p_playlist );
+ }
+
vlc_mutex_lock( &p_playlist->object_lock );
/* First, check if we have something to do */
/* If there is an input, check that it doesn't need to die. */
if( p_playlist->p_input )
{
+ if( i_loops % 5 == 0 )
+ {
+ stats_ComputeInputStats( p_playlist->p_input,
+ p_playlist->p_input->input.p_item->p_stats );
+// stats_DumpInputStats(
+// p_playlist->p_input->input.p_item->p_stats );
+ }
+
/* This input is dead. Remove it ! */
if( p_playlist->p_input->b_dead )
{
* Get the next item to play */
p_item = NextItem( p_playlist );
-
/* We must stop */
if( p_item == NULL )
{
}
else if( p_playlist->status.i_status == PLAYLIST_STOPPED )
{
+ if( p_item && p_playlist->status.p_item &&
+ p_playlist->status.p_item->i_flags & PLAYLIST_REMOVE_FLAG )
+ {
+ playlist_ItemDelete( p_item );
+ p_playlist->status.p_item = NULL;
+ }
+
/* Collect garbage */
vlc_mutex_unlock( &p_playlist->object_lock );
i_sout_destroyed_date =
}
/* Repeat and play/stop */
- if( !p_playlist->request.b_request && b_repeat == VLC_TRUE )
+ if( !p_playlist->request.b_request && b_repeat == VLC_TRUE &&
+ p_playlist->status.p_item )
{
msg_Dbg( p_playlist,"repeating item" );
return p_playlist->status.p_item;
/* TODO: use the "shuffled view" internally ? */
/* Random case. This is an exception: if request, but request is skip +- 1
* we don't go to next item but select a new random one. */
- if( b_random && (!p_playlist->request.b_request ||
- p_playlist->request.i_skip == 1 || p_playlist->request.i_skip == -1 ) )
+ if( b_random &&
+ ( !p_playlist->request.b_request ||
+ ( p_playlist->request.b_request && ( p_playlist->request.p_item == NULL ||
+ p_playlist->request.i_skip == 1 || p_playlist->request.i_skip == -1 ) ) ) )
{
- srand( (unsigned int)mdate() );
- i_new = 0;
- for( i_count = 0; i_count < p_playlist->i_size - 1 ; i_count ++ )
+ /* how many items to choose from ? */
+ i_count = 0;
+ for ( i = 0; i < p_playlist->i_size; i++ )
{
- i_new =
- (int)((float)p_playlist->i_size * rand() / (RAND_MAX+1.0));
- /* Check if the item has not already been played */
- if( p_playlist->pp_items[i_new]->i_nb_played == 0 )
- break;
+ if ( p_playlist->pp_items[i]->i_nb_played == 0 )
+ i_count++;
}
- if( i_count == p_playlist->i_size )
+ /* Nothing left? */
+ if ( i_count == 0 )
{
- /* The whole playlist has been played: reset the counters */
- while( i_count > 0 )
- {
- p_playlist->pp_items[--i_count]->i_nb_played = 0;
- }
+ /* Don't loop? Exit! */
if( !b_loop )
- {
return NULL;
+ /* Otherwise reset the counter */
+ for ( i = 0; i < p_playlist->i_size; i++ )
+ {
+ p_playlist->pp_items[i]->i_nb_played = 0;
}
+ i_count = p_playlist->i_size;
}
+ srand( (unsigned int)mdate() );
+ i = rand() % i_count + 1 ;
+ /* loop thru the list and count down the unplayed items to the selected one */
+ for ( i_new = 0; i_new < p_playlist->i_size && i > 0; i_new++ )
+ {
+ if ( p_playlist->pp_items[i_new]->i_nb_played == 0 )
+ i--;
+ }
+ i_new--;
+
p_playlist->request.i_skip = 0;
p_playlist->request.b_request = VLC_FALSE;
return p_playlist->pp_items[i_new];
}
p_playlist->request.i_skip = 0;
}
+ if( !( p_new->i_flags & PLAYLIST_SKIP_FLAG ) )
+ {
+ return NULL;
+ }
}
else
{
p_new );
if( p_new == NULL )
{
- if( b_loop )
- {
#ifdef PLAYLIST_DEBUG
- msg_Dbg( p_playlist, "looping" );
+ msg_Dbg( p_playlist, "looping" );
#endif
- p_new = playlist_FindNextFromParent( p_playlist,
- p_playlist->request.i_view,
- p_view->p_root,
- p_playlist->request.p_node,
- NULL );
- if( p_new == NULL ) break;
- }
- else
- {
- break;
- }
+ p_new = playlist_FindNextFromParent( p_playlist,
+ p_playlist->request.i_view,
+ p_view->p_root,
+ p_view->p_root,
+ NULL );
+ if( p_new == NULL ) break;
}
}
}
p_view->p_root,
p_playlist->request.p_node,
p_new );
+ if( p_new == NULL )
+ {
+ /* We reach the beginning of the playlist.
+ Go back to the last item. */
+ p_new = playlist_RecursiveFindLast( p_playlist,
+ p_view->p_root );
+ }
if( p_new == NULL ) break;
}
p_new = playlist_FindNextFromParent( p_playlist,
p_playlist->status.i_view,
p_view->p_root,
- p_playlist->status.p_node,
+ p_view->p_root,
NULL );
}
if( p_new != NULL && !(p_new->i_flags & PLAYLIST_SKIP_FLAG) )
p_playlist->p_input = input_CreateThread( p_playlist, &p_item->input );
- var_AddCallback( p_playlist->p_input, "item-change",
- ItemChange, p_playlist );
-
val.i_int = p_item->input.i_id;
/* unlock the playlist to set the var...mmm */
vlc_mutex_unlock( &p_playlist->object_lock);
return VLC_SUCCESS;
}
-
-/* Forward item change from input */
-static int ItemChange( vlc_object_t *p_obj, const char *psz_var,
- vlc_value_t oldval, vlc_value_t newval, void *param )
-{
- playlist_t *p_playlist = (playlist_t *)param;
-
- //p_playlist->b_need_update = VLC_TRUE;
- var_SetInteger( p_playlist, "item-change", newval.i_int );
-
- /* Update view */
- /* FIXME: Make that automatic */
-// playlist_ViewUpdate( p_playlist, VIEW_S_AUTHOR );
-
- return VLC_SUCCESS;
-}