X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fplaylist%2Fplaylist.c;h=c3195f4071c19c3070c2fa8674b82b8166369110;hb=e611fdaed9c43584597eba1d1a7002cda5c9961a;hp=23b67811573d433e056f6bcf59a7321afc7c0ce7;hpb=82f53048eacbf2c96f23f944707676ea7796b699;p=vlc diff --git a/src/playlist/playlist.c b/src/playlist/playlist.c index 23b6781157..c3195f4071 100644 --- a/src/playlist/playlist.c +++ b/src/playlist/playlist.c @@ -1,11 +1,11 @@ /***************************************************************************** * playlist.c : Playlist management functions ***************************************************************************** - * Copyright (C) 1999-2004 VideoLAN + * Copyright (C) 1999-2004 the VideoLAN team * $Id$ * * Authors: Samuel Hocevar - * Clément Stenac + * Clément Stenac * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #include /* free(), strtol() */ #include /* sprintf() */ @@ -32,11 +32,13 @@ #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" ) -#define PLAYLIST_PROFILE 1 +#undef PLAYLIST_PROFILE #undef PLAYLIST_DEBUG /***************************************************************************** @@ -47,11 +49,39 @@ static void RunPreparse( playlist_preparse_t * ); 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 @@ -107,6 +137,8 @@ playlist_t * __playlist_Create ( vlc_object_t *p_parent ) var_CreateGetBool( p_playlist, "loop" ); /* Initialise data structures */ + vlc_mutex_init( p_playlist, &p_playlist->gc_lock ); + p_playlist->i_last_id = 0; p_playlist->b_go_next = VLC_TRUE; p_playlist->p_input = NULL; @@ -118,32 +150,35 @@ playlist_t * __playlist_Create ( vlc_object_t *p_parent ) p_playlist->i_index = -1; p_playlist->i_size = 0; p_playlist->pp_items = NULL; + p_playlist->i_all_size = 0; + p_playlist->pp_all_items = 0; playlist_ViewInsert( p_playlist, VIEW_CATEGORY, TITLE_CATEGORY ); - playlist_ViewInsert( p_playlist, VIEW_SIMPLE, TITLE_SIMPLE ); playlist_ViewInsert( p_playlist, VIEW_ALL, TITLE_ALL ); p_view = playlist_ViewFind( p_playlist, VIEW_CATEGORY ); - p_playlist->p_general = playlist_NodeCreate( p_playlist, VIEW_CATEGORY, - _( "General" ), p_view->p_root ); + p_playlist->p_general = + playlist_NodeCreate( p_playlist, VIEW_CATEGORY, + _( "General" ), p_view->p_root ); p_playlist->p_general->i_flags |= PLAYLIST_RO_FLAG; /* Set startup status * We set to simple view on startup for interfaces that don't do * anything */ - p_view = playlist_ViewFind( p_playlist, VIEW_SIMPLE ); - p_playlist->status.i_view = VIEW_SIMPLE; + p_view = playlist_ViewFind( p_playlist, VIEW_CATEGORY ); + p_playlist->status.i_view = VIEW_CATEGORY; p_playlist->status.p_item = NULL; p_playlist->status.p_node = p_view->p_root; p_playlist->request.b_request = VLC_FALSE; p_playlist->status.i_status = PLAYLIST_STOPPED; - - p_playlist->i_last_id = 0; p_playlist->i_sort = SORT_ID; p_playlist->i_order = ORDER_NORMAL; + p_playlist->p_stats = (global_stats_t *)malloc( sizeof( global_stats_t ) ); + vlc_mutex_init( p_playlist, &p_playlist->p_stats->lock ); + /* Finally, launch the thread ! */ if( vlc_thread_create( p_playlist, "playlist", RunThread, VLC_THREAD_PRIORITY_LOW, VLC_TRUE ) ) @@ -163,8 +198,12 @@ playlist_t * __playlist_Create ( vlc_object_t *p_parent ) return NULL; } + // Preparse p_playlist->p_preparse->i_waiting = 0; - p_playlist->p_preparse->pp_waiting = NULL; + p_playlist->p_preparse->pi_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", @@ -194,10 +233,15 @@ int playlist_Destroy( playlist_t * p_playlist ) int i; p_playlist->b_die = 1; - for( i = 0 ; i< p_playlist->i_sds ; i++ ) + while( p_playlist->i_sds ) { playlist_ServicesDiscoveryRemove( p_playlist, - p_playlist->pp_sds[i]->psz_module ); + 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 ); @@ -227,6 +271,10 @@ int playlist_Destroy( playlist_t * p_playlist ) free( p_view ); } + 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 ); @@ -246,6 +294,30 @@ int playlist_Destroy( playlist_t * p_playlist ) * \param variable number of arguments * \return VLC_SUCCESS or an error */ +int playlist_LockControl( playlist_t * p_playlist, int i_query, ... ) +{ + va_list args; + int i_result; + va_start( args, i_query ); + vlc_mutex_lock( &p_playlist->object_lock ); + i_result = playlist_vaControl( p_playlist, i_query, args ); + va_end( args ); + vlc_mutex_unlock( &p_playlist->object_lock ); + return i_result; +} + +/** + * Do a playlist action. + * + * If there is something in the playlist then you can do playlist actions. + * + * Playlist lock must be taken when calling this function + * + * \param p_playlist the playlist to do the command on + * \param i_query the command to do + * \param variable number of arguments + * \return VLC_SUCCESS or an error + */ int playlist_Control( playlist_t * p_playlist, int i_query, ... ) { va_list args; @@ -260,17 +332,16 @@ int playlist_Control( playlist_t * p_playlist, int i_query, ... ) int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) { playlist_view_t *p_view; + playlist_item_t *p_item, *p_node; + int i_view; vlc_value_t val; - vlc_mutex_lock( &p_playlist->object_lock ); - #ifdef PLAYLIST_PROFILE p_playlist->request_date = mdate(); #endif if( p_playlist->i_size <= 0 ) { - vlc_mutex_unlock( &p_playlist->object_lock ); return VLC_EGENERIC; } @@ -279,14 +350,17 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) 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: + p_item = (playlist_item_t *)va_arg( args, playlist_item_t * ); + if ( p_item == NULL || p_item->input.psz_uri == NULL ) + return VLC_EGENERIC; p_playlist->status.i_status = PLAYLIST_RUNNING; p_playlist->request.i_skip = 0; p_playlist->request.b_request = VLC_TRUE; - p_playlist->request.p_item = (playlist_item_t *)va_arg( args, - playlist_item_t *); + p_playlist->request.p_item = p_item; p_playlist->request.i_view = p_playlist->status.i_view; p_view = playlist_ViewFind( p_playlist, p_playlist->status.i_view ); if( p_view ) @@ -300,19 +374,25 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) break; case PLAYLIST_VIEWPLAY: + 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 )) + { + p_playlist->status.i_status = PLAYLIST_STOPPED; + p_playlist->request.b_request = VLC_TRUE; + return VLC_SUCCESS; + } p_playlist->status.i_status = PLAYLIST_RUNNING; p_playlist->request.i_skip = 0; p_playlist->request.b_request = VLC_TRUE; - p_playlist->request.i_view = (int)va_arg( args,int ); - p_playlist->request.p_node = (playlist_item_t *)va_arg( args, - playlist_item_t *); - p_playlist->request.p_item = (playlist_item_t *)va_arg( args, - playlist_item_t *); - - /* 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 ) + p_playlist->request.i_view = i_view; + p_playlist->request.p_node = p_node; + p_playlist->request.p_item = p_item; + + /* 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; } @@ -343,6 +423,7 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) 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; @@ -373,11 +454,17 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) break; case PLAYLIST_SKIP: + p_playlist->request.i_view = p_playlist->status.i_view; if( p_playlist->status.i_view > -1 ) { 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; @@ -392,12 +479,11 @@ int playlist_vaControl( playlist_t * p_playlist, int i_query, va_list args ) break; default: - msg_Err( p_playlist, "unimplemented playlist query" ); + msg_Err( p_playlist, "unknown playlist query" ); return VLC_EBADVAR; break; } - vlc_mutex_unlock( &p_playlist->object_lock ); return VLC_SUCCESS; } @@ -405,11 +491,44 @@ int playlist_PreparseEnqueue( playlist_t *p_playlist, input_item_t *p_item ) { vlc_mutex_lock( &p_playlist->p_preparse->object_lock ); - INSERT_ELEM( p_playlist->p_preparse->pp_waiting, + INSERT_ELEM( p_playlist->p_preparse->pi_waiting, p_playlist->p_preparse->i_waiting, p_playlist->p_preparse->i_waiting, - p_item ); + p_item->i_id ); + vlc_mutex_unlock( &p_playlist->p_preparse->object_lock ); + 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->pi_waiting, + p_playlist->p_preparse->i_waiting, + p_playlist->p_preparse->i_waiting, + (p_item->input.i_id) ); + } + 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; } @@ -429,6 +548,7 @@ static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type, } else { + vlc_mutex_lock( &p_playlist->gc_lock ); while( ( p_obj = vlc_object_find( p_playlist, i_type, FIND_CHILD ) ) ) { if( p_obj->p_parent != (vlc_object_t*)p_playlist ) @@ -439,7 +559,7 @@ static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type, } if( i_type == VLC_OBJECT_VOUT ) { - msg_Dbg( p_playlist, "garbage collector destroying 1 vout" ); + msg_Dbg( p_playlist, "garbage collector destroys 1 vout" ); vlc_object_detach( p_obj ); vlc_object_release( p_obj ); vout_Destroy( (vout_thread_t *)p_obj ); @@ -450,6 +570,7 @@ static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type, sout_DeleteInstance( (sout_instance_t*)p_obj ); } } + vlc_mutex_unlock( &p_playlist->gc_lock ); return 0; } } @@ -460,11 +581,13 @@ static mtime_t ObjectGarbageCollector( playlist_t *p_playlist, int i_type, static void RunThread ( playlist_t *p_playlist ) { vlc_object_t *p_obj; - playlist_item_t *p_item; + playlist_item_t *p_item = NULL; mtime_t i_vout_destroyed_date = 0; mtime_t i_sout_destroyed_date = 0; + int i_loops = 0; + playlist_item_t *p_autodelete_item = NULL; /* Tell above that we're ready */ @@ -472,6 +595,20 @@ static void RunThread ( playlist_t *p_playlist ) while( !p_playlist->b_die ) { + i_loops++; + if( p_playlist->p_interaction ) + { + stats_TimerStart( p_playlist, "Interaction thread", + STATS_TIMER_INTERACTION ); + intf_InteractionManage( p_playlist ); + stats_TimerStop( p_playlist, STATS_TIMER_INTERACTION ); + } + + if( i_loops %5 == 0 && p_playlist->p_stats ) + { + stats_ComputeGlobalStats( p_playlist, p_playlist->p_stats ); + } + vlc_mutex_lock( &p_playlist->object_lock ); /* First, check if we have something to do */ @@ -497,6 +634,14 @@ static void RunThread ( playlist_t *p_playlist ) /* 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 ) { @@ -522,14 +667,21 @@ static void RunThread ( playlist_t *p_playlist ) i_vout_destroyed_date = 0; i_sout_destroyed_date = 0; + if( p_playlist->status.p_item->i_flags + & PLAYLIST_REMOVE_FLAG ) + { + playlist_ItemDelete( p_item ); + p_playlist->status.p_item = NULL; + } + continue; } - /* This input is dying, let him do */ + /* This input is dying, let it do */ else if( p_playlist->p_input->b_die ) { ; } - /* This input has finished, ask him to die ! */ + /* This input has finished, ask it to die ! */ else if( p_playlist->p_input->b_error || p_playlist->p_input->b_eof ) { @@ -561,8 +713,10 @@ static void RunThread ( playlist_t *p_playlist ) { /* Start another input. * Get the next item to play */ + stats_TimerStart( p_playlist, "Playlist walk", + STATS_TIMER_PLAYLIST_WALK ); p_item = NextItem( p_playlist ); - + stats_TimerStop( p_playlist, STATS_TIMER_PLAYLIST_WALK ); /* We must stop */ if( p_item == NULL ) @@ -588,6 +742,13 @@ static void RunThread ( playlist_t *p_playlist ) } 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 = @@ -645,7 +806,7 @@ static void RunThread ( playlist_t *p_playlist ) } else if( p_playlist->p_input->b_die ) { - /* This input is dying, leave him alone */ + /* This input is dying, leave it alone */ ; } else if( p_playlist->p_input->b_error || p_playlist->p_input->b_eof ) @@ -697,11 +858,40 @@ static void RunPreparse ( playlist_preparse_t *p_obj ) if( p_obj->i_waiting > 0 ) { - input_item_t *p_current = p_obj->pp_waiting[0]; - REMOVE_ELEM( p_obj->pp_waiting, p_obj->i_waiting, 0 ); + int i_current_id = p_obj->pi_waiting[0]; + playlist_item_t *p_current; + REMOVE_ELEM( p_obj->pi_waiting, p_obj->i_waiting, 0 ); vlc_mutex_unlock( &p_obj->object_lock ); - input_Preparse( p_playlist, p_current ); - var_SetInteger( p_playlist, "item-change", p_current->i_id ); + vlc_mutex_lock( &p_playlist->object_lock ); + + p_current = playlist_ItemGetById( p_playlist, i_current_id ); + if( p_current ) + { + vlc_bool_t b_preparsed = VLC_FALSE; + if( strncmp( p_current->input.psz_uri, "http:", 5 ) && + strncmp( p_current->input.psz_uri, "rtsp:", 5 ) && + strncmp( p_current->input.psz_uri, "udp:", 4 ) && + strncmp( p_current->input.psz_uri, "mms:", 4 ) && + strncmp( p_current->input.psz_uri, "cdda:", 4 ) && + strncmp( p_current->input.psz_uri, "dvd:", 4 ) && + strncmp( p_current->input.psz_uri, "v4l:", 4 ) && + strncmp( p_current->input.psz_uri, "dshow:", 6 ) ) + { + b_preparsed = VLC_TRUE; + stats_TimerStart( p_playlist, "Preparse run", + STATS_TIMER_PREPARSE ); + input_Preparse( p_playlist, &p_current->input ); + stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE ); + } + vlc_mutex_unlock( &p_playlist->object_lock ); + if( b_preparsed ) + { + var_SetInteger( p_playlist, "item-change", + p_current->input.i_id ); + } + } + else + vlc_mutex_unlock( &p_playlist->object_lock ); vlc_mutex_lock( &p_obj->object_lock ); } b_sleep = ( p_obj->i_waiting == 0 ); @@ -727,7 +917,7 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) int i_skip,i_goto,i, i_new, i_count ; playlist_view_t *p_view; - vlc_bool_t b_loop = var_GetBool( p_playlist, "loop"); + vlc_bool_t b_loop = var_GetBool( p_playlist, "loop" ); vlc_bool_t b_random = var_GetBool( p_playlist, "random" ); vlc_bool_t b_repeat = var_GetBool( p_playlist, "repeat" ); vlc_bool_t b_playstop = var_GetBool( p_playlist, "play-and-stop" ); @@ -736,8 +926,6 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) /* Calculate time needed */ int64_t start = mdate(); #endif - - /* Handle quickly a few special cases */ /* No items to play */ @@ -753,7 +941,8 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) } /* 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; @@ -766,7 +955,7 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) } if( !p_playlist->request.b_request && p_playlist->status.p_item && - !(p_playlist->status.p_item->i_flags & PLAYLIST_SKIP_FLAG) ) + !( p_playlist->status.p_item->i_flags & PLAYLIST_SKIP_FLAG ) ) { msg_Dbg( p_playlist, "no-skip mode, stopping") ; return NULL; @@ -776,52 +965,66 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) /* 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; - } - if( !b_loop ) - { + /* 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]; - } + } /* Start the real work */ if( p_playlist->request.b_request ) { +#ifdef PLAYLIST_DEBUG msg_Dbg( p_playlist,"processing request" ); +#endif /* We are not playing from a view */ - if( p_playlist->request.i_view == -1 ) + if( p_playlist->request.i_view == -1 ) { #ifdef PLAYLIST_DEBUG msg_Dbg( p_playlist, "non-view mode request"); #endif /* Directly select the item, just like now */ + p_new = p_playlist->request.p_item; i_skip = p_playlist->request.i_skip; i_goto = p_playlist->request.i_goto; - if( p_playlist->i_index == -1 ) p_playlist->i_index = 0; - p_new = p_playlist->pp_items[p_playlist->i_index]; + if( p_playlist->i_index < 0 ) p_playlist->i_index = 0; + if ( p_new == NULL ) + p_new = p_playlist->pp_items[p_playlist->i_index]; if( i_goto >= 0 && i_goto < p_playlist->i_size ) { @@ -838,6 +1041,11 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) p_playlist->i_index += i_skip; p_new = p_playlist->pp_items[p_playlist->i_index]; } + p_playlist->request.i_skip = 0; + } + if( !( p_new->i_flags & PLAYLIST_SKIP_FLAG ) ) + { + return NULL; } } else @@ -859,7 +1067,7 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) p_playlist->status.i_view = p_playlist->request.i_view; if( !p_view ) { - msg_Err( p_playlist, "p_view is NULL and should not! (FIXME)" ); + msg_Err( p_playlist, "p_view is NULL and should not! (requested view is %i", p_playlist->request.i_view ); } else if( i_skip > 0 ) { @@ -872,19 +1080,15 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) p_new ); if( p_new == NULL ) { - if( b_loop ) - { - 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; - } +#ifdef PLAYLIST_DEBUG + msg_Dbg( p_playlist, "looping" ); +#endif + 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; } } } @@ -897,6 +1101,13 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) 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; } @@ -912,18 +1123,20 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) if( p_playlist->status.i_view == -1 ) { +#ifdef PLAYLIST_DEBUG + msg_Dbg( p_playlist, "no request - old mode" ); +#endif if( p_playlist->i_index + 1 < p_playlist->i_size ) { p_playlist->i_index++; p_new = p_playlist->pp_items[p_playlist->i_index]; - if( !(p_new->i_flags & PLAYLIST_SKIP_FLAG) ) + if( !( p_new->i_flags & PLAYLIST_SKIP_FLAG ) ) { return NULL; } } else { - msg_Dbg( p_playlist,"finished" ); if( b_loop && p_playlist->i_size > 0) { p_playlist->i_index = 0; @@ -936,6 +1149,9 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) /* We are playing with a view */ else { +#ifdef PLAYLIST_DEBUG + msg_Dbg( p_playlist,"no request - from a view" ); +#endif playlist_view_t *p_view = playlist_ViewFind( p_playlist, p_playlist->status.i_view ); @@ -952,12 +1168,17 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) p_playlist->status.p_item ); if( p_new == NULL && b_loop ) { +#ifdef PLAYLIST_DEBUG + msg_Dbg( p_playlist, "looping" ); +#endif 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) ) + return NULL; } } } @@ -976,58 +1197,12 @@ static playlist_item_t * NextItem( playlist_t *p_playlist ) if( p_new == NULL ) { - msg_Info( p_playlist, "Nothing to play" ); - } - return p_new; -} - - -#if 0 - - -static void SkipItem( playlist_t *p_playlist, int i_arg ) -{ - int i_oldindex = p_playlist->i_index; - vlc_bool_t b_random, b_repeat, b_loop; - vlc_value_t val; - int i_count; - - /* Increment */ - else if( !b_repeat ) - { - p_playlist->i_index += i_arg; - } - - /* Boundary check */ - if( p_playlist->i_index >= p_playlist->i_size ) - { - if( p_playlist->i_status == PLAYLIST_STOPPED || b_random || b_loop ) - { - p_playlist->i_index -= p_playlist->i_size - * ( p_playlist->i_index / p_playlist->i_size ); - } - else - { - /* Don't loop by default: stop at playlist end */ - p_playlist->i_index = i_oldindex; - p_playlist->i_status = PLAYLIST_STOPPED; - } - } - else if( p_playlist->i_index < 0 ) - { - p_playlist->i_index = p_playlist->i_size - 1; + msg_Info( p_playlist, "nothing to play" ); } - /* Check that the item is enabled */ - if( p_playlist->pp_items[p_playlist->i_index]->b_enabled == VLC_FALSE && - p_playlist->i_enabled != 0) - { - SkipItem( p_playlist , 1 ); - } + return p_new; } -#endif - /***************************************************************************** * PlayItem: start the input thread for an item ****************************************************************************/ @@ -1053,9 +1228,6 @@ static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item ) 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); @@ -1065,19 +1237,3 @@ static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item ) 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; -}