Playlist
authorClément Stenac <zorglub@videolan.org>
Sat, 21 Oct 2006 11:09:51 +0000 (11:09 +0000)
committerClément Stenac <zorglub@videolan.org>
Sat, 21 Oct 2006 11:09:51 +0000 (11:09 +0000)
 * Remove the random special case
 * Use the array of currently playing items for all cases
 * Convert array items to array API
 * Replace standard searches in sorted arrays by bsearches
 * Size is not yet fixed (next round).

Array
 * Add reset/value and bsearch functions
 * Add foreach helper

20 files changed:
include/vlc_arrays.h
include/vlc_playlist.h
modules/control/hotkeys.c
modules/control/http/macro.c
modules/gui/macosx/controls.m
modules/gui/macosx/intf.m
modules/gui/macosx/playlist.m
modules/gui/qt4/main_interface.cpp
modules/gui/qt4/menus.cpp
modules/gui/skins2/commands/cmd_input.cpp
src/control/mediacontrol_core.c
src/control/playlist.c
src/input/item.c
src/libvlc.c
src/playlist/control.c
src/playlist/engine.c
src/playlist/item.c
src/playlist/search.c
src/playlist/thread.c
src/playlist/tree.c

index e8802c5..74d279e 100644 (file)
     }
 
 /**
- * Binary search in an array
+ * Binary search in a sorted array. The key must be comparable by < and >
  * \param entries array of entries
  * \param count number of entries
  * \param elem key to check within an entry (like .id, or ->i_id)
@@ -218,6 +218,11 @@ VLC_EXPORT( int, vlc_DictLookup, (dict_t *, int, const char * ) );
     array.i_size = 0;                                                       \
     array.p_elems = NULL;
 
+#define ARRAY_RESET(array)                                                  \
+    array.i_alloc = 0;                                                      \
+    array.i_size = 0;                                                       \
+    free( array.p_elems ); array.p_elems = NULL;
+
 #define ARRAY_APPEND(array, elem) {                                         \
     _ARRAY_GROW1(array);                                                    \
     array.p_elems[array.i_size] = elem;                                     \
@@ -244,4 +249,17 @@ VLC_EXPORT( int, vlc_DictLookup, (dict_t *, int, const char * ) );
     _ARRAY_SHRINK(array);                                                   \
 }
 
+#define ARRAY_VAL(array, pos) array.p_elems[pos]
+
+#define ARRAY_BSEARCH(array, elem, zetype, key, answer) \
+    BSEARCH( array.p_elems, array.i_size, elem, zetype, key, answer)
+
+#define FOREACH_ARRAY( item, array ) { \
+    int fe_idx; \
+    for( fe_idx = 0 ; fe_idx < array.i_size ; fe_idx++ ) \
+    { \
+        item = array.p_elems[fe_idx];
+
+#define FOREACH_END() } }
+
 #endif
index ec497e2..ec33ee3 100644 (file)
 
 #include <assert.h>
 
+TYPEDEF_ARRAY(playlist_item_t*, playlist_item_array_t);
+TYPEDEF_ARRAY(input_item_t*, input_item_array_t);
 /**
- *  \file
- *  This file contain structures and function prototypes related
- *  to the playlist in vlc
- */
-
-/**
+ * \file
+ * This file contain structures and function prototypes related
+ * to the playlist in vlc
+ *
  * \defgroup vlc_playlist Playlist
  * @{
  */
@@ -102,20 +102,15 @@ struct playlist_t
 /*@{*/
     int                   i_enabled; /**< How many items are enabled ? */
 
-    /* Arrays of items */
-    int                   i_size;   /**< total size of the list */
-    playlist_item_t **    pp_items; /**< array of pointers to the
-                                     * playlist items */
-    int                   i_all_size; /**< size of list of items and nodes */
-    playlist_item_t **    pp_all_items; /**< array of pointers to the
-                                         * playlist items and nodes */
-    int                   i_input_items;
-    input_item_t **       pp_input_items;
-
-    int                   i_random;     /**< Number of candidates for random */
-    playlist_item_t **    pp_random;    /**< Random candidate items */
-    int                   i_random_index; /**< Current random item */
-    vlc_bool_t            b_reset_random; /**< Recreate random array ?*/
+    playlist_item_array_t items; /**< Arrays of items */
+    playlist_item_array_t all_items; /**< Array of items and nodes */
+
+    input_item_array_t    input_items; /**< Array of input items */
+
+    playlist_item_array_t current; /**< Items currently being played */
+    int                   i_current_index; /**< Index in current array */
+    /** Reset current item ? */
+    vlc_bool_t            b_reset_currently_playing;
 
     int                   i_last_playlist_id; /**< Last id to an item */
     int                   i_last_input_id ; /**< Last id on an input */
@@ -345,7 +340,7 @@ static inline int playlist_MLAddExt( playlist_t *p_playlist,
                             i_duration, ppsz_options, i_options, VLC_FALSE );
 }
 
-/** Add an input item to the playlist node 
+/** Add an input item to the playlist node
  * \see playlist_AddInput
  */
 static inline int playlist_PlaylistAddInput( playlist_t* p_playlist,
@@ -433,7 +428,7 @@ static inline vlc_bool_t playlist_IsEmpty( playlist_t * p_playlist )
 {
     vlc_bool_t b_empty;
     vlc_mutex_lock( &p_playlist->object_lock );
-    b_empty = p_playlist->i_size == 0;
+    b_empty = p_playlist->items.i_size == 0;
     vlc_mutex_unlock( &p_playlist->object_lock );
     return( b_empty );
 }
index 8c339bc..8fbe4cd 100644 (file)
@@ -796,13 +796,13 @@ static void PlayBookmark( intf_thread_t *p_intf, int i_num )
     var_Get( p_intf, psz_bookmark_name, &val );
 
     char *psz_bookmark = strdup( val.psz_string );
-    for( i = 0; i < p_playlist->i_size; i++)
+    for( i = 0; i < p_playlist->items.i_size; i++)
     {
         if( !strcmp( psz_bookmark,
-                     p_playlist->pp_items[i]->p_input->psz_uri ) )
+                     ARRAY_VAL( p_playlist->items,i )->p_input->psz_uri ) )
         {
             playlist_LockControl( p_playlist, PLAYLIST_VIEWPLAY, NULL,
-                                  p_playlist->pp_items[i] );
+                                  ARRAY_VAL( p_playlist->items, i ) );
             break;
         }
     }
index 7f9d9a1..fe80760 100644 (file)
@@ -398,19 +398,20 @@ void E_(MacroDo)( httpd_file_sys_t *p_args,
                         i_nb_items++;
                     }
 
-                    for( i = p_sys->p_playlist->i_size - 1 ; i >= 0; i-- )
+                    for( i = p_sys->p_playlist->items.i_size - 1 ; i >= 0; i-- )
                     {
                         /* Check if the item is in the keep list */
                         for( j = 0 ; j < i_nb_items ; j++ )
                         {
                             if( p_items[j] ==
-                                p_sys->p_playlist->pp_items[i]->p_input->i_id )
+                                 ARRAY_VAL(p_sys->p_playlist->items,i)
+                                                ->p_input->i_id)
                                 break;
                         }
                         if( j == i_nb_items )
                         {
                             playlist_LockDeleteAllFromInput( p_sys->p_playlist,
-                            p_sys->p_playlist->pp_items[i]->p_input->i_id );
+                           p_sys->p_playlist->items.p_elems[i]->p_input->i_id );
                             msg_Dbg( p_intf, "requested playlist delete: %d",
                                      i );
                         }
index cf69ad3..e872714 100644 (file)
@@ -68,7 +68,7 @@
     playlist_t * p_playlist = pl_Yield( p_intf );
 
     vlc_mutex_lock( &p_playlist->object_lock );
-    if( p_playlist->i_size <= 0 )
+    if( playlist_IsEmpty( p_playlist ) )
     {
         vlc_mutex_unlock( &p_playlist->object_lock );
         vlc_object_release( p_playlist );
     else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
              [[o_mi title] isEqualToString: _NS("Next")] )
     {
-            bEnabled = p_playlist->i_size > 1;
+           /** \todo fix i_size use */
+            bEnabled = p_playlist->items.i_size > 1;
     }
     else if( [[o_mi title] isEqualToString: _NS("Random")] )
     {
index a30fe7a..c163ae7 100644 (file)
@@ -1067,7 +1067,8 @@ static VLCMain *_o_sharedMainInstance = nil;
         vlc_bool_t b_chapters = VLC_FALSE;
 
         playlist_t * p_playlist = pl_Yield( p_intf );
-        b_plmul = p_playlist->i_size > 1;
+       /** \todo fix i_size use */
+        b_plmul = p_playlist->items.i_size > 1;
 
         vlc_object_release( p_playlist );
 
index b81915c..c3aba6c 100644 (file)
@@ -464,14 +464,15 @@ NSLog( @"expandable" );
 
     playlist_t *p_playlist = pl_Yield( VLCIntf );
 
-    if( p_playlist->i_size >= 2 )
+    /** \todo fix i_size use */
+    if( p_playlist->items.i_size >= 2 )
     {
         [o_status_field setStringValue: [NSString stringWithFormat:
-                    _NS("%i items in the playlist"), p_playlist->i_size]];
+                    _NS("%i items in the playlist"), p_playlist->items.i_size]];
     }
     else
     {
-        if( p_playlist->i_size == 0 )
+        if( playlist_IsEmpty( p_playlist ) )
         {
             [o_status_field setStringValue: _NS("No items in the playlist")];
         }
@@ -1366,15 +1367,15 @@ NSLog( @"expandable" );
 
     /* FIXME: playlist->i_size doesn't provide the correct number of items anymore
      * check the playlist API for the fixed function, once zorglub implemented it -- fpk, 9/17/06 */
-
-    if( p_playlist->i_size >= 2 )
+    /** \todo fix i_size use */
+    if( p_playlist->items.i_size >= 2 )
     {
         [o_status_field setStringValue: [NSString stringWithFormat:
-                    _NS("%i items in the playlist"), p_playlist->i_size]];
+                    _NS("%i items in the playlist"), p_playlist->items.i_size]];
     }
     else
     {
-        if( p_playlist->i_size == 0 )
+        if( playlist_IsEmpty( p_playlist ) )
         {
             [o_status_field setStringValue: _NS("No items in the playlist")];
         }
index 341170a..31da1b2 100644 (file)
@@ -556,7 +556,7 @@ void MainInterface::stop()
 }
 void MainInterface::play()
 {
-    if( !THEPL->i_size || !THEPL->i_enabled )
+    if( !playlist_IsEmpty(THEPL) || !THEPL->i_enabled )
     {
         /* The playlist is empty, open a file requester */
         THEDP->simpleOpenDialog();
index 70488e6..df16ea9 100644 (file)
@@ -354,7 +354,7 @@ QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
         else \
             MIM_SADD( qtr("Pause"), "", "", togglePlayPause() ) \
     } \
-    else if( THEPL->i_size && THEPL->i_enabled ) \
+    else if( THEPL->items.i_size && THEPL->i_enabled ) \
         MIM_SADD( qtr("Play"), "", "", togglePlayPause() ) \
     \
     QMenu *intfmenu = InterfacesMenu( p_intf, NULL ); \
index fb0be61..03e1828 100644 (file)
@@ -35,10 +35,8 @@ void CmdPlay::execute()
         return;
     }
 
-    if( pPlaylist->i_size )
-    {
+    if( !playlist_IsEmpty( pPlaylist ) )
         playlist_Play( pPlaylist );
-    }
     else
     {
         // If the playlist is empty, open a file requester instead
index 18f7800..7cf9e0b 100644 (file)
@@ -220,7 +220,7 @@ mediacontrol_start( mediacontrol_Instance *self,
     }
 
     vlc_mutex_lock( &p_playlist->object_lock );
-    if( p_playlist->i_size )
+    if( p_playlist->items.i_size )
     {
         int i_from;
         char *psz_from = NULL;
@@ -360,13 +360,13 @@ mediacontrol_playlist_get_list( mediacontrol_Instance *self,
     }
 
     vlc_mutex_lock( &p_playlist->object_lock );
-    i_playlist_size = p_playlist->i_size;
+    i_playlist_size = p_playlist->items.i_size;
 
     retval = mediacontrol_PlaylistSeq__alloc( i_playlist_size );
 
     for( i_index = 0 ; i_index < i_playlist_size ; i_index++ )
     {
-        retval->data[i_index] = strdup( p_playlist->pp_items[i_index]->p_input->psz_uri );
+        retval->data[i_index] = strdup( ARRAY_VAL(p_playlist->items, i_index)->p_input->psz_uri );
     }
     vlc_mutex_unlock( &p_playlist->object_lock );
 
index 038f60d..cfe82b4 100644 (file)
@@ -44,7 +44,7 @@ void libvlc_playlist_play( libvlc_instance_t *p_instance, int i_id,
     assert( PL );
     ///\todo Handle additionnal options
 
-    if( PL->i_size == 0 ) RAISEVOID( "Empty playlist" );
+    if( PL->items.i_size == 0 ) RAISEVOID( "Empty playlist" );
     if( i_id > 0 )
     {
         playlist_item_t *p_item = playlist_ItemGetById( PL,
@@ -136,7 +136,7 @@ int libvlc_playlist_items_count( libvlc_instance_t *p_instance,
                                  libvlc_exception_t *p_e )
 {
     assert( PL );
-    return PL->i_size;
+    return PL->items.i_size;
 }
 
 libvlc_input_t * libvlc_playlist_get_input( libvlc_instance_t *p_instance,
index f07b1aa..24975f2 100644 (file)
@@ -76,15 +76,10 @@ static void input_ItemDestroy ( gc_object_t *p_this )
     playlist_t *p_playlist = pl_Yield( p_obj );
     input_ItemClean( p_input );
 
-    for( i = 0 ; i< p_playlist->i_input_items ; i++ )
-    {
-        if( p_playlist->pp_input_items[i]->i_id == p_input->i_id )
-        {
-            REMOVE_ELEM( p_playlist->pp_input_items,
-                         p_playlist->i_input_items, i );
-            break;
-        }
-    }
+    ARRAY_BSEARCH( p_playlist->input_items,->i_id, int, p_input->i_id, i);
+    if( i != -1 )
+        ARRAY_REMOVE( p_playlist->input_items, i);
+
     pl_Release( p_obj );
     free( p_input );
 }
@@ -186,22 +181,10 @@ int input_ItemAddInfo( input_item_t *p_i,
 
 input_item_t *input_ItemGetById( playlist_t *p_playlist, int i_id )
 {
-    int i, i_top, i_bottom;
-    i_bottom = 0; i_top = p_playlist->i_input_items -1;
-    i = i_top  /2 ;
-    while( p_playlist->pp_input_items[i]->i_id != i_id &&
-           i_top > i_bottom )
-    {
-        if( p_playlist->pp_input_items[i]->i_id < i_id )
-            i_bottom = i + 1;
-        else
-            i_top = i - 1;
-        i = i_bottom + ( i_top - i_bottom ) / 2;
-    }
-    if( p_playlist->pp_input_items[i]->i_id == i_id )
-    {
-        return p_playlist->pp_input_items[i];
-    }
+    int i;
+    ARRAY_BSEARCH( p_playlist->input_items, ->i_id, int, i_id, i);
+    if( i != -1 )
+        return ARRAY_VAL( p_playlist->input_items, i);
     return NULL;
 }
 
@@ -228,9 +211,7 @@ input_item_t *input_ItemNewWithType( vlc_object_t *p_obj, const char *psz_uri,
 
     PL_LOCK;
     p_input->i_id = ++p_playlist->i_last_input_id;
-    TAB_APPEND( p_playlist->i_input_items,
-                p_playlist->pp_input_items,
-                p_input );
+    ARRAY_APPEND( p_playlist->input_items, p_input );
     PL_UNLOCK;
     pl_Release( p_obj );
 
index 469c3ad..dc521a4 100644 (file)
@@ -670,7 +670,7 @@ int VLC_PlaylistNumberOfItems( int i_object )
 {
     int i_size;
     LIBVLC_PLAYLIST_FUNC;
-    i_size = p_libvlc->p_playlist->i_size;
+    i_size = p_libvlc->p_playlist->items.i_size;
     LIBVLC_PLAYLIST_FUNC_END;
     return i_size;
 }
index 5af18b9..6543bfd 100644 (file)
@@ -84,10 +84,8 @@ int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args )
     playlist_item_t *p_item, *p_node;
     vlc_value_t val;
 
-    if( p_playlist->i_size <= 0 )
-    {
+    if( p_playlist->items.i_size <= 0 )
         return VLC_EGENERIC;
-    }
 
     switch( i_query )
     {
@@ -100,7 +98,6 @@ int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args )
     // Node can be null, it will keep the same. Use with care ...
     // Item null = take the first child of node
     case PLAYLIST_VIEWPLAY:
-        p_playlist->b_reset_random = VLC_TRUE;
         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 )
@@ -113,6 +110,8 @@ int PlaylistVAControl( playlist_t * p_playlist, int i_query, va_list args )
         p_playlist->request.b_request = VLC_TRUE;
         p_playlist->request.p_node = p_node;
         p_playlist->request.p_item = p_item;
+        if( p_item && var_GetBool( p_playlist, "random" ) )
+            p_playlist->b_reset_currently_playing = VLC_TRUE;
         break;
 
     case PLAYLIST_PLAY:
@@ -261,6 +260,66 @@ void PreparseEnqueueItemSub( playlist_t *p_playlist,
  * Playback logic
  *****************************************************************************/
 
+static void ResyncCurrentIndex(playlist_t *p_playlist, playlist_item_t *p_cur )
+{
+     PL_DEBUG("resyncing on %s", PLI_NAME(p_cur) );
+     /* Simply resync index */
+     int i;
+     p_playlist->i_current_index = -1;
+     for( i = 0 ; i< p_playlist->current.i_size; i++ )
+     {
+          if( ARRAY_VAL(p_playlist->current, i) == p_cur )
+          {
+              p_playlist->i_current_index = i;
+              break;
+          }
+     }
+     PL_DEBUG("%s is at %i", PLI_NAME(p_cur), p_playlist->i_current_index );
+}
+
+static void ResetCurrentlyPlaying( playlist_t *p_playlist, vlc_bool_t b_random,
+                                   playlist_item_t *p_cur )
+{
+    playlist_item_t *p_next = NULL;
+    PL_DEBUG("rebuilding array of current - root %s",
+              PLI_NAME(p_playlist->status.p_node) );
+    ARRAY_RESET(p_playlist->current);
+    p_playlist->i_current_index = -1;
+    while( 1 )
+    {
+        /** FIXME: this is *slow* */
+        p_next = playlist_GetNextLeaf( p_playlist,
+                                       p_playlist->status.p_node,
+                                       p_next, VLC_TRUE, VLC_FALSE );
+        if( p_next )
+        {
+            if( p_next == p_cur )
+                p_playlist->i_current_index = p_playlist->current.i_size;
+            ARRAY_APPEND( p_playlist->current, p_next);
+        }
+        else break;
+    }
+    PL_DEBUG("rebuild done - %i items, index %i", p_playlist->current.i_size,
+                                                  p_playlist->i_current_index);
+    if( b_random )
+    {
+        /* Shuffle the array */
+        srand( (unsigned int)mdate() );
+        int swap = 0;
+        int j;
+        for( j = p_playlist->current.i_size - 1; j > 0; j-- )
+        {
+            swap++;
+            int i = rand() % (j+1); /* between 0 and j */
+            playlist_item_t *p_tmp;
+            p_tmp = ARRAY_VAL(p_playlist->current, i);
+            ARRAY_VAL(p_playlist->current,i) = ARRAY_VAL(p_playlist->current,j);
+            ARRAY_VAL(p_playlist->current,j) = p_tmp;
+        }
+    }
+    p_playlist->b_reset_currently_playing = VLC_FALSE;
+}
+
 /** This function calculates the next playlist item, depending
  *  on the playlist course mode (forward, backward, random, view,...). */
 playlist_item_t * playlist_NextItem( playlist_t *p_playlist )
@@ -275,7 +334,7 @@ playlist_item_t * playlist_NextItem( playlist_t *p_playlist )
 
     /* Handle quickly a few special cases */
     /* No items to play */
-    if( p_playlist->i_size == 0 )
+    if( p_playlist->items.i_size == 0 )
     {
         msg_Info( p_playlist, "playlist is empty" );
         return NULL;
@@ -308,74 +367,6 @@ playlist_item_t * playlist_NextItem( playlist_t *p_playlist )
         }
     }
 
-    /* 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.b_request &&
-            ( p_playlist->request.p_item == NULL ||
-              p_playlist->request.i_skip == 1    ||
-              p_playlist->request.i_skip == -1 ) ) ) )
-    {
-       PL_DEBUG( "doing random, have %i items, currently at %i, reset %i\n",
-                        p_playlist->i_random, p_playlist->i_random_index,
-                        p_playlist->b_reset_random );
-       if( p_playlist->b_reset_random )
-        {
-            int j;
-            FREE( p_playlist->pp_random );
-            if( !p_playlist->b_reset_random &&  !b_loop ) goto end;
-            p_playlist->i_random = 0;
-            p_playlist->i_random_index = 0;
-            p_playlist->i_random = playlist_GetAllEnabledChildren(
-                                                p_playlist,
-                                                p_playlist->status.p_node,
-                                                &p_playlist->pp_random );
-            /* Shuffle the array */
-            srand( (unsigned int)mdate() );
-            int swap = 0;
-            for( j = p_playlist->i_random -1; j > 0; j-- )
-            {
-                swap++;
-                int i = rand() % (j+1); /* between 0 and j */
-                playlist_item_t *p_tmp;
-                p_tmp = p_playlist->pp_random[i];
-                p_playlist->pp_random[i] = p_playlist->pp_random[j];
-                p_playlist->pp_random[j] = p_tmp;
-            }
-            p_playlist->b_reset_random = VLC_FALSE;
-            PL_DEBUG( "random rebuilt, have %i items", p_playlist->i_random );
-        }
-        else
-        {
-            /* Go backward or forward */
-            if( !p_playlist->request.b_request || !p_playlist->request.p_item ||
-                                               p_playlist->request.i_skip == 1 )
-                p_playlist->i_random_index++;
-            else
-                p_playlist->i_random_index--;
-            /* Handle bounds situations */
-            if( p_playlist->i_random_index == -1 )
-            {
-                if( !b_loop || p_playlist->i_random == 0 ) goto end;
-                p_playlist->i_random_index = p_playlist->i_random - 1;
-            }
-            else if( p_playlist->i_random_index == p_playlist->i_random )
-            {
-                if( !b_loop || p_playlist->i_random == 0 ) goto end;
-                p_playlist->i_random_index = 0;
-            }
-        }
-        PL_DEBUG( "using random item %i", p_playlist->i_random_index );
-        if ( p_playlist->i_random == 0 ) goto end; /* Can this happen ?? */
-        p_new = p_playlist->pp_random[p_playlist->i_random_index];
-end:
-        if( !p_new ) p_playlist->b_reset_random = VLC_TRUE;
-        p_playlist->request.i_skip = 0;
-        p_playlist->request.b_request = VLC_FALSE;
-        return p_new;
-    }
-
     /* Start the real work */
     if( p_playlist->request.b_request )
     {
@@ -385,47 +376,51 @@ end:
                         PLI_NAME( p_playlist->request.p_item ),
                         PLI_NAME( p_playlist->request.p_node ), i_skip );
 
-        if( p_playlist->request.p_node )
+        if( p_playlist->request.p_node &&
+            p_playlist->request.p_node != p_playlist->status.p_node )
+        {
             p_playlist->status.p_node = p_playlist->request.p_node;
+            p_playlist->b_reset_currently_playing = VLC_TRUE;
+        }
 
         /* If we are asked for a node, dont take it */
         if( i_skip == 0 && ( p_new == NULL || p_new->i_children != -1 ) )
             i_skip++;
 
-        if( i_skip > 0 )
+        if( p_playlist->b_reset_currently_playing )
+            ResetCurrentlyPlaying( p_playlist, b_random, p_new );
+        else if( p_new )
+            ResyncCurrentIndex( p_playlist, p_new );
+        else
+            p_playlist->i_current_index = -1;
+
+        if( p_playlist->current.i_size && i_skip > 0 )
         {
             for( i = i_skip; i > 0 ; i-- )
             {
-                p_new = playlist_GetNextLeaf( p_playlist,
-                                              p_playlist->request.p_node,
-                                              p_new, VLC_TRUE, VLC_FALSE );
-                if( p_new == NULL )
+                p_playlist->i_current_index++;
+                if( p_playlist->i_current_index == p_playlist->current.i_size )
                 {
                     PL_DEBUG( "looping - restarting at beginning of node" );
-                    p_new = playlist_GetNextLeaf( p_playlist,
-                                                  p_playlist->request.p_node,
-                                                  NULL, VLC_TRUE, VLC_FALSE);
-                    if( p_new == NULL ) break;
+                    p_playlist->i_current_index = 0;
                 }
             }
+            p_new = ARRAY_VAL( p_playlist->current,
+                               p_playlist->i_current_index );
         }
-        else if( i_skip < 0 )
+        else if( p_playlist->current.i_size && i_skip < 0 )
         {
             for( i = i_skip; i < 0 ; i++ )
             {
-                p_new = playlist_GetPrevLeaf( p_playlist,
-                                              p_playlist->request.p_node,
-                                              p_new, VLC_FALSE, VLC_FALSE );
-                if( p_new == NULL )
+                p_playlist->i_current_index--;
+                if( p_playlist->i_current_index == -1 )
                 {
                     PL_DEBUG( "looping - restarting at end of node" );
-                    /** \bug This is needed because GetPrevLeaf does not loop
-                      * by itself */
-                    p_new = playlist_GetLastLeaf( p_playlist,
-                                                 p_playlist->request.p_node );
+                    p_playlist->i_current_index = p_playlist->current.i_size-1;
                 }
-                if( p_new == NULL ) break;
             }
+            p_new = ARRAY_VAL( p_playlist->current,
+                               p_playlist->i_current_index );
         }
         /* Clear the request */
         p_playlist->request.b_request = VLC_FALSE;
@@ -433,31 +428,31 @@ end:
     /* "Automatic" item change ( next ) */
     else
     {
-        PL_DEBUG( "changing item without a request" );
+        PL_DEBUG( "changing item without a request (current %i/%i)",
+                  p_playlist->i_current_index, p_playlist->current.i_size );
         /* Cant go to next from current item */
         if( p_playlist->status.p_item &&
             p_playlist->status.p_item->i_flags & PLAYLIST_SKIP_FLAG )
             return NULL;
 
-        p_new = playlist_GetNextLeaf( p_playlist,
-                                      p_playlist->status.p_node,
-                                      p_playlist->status.p_item,
-                                      VLC_TRUE, VLC_FALSE );
-        if( p_new == NULL && b_loop )
+        if( p_playlist->b_reset_currently_playing )
+            ResetCurrentlyPlaying( p_playlist, b_random,
+                                   p_playlist->status.p_item );
+
+        p_playlist->i_current_index++;
+        if( p_playlist->i_current_index == p_playlist->current.i_size )
         {
-            PL_DEBUG( "looping" );
-            p_new = playlist_GetNextLeaf( p_playlist,
-                                          p_playlist->status.p_node,
-                                          NULL, VLC_TRUE, VLC_FALSE );
+            if( !b_loop || p_playlist->current.i_size == 0 ) return NULL;
+            p_playlist->i_current_index = 0;
         }
+        PL_DEBUG( "using item %i", p_playlist->i_current_index );
+        if ( p_playlist->current.i_size == 0 ) return NULL;
+
+        p_new = ARRAY_VAL( p_playlist->current, p_playlist->i_current_index );
         /* The new item can't be autoselected  */
         if( p_new != NULL && p_new->i_flags & PLAYLIST_SKIP_FLAG )
             return NULL;
     }
-    if( p_new == NULL )
-    {
-        msg_Dbg( p_playlist, "did not find something to play" );
-    }
     return p_new;
 }
 
index 0b8802a..f7ba590 100644 (file)
  *****************************************************************************/
 static void VariablesInit( playlist_t *p_playlist );
 
+static int RandomCallback( vlc_object_t *p_this, char const *psz_cmd,
+                           vlc_value_t oldval, vlc_value_t newval, void *a )
+{
+    ((playlist_t*)p_this)->b_reset_currently_playing = VLC_TRUE;
+    return VLC_SUCCESS;
+}
+
 /**
  * Create playlist
  *
@@ -66,18 +73,13 @@ playlist_t * playlist_Create( vlc_object_t *p_parent )
     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->pp_all_items = NULL;
+    ARRAY_INIT( p_playlist->items );
+    ARRAY_INIT( p_playlist->all_items );
+    ARRAY_INIT( p_playlist->input_items );
+    ARRAY_INIT( p_playlist->current );
 
-    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;
+    p_playlist->i_current_index = 0;
+    p_playlist->b_reset_currently_playing = VLC_TRUE;
 
     i_tree = var_CreateGetBool( p_playlist, "playlist-tree" );
     p_playlist->b_always_tree = (i_tree == 1);
@@ -162,10 +164,24 @@ void playlist_Destroy( playlist_t *p_playlist )
     var_Destroy( p_playlist, "activity" );
 
     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 );
+    /* Go through all items, and simply free everything without caring
+     * about the tree structure. Do not decref, it will be done by doing
+     * the same thing on the input items array */
+    FOREACH_ARRAY( playlist_item_t *p_del, p_playlist->all_items )
+        free( p_del->pp_children );
+        free( p_del );
+    FOREACH_END();
+    ARRAY_RESET( p_playlist->all_items );
+
+    FOREACH_ARRAY( input_item_t *p_del, p_playlist->input_items )
+        input_ItemClean( p_del );
+        free( p_del );
+    FOREACH_END();
+    ARRAY_RESET( p_playlist->input_items );
+
+    ARRAY_RESET( p_playlist->items );
+    ARRAY_RESET( p_playlist->current );
+
     PL_UNLOCK;
 
     if( p_playlist->p_stats )
@@ -635,4 +651,6 @@ static void VariablesInit( playlist_t *p_playlist )
     var_CreateGetBool( p_playlist, "random" );
     var_CreateGetBool( p_playlist, "repeat" );
     var_CreateGetBool( p_playlist, "loop" );
+
+    var_AddCallback( p_playlist, "random", RandomCallback, NULL );
 }
index 58928ee..45f394e 100644 (file)
@@ -403,7 +403,7 @@ playlist_item_t *playlist_ItemToNode( playlist_t *p_playlist,
             playlist_DeleteFromInput( p_playlist, p_item_in_one->p_input->i_id,
                                       p_playlist->p_root_onelevel, VLC_FALSE );
         }
-        p_playlist->b_reset_random = VLC_TRUE;
+        p_playlist->b_reset_currently_playing = VLC_TRUE;
         var_SetInteger( p_playlist, "item-change", p_item_in_category->
                                                         p_input->i_id );
         return p_item_in_category;
@@ -544,7 +544,7 @@ void playlist_SendAddNotify( playlist_t *p_playlist, int i_item_id,
     p_add->i_item = i_item_id;
     p_add->i_node = i_node_id;
     val.p_address = p_add;
-    p_playlist->b_reset_random = VLC_TRUE;
+    p_playlist->b_reset_currently_playing = VLC_TRUE;
     var_Set( p_playlist, "item-append", val );
     free( p_add );
 }
@@ -610,20 +610,15 @@ void GoAndPreparse( playlist_t *p_playlist, int i_mode,
 void AddItem( playlist_t *p_playlist, playlist_item_t *p_item,
               playlist_item_t *p_node, int i_pos )
 {
-    INSERT_ELEM( p_playlist->pp_items, p_playlist->i_size,
-                 p_playlist->i_size, p_item );
-    INSERT_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size,
-                 p_playlist->i_all_size, p_item );
+    ARRAY_APPEND(p_playlist->items, p_item);
+    ARRAY_APPEND(p_playlist->all_items, p_item);
     p_playlist->i_enabled ++;
 
     if( i_pos == PLAYLIST_END )
-    {
         playlist_NodeAppend( p_playlist, p_item, p_node );
-    }
     else
-    {
         playlist_NodeInsert( p_playlist, p_item, p_node, i_pos );
-    }
+
     if( !p_playlist->b_doing_ml )
         playlist_SendAddNotify( p_playlist, p_item->i_id, p_node->i_id );
 }
@@ -636,20 +631,16 @@ void ChangeToNode( playlist_t *p_playlist, playlist_item_t *p_item )
         p_item->i_children = 0;
 
     /* Remove it from the array of available items */
-    for( i = 0 ; i < p_playlist->i_size ; i++ )
-    {
-        if( p_item == p_playlist->pp_items[i] )
-        {
-            REMOVE_ELEM( p_playlist->pp_items, p_playlist->i_size, i );
-        }
-    }
+    ARRAY_BSEARCH( p_playlist->items,->i_id, int, p_item->i_id, i );
+    if( i != -1 )
+        ARRAY_REMOVE( p_playlist->items, i );
 }
 
 /* Do the actual removal */
 int DeleteInner( playlist_t * p_playlist, playlist_item_t *p_item,
                 vlc_bool_t b_stop )
 {
-    int i, i_top, i_bottom;
+    int i;
     int i_id = p_item->i_id;
     vlc_bool_t b_flag = VLC_FALSE;
 
@@ -657,29 +648,13 @@ int DeleteInner( playlist_t * p_playlist, playlist_item_t *p_item,
     {
         return playlist_NodeDelete( p_playlist, p_item, VLC_TRUE, VLC_FALSE );
     }
-    p_playlist->b_reset_random = VLC_TRUE;
+    p_playlist->b_reset_currently_playing = VLC_TRUE;
     var_SetInteger( p_playlist, "item-deleted", i_id );
 
     /* Remove the item from the bank */
-    i_bottom = 0; i_top = p_playlist->i_all_size - 1;
-    i = i_top / 2;
-    while( p_playlist->pp_all_items[i]->i_id != i_id &&
-           i_top > i_bottom )
-    {
-        if( p_playlist->pp_all_items[i]->i_id < i_id )
-        {
-            i_bottom = i + 1;
-        }
-        else
-        {
-            i_top = i - 1;
-        }
-        i = i_bottom + ( i_top - i_bottom ) / 2;
-    }
-    if( p_playlist->pp_all_items[i]->i_id == i_id )
-    {
-        REMOVE_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size, i );
-    }
+    ARRAY_BSEARCH( p_playlist->all_items,->i_id, int, i_id, i );
+    if( i != -1 )
+        ARRAY_REMOVE( p_playlist->all_items, i );
 
     /* Check if it is the current item */
     if( p_playlist->status.p_item == p_item )
index 7df9da3..00077f4 100644 (file)
  */
 playlist_item_t * playlist_ItemGetById( playlist_t * p_playlist , int i_id )
 {
-    int i, i_top, i_bottom;
-    i_bottom = 0; i_top = p_playlist->i_all_size - 1;
-    i = i_top / 2;
-    while( p_playlist->pp_all_items[i]->i_id != i_id &&
-           i_top > i_bottom )
-    {
-        if( p_playlist->pp_all_items[i]->i_id < i_id )
-            i_bottom = i + 1;
-        else
-            i_top = i - 1;
-        i = i_bottom + ( i_top - i_bottom ) / 2;
-    }
-    if( p_playlist->pp_all_items[i]->i_id == i_id )
-    {
-        return p_playlist->pp_all_items[i];
-    }
+    int i;
+    ARRAY_BSEARCH( p_playlist->all_items,->i_id, int, i_id, i );
+    if( i != -1 )
+        return ARRAY_VAL( p_playlist->all_items, i );
     return NULL;
 }
 
@@ -73,13 +61,11 @@ playlist_item_t * playlist_ItemGetByInput( playlist_t * p_playlist ,
     {
         return p_playlist->status.p_item;
     }
-
-    for( i =  0 ; i < p_playlist->i_all_size; i++ )
+    /** \todo Check if this is always incremental and whether we can bsearch */
+    for( i =  0 ; i < p_playlist->all_items.i_size; i++ )
     {
-        if( p_playlist->pp_all_items[i]->p_input->i_id == p_item->i_id )
-        {
-            return p_playlist->pp_all_items[i];
-        }
+        if( ARRAY_VAL(p_playlist->all_items, i)->p_input->i_id == p_item->i_id )
+            return ARRAY_VAL(p_playlist->all_items, i);
     }
     return NULL;
 }
@@ -92,7 +78,7 @@ int playlist_LiveSearchUpdate( playlist_t *p_playlist, playlist_item_t *p_root,
                                const char *psz_string )
 {
    int i;
-   p_playlist->b_reset_random = VLC_TRUE;
+   p_playlist->b_reset_currently_playing = VLC_TRUE;
    for( i = 0 ; i< p_root->i_children ; i ++ )
    {
         playlist_item_t *p_item = p_root->pp_children[i];
index e7b8e57..725751a 100644 (file)
@@ -143,9 +143,15 @@ int playlist_ThreadDestroy( playlist_t * p_playlist )
 {
     p_playlist->b_die = VLC_TRUE;
     if( p_playlist->p_preparse )
+    {
         vlc_cond_signal( &p_playlist->p_preparse->object_wait );
+        free( p_playlist->p_preparse->pp_waiting );
+    }
     if( p_playlist->p_secondary_preparse )
+    {
         vlc_cond_signal( &p_playlist->p_secondary_preparse->object_wait );
+        free( p_playlist->p_secondary_preparse->p_waiting );
+    }
 
     DestroyInteraction( p_playlist );
     DestroyPlaylist( p_playlist );
index 103b82e..e22ae7d 100644 (file)
@@ -62,19 +62,12 @@ playlist_item_t * playlist_NodeCreate( playlist_t *p_playlist, char *psz_name,
     p_item = playlist_ItemNewFromInput( VLC_OBJECT(p_playlist), p_input );
     p_item->i_children = 0;
 
-    if( p_item == NULL )
-    {
-        return NULL;
-    }
-    INSERT_ELEM( p_playlist->pp_all_items,
-                 p_playlist->i_all_size,
-                 p_playlist->i_all_size,
-                 p_item );
+    if( p_item == NULL )  return NULL;
+
+    ARRAY_APPEND(p_playlist->all_items, p_item);
 
     if( p_parent != NULL )
-    {
         playlist_NodeAppend( p_playlist, p_item, p_parent );
-    }
 
     playlist_SendAddNotify( p_playlist, p_item->i_id,
                             p_parent ? p_parent->i_id : -1 );
@@ -156,23 +149,16 @@ int playlist_NodeDelete( playlist_t *p_playlist, playlist_item_t *p_root,
     }
     else
     {
+        int i;
         var_SetInteger( p_playlist, "item-deleted", p_root->p_input->i_id );
-        for( i = 0 ; i< p_playlist->i_all_size; i ++ )
-        {
-            if( p_playlist->pp_all_items[i]->p_input->i_id ==
-                               p_root->p_input->i_id )
-            {
-                REMOVE_ELEM( p_playlist->pp_all_items, p_playlist->i_all_size,
-                             i );
-                break;
-            }
-        }
+        ARRAY_BSEARCH( p_playlist->all_items, ->p_input->i_id, int,
+                       p_root->p_input->i_id, i );
+        if( i != -1 )
+            ARRAY_REMOVE( p_playlist->all_items, i );
 
         /* Remove the item from its parent */
         if( p_root->p_parent )
-        {
             playlist_NodeRemoveItem( p_playlist, p_root, p_root->p_parent );
-        }
 
         playlist_ItemDelete( p_root );
     }
@@ -430,7 +416,6 @@ playlist_item_t *playlist_GetNextLeaf( playlist_t *p_playlist,
     {
         vlc_bool_t b_ena_ok = VLC_TRUE, b_unplayed_ok = VLC_TRUE;
         p_next = GetNextItem( p_playlist, p_root, p_next );
-        PL_DEBUG( "Got next item %s, testing suitability", PLI_NAME(p_next) );
         if( !p_next || p_next == p_root )
             break;
         if( p_next->i_children == -1 )
@@ -521,8 +506,6 @@ playlist_item_t *GetNextItem( playlist_t *p_playlist,
         p_parent = p_item->p_parent;
     else
         p_parent = p_root;
-    PL_DEBUG( "Parent %s has %i children", PLI_NAME(p_parent),
-                                           p_parent->i_children );
     for( i= 0 ; i < p_parent->i_children ; i++ )
     {
         if( p_item == NULL || p_parent->pp_children[i] == p_item )