Libvlc: Start the implementation of the libvlc playlist. Still in progress.
authorPierre d'Herbemont <pdherbemont@videolan.org>
Wed, 8 Aug 2007 21:12:02 +0000 (21:12 +0000)
committerPierre d'Herbemont <pdherbemont@videolan.org>
Wed, 8 Aug 2007 21:12:02 +0000 (21:12 +0000)
include/vlc/libvlc.h
include/vlc/libvlc_structures.h
src/control/event.c
src/control/libvlc_internal.h
src/control/media_descriptor.c
src/control/media_instance.c
src/control/media_list.c [new file with mode: 0644]
src/control/media_list_player.c [new file with mode: 0644]
src/control/tag_query.c [new file with mode: 0644]

index fcc5df7..9381ef4 100644 (file)
@@ -141,11 +141,10 @@ VLC_PUBLIC_API libvlc_media_descriptor_t * libvlc_media_descriptor_new(
                                    const char * psz_mrl,
                                    libvlc_exception_t *p_e );
 
-/**
- * Destroy a media descriptor object.
- * \param p_meta_desc the md to destroy
- */
-VLC_PUBLIC_API void libvlc_media_descriptor_destroy(
+VLC_PUBLIC_API void libvlc_media_descriptor_retain(
+                                   libvlc_media_descriptor_t *p_meta_desc );
+
+VLC_PUBLIC_API void libvlc_media_descriptor_release(
                                    libvlc_media_descriptor_t *p_meta_desc );
 
 /**
@@ -321,6 +320,7 @@ VLC_PUBLIC_API libvlc_media_instance_t * libvlc_media_instance_new_from_media_de
  * \param p_mi the Media Instance to free
  */
 VLC_PUBLIC_API void libvlc_media_instance_release( libvlc_media_instance_t * );
+VLC_PUBLIC_API void libvlc_media_instance_retain( libvlc_media_instance_t * );
 
 /** Set the media descriptor that will be used by the media_instance. If any,
  * previous md will be released.
@@ -343,6 +343,7 @@ VLC_PUBLIC_API libvlc_event_manager_t * libvlc_media_instance_event_manager ( li
 
 VLC_PUBLIC_API void libvlc_media_instance_play ( libvlc_media_instance_t *, libvlc_exception_t * );
 VLC_PUBLIC_API void libvlc_media_instance_pause ( libvlc_media_instance_t *, libvlc_exception_t * );
+VLC_PUBLIC_API void libvlc_media_instance_stop ( libvlc_media_instance_t *, libvlc_exception_t * );
 
 /// \bug This might go away ... to be replaced by a broader system
 VLC_PUBLIC_API vlc_int64_t libvlc_media_instance_get_length     ( libvlc_media_instance_t *, libvlc_exception_t *);
@@ -364,6 +365,126 @@ VLC_PUBLIC_API vlc_bool_t  libvlc_media_instance_has_vout( libvlc_media_instance
 VLC_PUBLIC_API float       libvlc_media_instance_get_fps( libvlc_media_instance_t *, libvlc_exception_t *);
 
 
+/** @} */
+
+/*****************************************************************************
+ * Tag Query
+ *****************************************************************************/
+/** defgroup libvlc_tag_query Tag Query
+ * \ingroup libvlc
+ * LibVLC Tag query
+ * @{
+ */
+VLC_PUBLIC_API libvlc_tag_query_t * 
+    libvlc_tag_query_new( libvlc_instance_t *, libvlc_exception_t * );
+
+VLC_PUBLIC_API void 
+    libvlc_tag_query_release( libvlc_tag_query_t * );
+
+VLC_PUBLIC_API void 
+    libvlc_tag_query_retain( libvlc_tag_query_t * );
+
+VLC_PUBLIC_API vlc_bool_t 
+    libvlc_tag_query_match( libvlc_tag_query_t *, libvlc_media_descriptor_t *,
+                            libvlc_exception_t * );
+
+/** @} */
+
+/*****************************************************************************
+ * Media List
+ *****************************************************************************/
+/** defgroup libvlc_media_list MediaList
+ * \ingroup libvlc
+ * LibVLC Media List
+ * @{
+ */
+VLC_PUBLIC_API libvlc_media_list_t *
+    libvlc_media_list_new( libvlc_instance_t *, libvlc_exception_t * );
+
+VLC_PUBLIC_API void
+    libvlc_media_list_release( libvlc_media_list_t * );
+
+VLC_PUBLIC_API void
+    libvlc_media_list_retain( libvlc_media_list_t * );
+
+VLC_PUBLIC_API void
+    libvlc_media_list_add_media_descriptor( libvlc_media_list_t *,
+                                            libvlc_media_descriptor_t *,
+                                            libvlc_exception_t * );
+VLC_PUBLIC_API void
+    libvlc_media_list_insert_media_descriptor( libvlc_media_list_t *,
+                                               libvlc_media_descriptor_t *,
+                                               int,
+                                               libvlc_exception_t * );
+VLC_PUBLIC_API void
+    libvlc_media_list_remove_index( libvlc_media_list_t *, int,
+                                    libvlc_exception_t * );
+
+VLC_PUBLIC_API int
+    libvlc_media_list_count( libvlc_media_list_t * p_mlist,
+                             libvlc_exception_t * p_e );
+
+VLC_PUBLIC_API libvlc_media_descriptor_t *
+    libvlc_media_list_item_at_index( libvlc_media_list_t *, int,
+                                     libvlc_exception_t * );
+VLC_PUBLIC_API int
+    libvlc_media_list_index_of_item( libvlc_media_list_t *,
+                                     libvlc_media_descriptor_t *,
+                                     libvlc_exception_t * );
+
+VLC_PUBLIC_API void
+    libvlc_media_list_lock( libvlc_media_list_t * );
+VLC_PUBLIC_API void
+    libvlc_media_list_unlock( libvlc_media_list_t * );
+
+VLC_PUBLIC_API libvlc_event_manager_t *
+    libvlc_media_list_event_manager( libvlc_media_list_t *,
+                                    libvlc_exception_t * );
+
+VLC_PUBLIC_API libvlc_media_list_t *
+    libvlc_media_list_dynamic_sublist( libvlc_media_list_t *,
+                                       libvlc_tag_query_t *,
+                                       libvlc_exception_t * );
+
+/** @} */
+
+/*****************************************************************************
+ * Media List Player
+ *****************************************************************************/
+/** defgroup libvlc_media_list_player MediaListPlayer
+ * \ingroup libvlc
+ * LibVLC Media List Player
+ * @{
+ */
+VLC_PUBLIC_API libvlc_media_list_player_t *
+    libvlc_media_list_player_new( libvlc_instance_t * p_instance,
+                                  libvlc_exception_t * p_e );
+VLC_PUBLIC_API void
+    libvlc_media_list_player_release( libvlc_media_list_player_t * p_mlp );
+
+VLC_PUBLIC_API void
+    libvlc_media_list_player_set_media_instance(
+                                     libvlc_media_list_player_t * p_mlp,
+                                     libvlc_media_instance_t * p_mi,
+                                     libvlc_exception_t * p_e );
+
+VLC_PUBLIC_API void
+    libvlc_media_list_player_set_media_list(
+                                     libvlc_media_list_player_t * p_mlp,
+                                     libvlc_media_list_t * p_mlist,
+                                     libvlc_exception_t * p_e );
+
+VLC_PUBLIC_API void
+    libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp,
+                                   libvlc_exception_t * p_e );
+
+VLC_PUBLIC_API void
+    libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp,
+                                   libvlc_exception_t * p_e );
+VLC_PUBLIC_API void
+    libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp,
+                                   libvlc_exception_t * p_e );
+
 /** @} */
 
 /** defgroup libvlc_video Video
index a31e2ca..4334a2f 100644 (file)
@@ -52,6 +52,19 @@ typedef struct libvlc_exception_t
 
 /**@} */
 
+/*****************************************************************************
+ * Tag Query
+ *****************************************************************************/
+/** defgroup libvlc_tag_query Tag Query
+ * \ingroup libvlc
+ * LibVLC Tag Query support in media descriptor
+ * @{
+ */
+
+typedef struct libvlc_tag_query_t libvlc_tag_query_t;
+
+/**@} */
+
 /*****************************************************************************
  * Media Descriptor
  *****************************************************************************/
@@ -79,6 +92,7 @@ typedef struct libvlc_media_descriptor_t libvlc_media_descriptor_t;
 
 /**@} */
 
+
 /*****************************************************************************
  * Media Instance
  *****************************************************************************/
@@ -92,6 +106,31 @@ typedef struct libvlc_media_instance_t libvlc_media_instance_t;
 
 /**@} */
 
+/*****************************************************************************
+ * Media List
+ *****************************************************************************/
+/** defgroup libvlc_media_list MediaList
+ * \ingroup libvlc
+ * LibVLC Media List handling
+ * @{
+ */
+
+typedef struct libvlc_media_list_t libvlc_media_list_t;
+
+/**@} */
+
+/*****************************************************************************
+ * Media List Player
+ *****************************************************************************/
+/** defgroup libvlc_media_list_player MediaListPlayer
+ * \ingroup libvlc
+ * LibVLC Media List Player handling
+ * @{
+ */
+
+typedef struct libvlc_media_list_player_t libvlc_media_list_player_t;
+
+/**@} */
 
 /*****************************************************************************
  * Playlist
@@ -188,6 +227,9 @@ typedef struct libvlc_log_message_t
 
 typedef enum libvlc_event_type_t {
     libvlc_MediaInstanceReachedEnd,
+    libvlc_MediaListItemAdded,
+    libvlc_MediaListItemDeleted,
+    libvlc_MediaListItemChanged,
 } libvlc_event_type_t;
 
 /**
@@ -200,13 +242,24 @@ typedef enum libvlc_event_type_t {
 typedef struct libvlc_event_t
 {
     libvlc_event_type_t type;
-       void * p_obj;
-    union
+    void * p_obj;
+    union event_type_specific
     {
         struct
         {
-            int new_volume;
-        } volume_changed; /* Scheduled for deletion */
+            libvlc_media_descriptor_t * item;
+            int index;
+        } media_list_item_added;
+        struct
+        {
+            libvlc_media_descriptor_t * item;
+            int index;
+        } media_list_item_deleted;
+        struct
+        {
+            libvlc_media_descriptor_t * item;
+            int index;
+        } media_list_item_changed;
     } u;
 } libvlc_event_t;
 
@@ -222,7 +275,7 @@ typedef struct libvlc_event_manager_t libvlc_event_manager_t;
  * \param p_event the event triggering the callback
  */
 
-typedef void ( *libvlc_callback_t )( const libvlc_event_t * );
+typedef void ( *libvlc_callback_t )( const libvlc_event_t *, void * );
 
 /**@} */
 
index 3bea3ee..e7d3dbd 100644 (file)
@@ -141,7 +141,7 @@ void libvlc_event_send( libvlc_event_manager_t * p_em,
         {
             /* We found the group, now send every one the event */
             FOREACH_ARRAY( listener, listeners_group->listeners )
-                listener->pf_callback( p_event );
+                listener->pf_callback( p_event, listener->p_user_data );
             FOREACH_END()
             break;
         }
index 74c7ad0..e86d7c6 100644 (file)
@@ -67,9 +67,28 @@ struct libvlc_media_descriptor_t
 {
     int                b_preparsed;
     input_item_t      *p_input_item;
+    int                i_refcount;
     libvlc_instance_t *p_libvlc_instance;
 };
 
+struct libvlc_tag_query_t
+{
+    struct libvlc_instance_t  *p_libvlc_instance; /* Parent instance */
+    int                i_refcount;
+};
+
+
+struct libvlc_media_list_t
+{
+    libvlc_event_manager_t * p_event_manager;
+    libvlc_instance_t *      p_libvlc_instance;
+    int                      i_refcount;
+    vlc_mutex_t              object_lock;
+    libvlc_media_list_t *    p_media_provider; /* For dynamic sublist */
+    libvlc_tag_query_t *     p_query;              /* For dynamic sublist */
+    DECL_ARRAY(void *) items;
+};
+
 struct libvlc_media_instance_t
 {
     int                i_refcount;
@@ -81,6 +100,19 @@ struct libvlc_media_instance_t
     libvlc_event_manager_t * p_event_manager;
 };
 
+struct libvlc_media_list_player_t
+{
+    libvlc_event_manager_t * p_event_manager;
+    libvlc_instance_t *      p_libvlc_instance;
+    int                      i_refcount;
+    vlc_mutex_t              object_lock;
+    int                      i_current_playing_index;
+    libvlc_media_descriptor_t * p_current_playing_item;
+    libvlc_media_list_t *    p_mlist;
+    libvlc_media_instance_t *  p_mi;
+};
+
+
 
 /* 
  * Event Handling
index efa9216..e2b78a0 100644 (file)
@@ -65,6 +65,7 @@ libvlc_media_descriptor_t * libvlc_media_descriptor_new(
     p_md->p_libvlc_instance = p_instance;
     p_md->p_input_item      = p_input_item;
     p_md->b_preparsed       = VLC_FALSE;
+    p_md->i_refcount        = 1;
  
     vlc_gc_incref( p_md->p_input_item );
 
@@ -92,6 +93,7 @@ libvlc_media_descriptor_t * libvlc_media_descriptor_new_from_input_item(
     p_md->p_libvlc_instance = p_instance;
     p_md->p_input_item      = p_input_item;
     p_md->b_preparsed       = VLC_TRUE;
+    p_md->i_refcount        = 1;
 
     vlc_gc_incref( p_md->p_input_item );
 
@@ -101,19 +103,38 @@ libvlc_media_descriptor_t * libvlc_media_descriptor_new_from_input_item(
 /**************************************************************************
  * Delete a media descriptor object
  **************************************************************************/
-void libvlc_media_descriptor_destroy( libvlc_media_descriptor_t *p_md )
+void libvlc_media_descriptor_release( libvlc_media_descriptor_t *p_md )
 {
     if (!p_md)
         return;
 
+    p_md->i_refcount--;
+
     /* XXX: locking */
     vlc_gc_decref( p_md->p_input_item );
+
+    if( p_md->i_refcount > 0 )
+        return;
     
     free( p_md );
 }
 
 /**************************************************************************
- * Delete a media descriptor object
+ * Retain a media descriptor object
+ **************************************************************************/
+void libvlc_media_descriptor_retain( libvlc_media_descriptor_t *p_md )
+{
+    if (!p_md)
+        return;
+
+    p_md->i_refcount++;
+
+    /* XXX: locking */
+    vlc_gc_incref( p_md->p_input_item );
+}
+
+/**************************************************************************
+ * Duplicate a media descriptor object
  **************************************************************************/
 libvlc_media_descriptor_t *
 libvlc_media_descriptor_duplicate( libvlc_media_descriptor_t *p_md_orig )
index 9034de8..56a585c 100644 (file)
@@ -261,7 +261,7 @@ void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi )
 
     input_DestroyThread( p_input_thread );
 
-    libvlc_media_descriptor_destroy( p_mi->p_md );
+    libvlc_media_descriptor_release( p_mi->p_md );
 
     free( p_mi );
 }
@@ -278,24 +278,32 @@ void libvlc_media_instance_release( libvlc_media_instance_t *p_mi )
     
     p_mi->i_refcount--;
 
-    /* We hold the mutex, as a waiter to make sure pending operations
-     * are finished. We can't hold it longer as the get_input_thread
-     * function holds a lock.  */
-
-    vlc_mutex_unlock( &p_mi->object_lock );
-    
     if( p_mi->i_refcount > 0 )
+    {
+        vlc_mutex_unlock( &p_mi->object_lock );
         return;
+    }
+    vlc_mutex_unlock( &p_mi->object_lock );
 
     libvlc_event_manager_release( p_mi->p_event_manager );
     
     release_input_thread( p_mi );
 
-    libvlc_media_descriptor_destroy( p_mi->p_md );
+    libvlc_media_descriptor_release( p_mi->p_md );
 
     free( p_mi );
 }
 
+/**************************************************************************
+ * Retain a Media Instance object
+ **************************************************************************/
+void libvlc_media_instance_retain( libvlc_media_instance_t *p_mi )
+{
+    if( !p_mi )
+        return;
+
+    p_mi->i_refcount++;
+}
 /**************************************************************************
  * Set the Media descriptor associated with the instance
  **************************************************************************/
@@ -313,7 +321,7 @@ void libvlc_media_instance_set_media_descriptor(
     
     release_input_thread( p_mi );
 
-    libvlc_media_descriptor_destroy( p_mi->p_md );
+    libvlc_media_descriptor_release( p_mi->p_md );
 
     if( !p_md )
     {
@@ -422,6 +430,15 @@ void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
     vlc_object_release( p_input_thread );
 }
 
+/**************************************************************************
+ * Stop
+ **************************************************************************/
+void libvlc_media_instance_stop( libvlc_media_instance_t *p_mi,
+                                 libvlc_exception_t *p_e )
+{
+    libvlc_exception_raise( p_mi, "Not implemented" );
+}
+
 /**************************************************************************
  * Getters for stream information
  **************************************************************************/
diff --git a/src/control/media_list.c b/src/control/media_list.c
new file mode 100644 (file)
index 0000000..3693a4b
--- /dev/null
@@ -0,0 +1,438 @@
+/*****************************************************************************
+ * media_list.c: libvlc new API media list functions
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "libvlc_internal.h"
+#include <vlc/libvlc.h>
+#include <assert.h>
+#include "vlc_arrays.h"
+
+/*
+ * Private functions
+ */
+
+/**************************************************************************
+ *       notify_item_addition (private)
+ *
+ * Call parent playlist and send the appropriate event.
+ **************************************************************************/
+static void
+notify_item_addition( libvlc_media_list_t * p_mlist,
+                      libvlc_media_descriptor_t * p_md,
+                      int index )
+{
+    libvlc_event_t event;
+
+    event.type = libvlc_MediaListItemAdded;
+    event.u.media_list_item_added.item = p_md;
+    event.u.media_list_item_added.index = index;
+    
+    libvlc_event_send( p_mlist->p_event_manager, &event );
+}
+
+/**************************************************************************
+ *       notify_item_deletion (private)
+ *
+ * Call parent playlist and send the appropriate event.
+ **************************************************************************/
+static void
+notify_item_deletion( libvlc_media_list_t * p_mlist,
+                      libvlc_media_descriptor_t * p_md,
+                      int index )
+{
+    libvlc_event_t event;
+    
+    event.type = libvlc_MediaListItemDeleted;
+    event.u.media_list_item_deleted.item = p_md;
+    event.u.media_list_item_deleted.index = index;
+
+    libvlc_event_send( p_mlist->p_event_manager, &event );
+}
+
+/**************************************************************************
+ *       dynamic_list_propose_item (private) (Event Callback)
+ *
+ * This is called if the dynamic sublist's data provider adds a new item.
+ **************************************************************************/
+static void
+dynamic_list_propose_item( const libvlc_event_t * p_event, void * p_user_data )
+{
+    libvlc_media_list_t * p_submlist = p_user_data;
+    libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_added.item;
+
+    //libvlc_media_descriptor_lock( p_md );
+    if( libvlc_tag_query_match( p_submlist->p_query, p_md, NULL ) )
+    {
+        libvlc_media_list_lock( p_submlist );
+        libvlc_media_list_add_media_descriptor( p_submlist, p_md, NULL );
+        libvlc_media_list_unlock( p_submlist );
+    }
+    //libvlc_media_descriptor_unlock( p_md );
+}
+
+/**************************************************************************
+ *       dynamic_list_remove_item (private) (Event Callback)
+ *
+ * This is called if the dynamic sublist's data provider adds a new item.
+ **************************************************************************/
+static void
+dynamic_list_remove_item( const libvlc_event_t * p_event, void * p_user_data )
+{
+    libvlc_media_list_t * p_submlist = p_user_data;
+    libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_deleted.item;
+
+    //libvlc_media_descriptor_lock( p_md );
+    if( libvlc_tag_query_match( p_submlist->p_query, p_md, NULL ) )
+    {
+        int i;
+        libvlc_media_list_lock( p_submlist );        
+        i = libvlc_media_list_index_of_item( p_submlist, p_md, NULL );
+        if ( i < 0 )
+        {
+            /* We've missed one item addition, that could happen especially
+             * if we add item in a threaded maner, so we just ignore */
+            libvlc_media_list_unlock( p_submlist );
+            //libvlc_media_descriptor_unlock( p_md );           
+            return;
+        }
+        libvlc_media_list_remove_index( p_submlist, i, NULL );
+        libvlc_media_list_unlock( p_submlist );
+    }
+    //libvlc_media_descriptor_unlock( p_md );
+}
+
+/**************************************************************************
+ *       dynamic_list_change_item (private) (Event Callback)
+ *
+ * This is called if the dynamic sublist's data provider adds a new item.
+ **************************************************************************/
+static void
+dynamic_list_change_item( const libvlc_event_t * p_event , void * p_user_data)
+{
+    libvlc_media_list_t * p_submlist = p_user_data;
+    libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_changed.item;
+    int index;
+
+    libvlc_media_list_lock( p_submlist );        
+    
+    index = libvlc_media_list_index_of_item( p_submlist, p_md, NULL );
+    if( index < 0 )
+    {
+        libvlc_media_list_unlock( p_submlist );     
+        return; /* Not found, no prob, just ignore */
+    }
+
+    //libvlc_media_descriptor_lock( p_md );
+    if( !libvlc_tag_query_match( p_submlist->p_query, p_md, NULL ) )
+        libvlc_media_list_remove_index( p_submlist, index, NULL );
+    //libvlc_media_descriptor_unlock( p_md );
+
+    libvlc_media_list_unlock( p_submlist );        
+}
+
+/*
+ * Public libvlc functions
+ */
+
+/**************************************************************************
+ *       libvlc_media_list_new (Public)
+ *
+ * Init an object.
+ **************************************************************************/
+libvlc_media_list_t *
+libvlc_media_list_new( libvlc_instance_t * p_inst,
+                       libvlc_exception_t * p_e )
+{
+    libvlc_media_list_t * p_mlist;
+
+    p_mlist = malloc(sizeof(libvlc_media_list_t));
+
+    if( !p_mlist )
+        return NULL;
+    
+    p_mlist->p_libvlc_instance = p_inst;
+    p_mlist->p_event_manager = libvlc_event_manager_new( p_mlist, p_inst, p_e );
+
+    libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
+            libvlc_MediaListItemAdded, p_e );
+    libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
+            libvlc_MediaListItemChanged, p_e );
+    libvlc_event_manager_register_event_type( p_mlist->p_event_manager,
+            libvlc_MediaListItemDeleted, p_e );
+
+    if( libvlc_exception_raised( p_e ) )
+    {
+        libvlc_event_manager_release( p_mlist->p_event_manager );
+        free( p_mlist );
+        return NULL;
+    }
+
+    vlc_mutex_init( p_inst->p_libvlc_int, &p_mlist->object_lock );
+    
+    ARRAY_INIT(p_mlist->items);
+    p_mlist->i_refcount = 1;
+    p_mlist->p_media_provider = NULL;
+
+    return p_mlist;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_release (Public)
+ *
+ * Release an object.
+ **************************************************************************/
+void libvlc_media_list_release( libvlc_media_list_t * p_mlist )
+{
+    libvlc_media_descriptor_t * p_md;
+
+    vlc_mutex_lock( &p_mlist->object_lock );
+    p_mlist->i_refcount--;
+    if( p_mlist->i_refcount > 0 )
+    {
+        vlc_mutex_unlock( &p_mlist->object_lock );        
+        return;
+    }
+    vlc_mutex_unlock( &p_mlist->object_lock );        
+
+    /* Refcount null, time to free */
+    if( p_mlist->p_media_provider )
+        libvlc_media_list_release( p_mlist->p_media_provider );
+
+    if( p_mlist->p_query )
+        libvlc_tag_query_release( p_mlist->p_query );
+
+    libvlc_event_manager_release( p_mlist->p_event_manager );
+
+    FOREACH_ARRAY( p_md, p_mlist->items )
+        libvlc_media_descriptor_release( p_md );
+    FOREACH_END()
+    free( p_mlist );
+}
+/**************************************************************************
+ *       libvlc_media_list_retain (Public)
+ *
+ * Increase an object refcount.
+ **************************************************************************/
+void libvlc_media_list_retain( libvlc_media_list_t * p_mlist )
+{
+    vlc_mutex_lock( &p_mlist->object_lock );
+    p_mlist->i_refcount++;
+    vlc_mutex_unlock( &p_mlist->object_lock );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_count (Public)
+ *
+ * Lock should be hold when entering.
+ **************************************************************************/
+int libvlc_media_list_count( libvlc_media_list_t * p_mlist,
+                             libvlc_exception_t * p_e )
+{
+    (void)p_e;
+    return p_mlist->items.i_size;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_add_media_descriptor (Public)
+ *
+ * Lock should be hold when entering.
+ **************************************************************************/
+void libvlc_media_list_add_media_descriptor( 
+                                   libvlc_media_list_t * p_mlist,
+                                   libvlc_media_descriptor_t * p_md,
+                                   libvlc_exception_t * p_e )
+{
+    (void)p_e;
+    libvlc_media_descriptor_retain( p_md );
+    
+    ARRAY_APPEND( p_mlist->items, p_md );
+    notify_item_addition( p_mlist, p_md, p_mlist->items.i_size-1 );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_insert_media_descriptor (Public)
+ *
+ * Lock should be hold when entering.
+ **************************************************************************/
+void libvlc_media_list_insert_media_descriptor( 
+                                   libvlc_media_list_t * p_mlist,
+                                   libvlc_media_descriptor_t * p_md,
+                                   int index,
+                                   libvlc_exception_t * p_e )
+{
+    (void)p_e;
+    libvlc_media_descriptor_retain( p_md );
+
+    ARRAY_INSERT( p_mlist->items, p_md, index);
+    notify_item_addition( p_mlist, p_md, index );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_remove_index (Public)
+ *
+ * Lock should be hold when entering.
+ **************************************************************************/
+void libvlc_media_list_remove_index( libvlc_media_list_t * p_mlist,
+                                     int index,
+                                     libvlc_exception_t * p_e )
+{
+    libvlc_media_descriptor_t * p_md;
+
+    p_md = ARRAY_VAL( p_mlist->items, index );
+
+    ARRAY_REMOVE( p_mlist->items, index )
+    notify_item_deletion( p_mlist, p_md, index );
+
+    libvlc_media_descriptor_release( p_md );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_item_at_index (Public)
+ *
+ * Lock should be hold when entering.
+ **************************************************************************/
+libvlc_media_descriptor_t *
+libvlc_media_list_item_at_index( libvlc_media_list_t * p_mlist,
+                                 int index,
+                                 libvlc_exception_t * p_e )
+{
+    return ARRAY_VAL( p_mlist->items, index );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_index_of_item (Public)
+ *
+ * Lock should be hold when entering.
+ * Warning: this function would return the first matching item
+ **************************************************************************/
+int libvlc_media_list_index_of_item( libvlc_media_list_t * p_mlist,
+                                     libvlc_media_descriptor_t * p_searched_md,
+                                     libvlc_exception_t * p_e )
+{
+    libvlc_media_descriptor_t * p_md;
+    FOREACH_ARRAY( p_md, p_mlist->items )
+        if( p_searched_md == p_md )
+            return fe_idx; /* Once more, we hate macro for that */
+    FOREACH_END()
+    return -1;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_lock (Public)
+ *
+ * The lock must be held in access operations. It is never used in the
+ * Public method.
+ **************************************************************************/
+void libvlc_media_list_lock( libvlc_media_list_t * p_mlist )
+{
+    vlc_mutex_lock( &p_mlist->object_lock );
+}
+
+
+/**************************************************************************
+ *       libvlc_media_list_unlock (Public)
+ *
+ * The lock must be held in access operations
+ **************************************************************************/
+void libvlc_media_list_unlock( libvlc_media_list_t * p_mlist )
+{
+    vlc_mutex_unlock( &p_mlist->object_lock );
+}
+
+
+
+/**************************************************************************
+ *       libvlc_media_list_p_event_manager (Public)
+ *
+ * The p_event_manager is immutable, so you don't have to hold the lock
+ **************************************************************************/
+libvlc_event_manager_t *
+libvlc_media_list_event_manager( libvlc_media_list_t * p_mlist,
+                                    libvlc_exception_t * p_e )
+{
+    (void)p_e;
+    return p_mlist->p_event_manager;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_dynamic_sublist (Public)
+ *
+ * Lock should be hold when entering.
+ **************************************************************************/
+libvlc_media_list_t *
+libvlc_media_list_dynamic_sublist( libvlc_media_list_t * p_mlist,
+                                   libvlc_tag_query_t * p_query,
+                                   libvlc_exception_t * p_e )
+{
+    libvlc_media_list_t * p_submlist;
+    libvlc_event_manager_t * p_em;
+    int count, i;
+
+    (void)p_e;
+
+    p_submlist = libvlc_media_list_new( p_mlist->p_libvlc_instance, p_e );
+    if( !p_submlist )
+    {
+        if( !libvlc_exception_raised( p_e ) )
+            libvlc_exception_raise( p_e, "Can't get the new media_list" );
+        return NULL;
+    }
+
+    /* We have a query */
+    libvlc_tag_query_retain( p_query );
+    p_submlist->p_query = p_query;
+
+    /* We have a media provider */
+    libvlc_media_list_retain( p_mlist );
+    p_submlist->p_media_provider = p_mlist;
+
+
+    libvlc_media_list_lock( p_submlist );        
+    
+    count = libvlc_media_list_count( p_mlist, p_e );
+
+    /* This should be running in a thread, a good plan to achieve that
+     * move all the dynamic code to libvlc_tag_query. */
+    for( i = 0; i < count; i++ )
+    {
+        libvlc_media_descriptor_t * p_md;
+        p_md = libvlc_media_list_item_at_index( p_mlist, i, p_e );
+        if( libvlc_tag_query_match( p_query, p_md, NULL ) )
+            libvlc_media_list_add_media_descriptor( p_submlist, p_md, p_e );
+    }
+
+    /* And we will listen to its event, so we can update p_submlist
+     * accordingly */
+    p_em = libvlc_media_list_event_manager( p_mlist, p_e );
+    libvlc_event_attach( p_em, libvlc_MediaListItemAdded,
+                         dynamic_list_propose_item, p_submlist, p_e );
+    libvlc_event_attach( p_em, libvlc_MediaListItemDeleted,
+                         dynamic_list_remove_item, p_submlist, p_e );
+    libvlc_event_attach( p_em, libvlc_MediaListItemChanged,
+                         dynamic_list_change_item, p_submlist, p_e );
+
+    libvlc_media_list_unlock( p_submlist );        
+
+    return p_submlist;
+}
+
diff --git a/src/control/media_list_player.c b/src/control/media_list_player.c
new file mode 100644 (file)
index 0000000..1c6972f
--- /dev/null
@@ -0,0 +1,305 @@
+/*****************************************************************************
+ * media_list_player.c: libvlc new API media_list player functions
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include "libvlc_internal.h"
+#include <vlc/libvlc.h>
+
+/*
+ * Private functions
+ */
+
+/**************************************************************************
+ *       get_next_index (private)
+ *
+ * Simple next item fetcher.
+ **************************************************************************/
+static int get_next_index( libvlc_media_list_player_t * p_mlp )
+{
+       /* We are entered with libvlc_media_list_lock( p_mlp->p_list ) */
+       
+       int next = p_mlp->i_current_playing_index + 1;
+
+       if( libvlc_media_list_count( p_mlp->p_mlist, NULL ) >= next )
+               return -1; /* no more to play */
+
+       return next;
+}
+
+/**************************************************************************
+ *       media_instance_reached_end (private) (Event Callback)
+ **************************************************************************/
+static void 
+media_instance_reached_end( const libvlc_event_t * p_event,
+                            void * p_user_data )
+{
+       libvlc_media_list_player_t * p_mlp = p_user_data;
+       libvlc_media_instance_t * p_mi = p_event->p_obj;
+    libvlc_media_descriptor_t *p_md, * p_current_md;
+    p_md = libvlc_media_instance_get_media_descriptor( p_mi, NULL );
+    /* XXX: need if p_mlp->p_current_playing_index is beyond */
+    p_current_md = libvlc_media_list_item_at_index(
+                        p_mlp->p_mlist,
+                        p_mlp->i_current_playing_index,
+                        NULL );
+       if( p_md != p_current_md )
+       {
+               msg_Warn( p_mlp->p_libvlc_instance->p_libvlc_int,
+                                 "We are not sync-ed with the media instance" );
+        libvlc_media_descriptor_release( p_md );
+        libvlc_media_descriptor_release( p_current_md );
+               return;
+       }
+    libvlc_media_descriptor_release( p_md );
+    libvlc_media_descriptor_release( p_current_md );
+       libvlc_media_list_player_next( p_mlp, NULL );
+}
+
+/**************************************************************************
+ *       playlist_item_deleted (private) (Event Callback)
+ **************************************************************************/
+static void 
+mlist_item_deleted( const libvlc_event_t * p_event, void * p_user_data )
+{
+    libvlc_media_descriptor_t * p_current_md;    
+       libvlc_media_list_player_t * p_mlp = p_user_data;
+       libvlc_media_list_t * p_emitting_mlist = p_event->p_obj;
+    /* XXX: need if p_mlp->p_current_playing_index is beyond */
+    p_current_md = libvlc_media_list_item_at_index(
+                        p_mlp->p_mlist,
+                        p_mlp->i_current_playing_index,
+                        NULL );
+
+       if( p_event->u.media_list_item_deleted.item == p_current_md &&
+           p_emitting_mlist == p_mlp->p_mlist )
+       {
+               /* We are playing this item, we choose to stop */
+               libvlc_media_list_player_stop( p_mlp, NULL );
+       }
+}
+
+/**************************************************************************
+ *       install_playlist_observer (private)
+ **************************************************************************/
+static void
+install_playlist_observer( libvlc_media_list_player_t * p_mlp )
+{
+       libvlc_event_attach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
+            libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
+}
+
+/**************************************************************************
+ *       uninstall_playlist_observer (private)
+ **************************************************************************/
+static void
+uninstall_playlist_observer( libvlc_media_list_player_t * p_mlp )
+{
+    libvlc_event_detach( libvlc_media_list_event_manager( p_mlp->p_mlist, NULL ),
+            libvlc_MediaListItemDeleted, mlist_item_deleted, p_mlp, NULL );
+}
+
+/**************************************************************************
+ *       install_media_instance_observer (private)
+ **************************************************************************/
+static void
+install_media_instance_observer( libvlc_media_list_player_t * p_mlp )
+{
+       libvlc_event_attach( libvlc_media_instance_event_manager( p_mlp->p_mi, NULL ),
+                         libvlc_MediaInstanceReachedEnd,
+                                             media_instance_reached_end, p_mlp, NULL );
+}
+
+
+/**************************************************************************
+ *       uninstall_media_instance_observer (private)
+ **************************************************************************/
+static void
+uninstall_media_instance_observer( libvlc_media_list_player_t * p_mlp )
+{
+       libvlc_event_detach( libvlc_media_instance_event_manager( p_mlp->p_mi, NULL ),
+                         libvlc_MediaInstanceReachedEnd,
+                                            media_instance_reached_end, p_mlp, NULL );
+}
+/**************************************************************************
+ *       Stop (Public)
+ **************************************************************************/
+static vlc_bool_t
+libvlc_media_list_player_is_playing( libvlc_media_list_player_t * p_mlp,
+                                    libvlc_exception_t * p_e )
+{
+    libvlc_exception_raise( p_e, "Unimplemented" );
+    return 0;
+}
+
+
+/*
+ * Public libvlc functions
+ */
+
+/**************************************************************************
+ *         libvlc_media_list_player_new (Public)
+ **************************************************************************/
+libvlc_media_list_player_t *
+libvlc_media_list_player_new( libvlc_instance_t * p_instance,
+                              libvlc_exception_t * p_e )
+{
+    (void)p_e;
+    libvlc_media_list_player_t * p_mlp;
+    p_mlp = malloc(sizeof(libvlc_media_list_player_t));
+       p_mlp->i_current_playing_index = -1;
+
+    vlc_mutex_init( p_instance->p_libvlc_int, &p_mlp->object_lock );
+    
+       return p_mlp;
+}
+
+/**************************************************************************
+ *         libvlc_media_list_player_release (Public)
+ **************************************************************************/
+void libvlc_media_list_player_release( libvlc_media_list_player_t * p_mlp )
+{
+    free(p_mlp);
+}
+
+/**************************************************************************
+ *        libvlc_media_list_player_set_media_instance (Public)
+ **************************************************************************/
+void libvlc_media_list_player_set_media_instance(
+                                     libvlc_media_list_player_t * p_mlp,
+                                     libvlc_media_instance_t * p_mi,
+                                     libvlc_exception_t * p_e )
+{
+    vlc_mutex_lock( &p_mlp->object_lock );
+
+       if( p_mlp->p_mi )
+       {
+               uninstall_playlist_observer( p_mlp );
+               libvlc_media_instance_release( p_mlp->p_mi );
+       }
+       libvlc_media_instance_retain( p_mi );
+       p_mlp->p_mi = p_mi;
+
+    install_media_instance_observer( p_mlp );
+
+    vlc_mutex_unlock( &p_mlp->object_lock );
+}
+
+/**************************************************************************
+ *       Set a playlist (Public)
+ **************************************************************************/
+void libvlc_media_list_player_set_media_list(
+                                     libvlc_media_list_player_t * p_mlp,
+                                     libvlc_media_list_t * p_mlist,
+                                     libvlc_exception_t * p_e )
+{
+    vlc_mutex_lock( &p_mlp->object_lock );
+    
+       if( libvlc_media_list_player_is_playing( p_mlp, p_e ) )
+               libvlc_media_list_player_stop( p_mlp, p_e );
+
+       if( p_mlp->p_mlist )
+       {
+               uninstall_playlist_observer( p_mlp );
+               libvlc_media_list_release( p_mlp->p_mlist );
+       }
+       libvlc_media_list_retain( p_mlist );
+       p_mlp->p_mlist = p_mlist;
+    
+       install_playlist_observer( p_mlp );
+
+    vlc_mutex_unlock( &p_mlp->object_lock );
+}
+
+/**************************************************************************
+ *        Play (Public)
+ **************************************************************************/
+void libvlc_media_list_player_play( libvlc_media_list_player_t * p_mlp,
+                                  libvlc_exception_t * p_e )
+{
+       libvlc_media_list_player_next( p_mlp, p_e );
+
+       if( libvlc_exception_raised( p_e ) )
+               return;
+
+       libvlc_media_instance_play( p_mlp->p_mi, p_e );
+}
+
+/**************************************************************************
+ *       Stop (Public)
+ **************************************************************************/
+void libvlc_media_list_player_stop( libvlc_media_list_player_t * p_mlp,
+                                    libvlc_exception_t * p_e )
+{
+       libvlc_media_instance_stop( p_mlp->p_mi, p_e );
+
+    vlc_mutex_lock( &p_mlp->object_lock );
+       p_mlp->i_current_playing_index = -1;
+    vlc_mutex_unlock( &p_mlp->object_lock );
+}
+
+/**************************************************************************
+ *       Next (Public)
+ **************************************************************************/
+void libvlc_media_list_player_next( libvlc_media_list_player_t * p_mlp,
+                                    libvlc_exception_t * p_e )
+{
+       libvlc_media_descriptor_t * p_md;
+       
+       int index;
+       
+       libvlc_media_list_lock( p_mlp->p_mlist );
+
+       index = get_next_index( p_mlp );
+
+       if( index < 0 )
+       {
+               libvlc_media_list_unlock( p_mlp->p_mlist );
+               libvlc_exception_raise( p_e, "No more element to play" );
+               libvlc_media_list_player_stop( p_mlp, p_e );
+               return;
+       }
+
+       p_md = libvlc_media_list_item_at_index( p_mlp->p_mlist, index, p_e );
+       if( !p_md )
+       {
+               libvlc_media_list_unlock( p_mlp->p_mlist );             
+               if( !libvlc_exception_raised( p_e ) )
+                       libvlc_exception_raise( p_e, "Can't obtain a media" );
+               return;
+       }
+
+    vlc_mutex_lock( &p_mlp->object_lock );
+       
+    p_mlp->i_current_playing_index = index;
+
+       /* We are not interested in getting media_descriptor stop event now */
+       uninstall_media_instance_observer( p_mlp );
+    libvlc_media_instance_set_media_descriptor( p_mlp->p_mi, p_md, NULL );
+//     wait_playing_state(); /* If we want to be synchronous */
+       install_media_instance_observer( p_mlp );
+
+    vlc_mutex_unlock( &p_mlp->object_lock );
+
+       libvlc_media_list_unlock( p_mlp->p_mlist );             
+       
+       libvlc_media_descriptor_release( p_md ); /* for libvlc_media_list_item_at_index */
+}
+
diff --git a/src/control/tag_query.c b/src/control/tag_query.c
new file mode 100644 (file)
index 0000000..8de212c
--- /dev/null
@@ -0,0 +1,103 @@
+/*****************************************************************************
+ * tag_query.c: libvlc new API media tag query functions
+ *****************************************************************************
+ * Copyright (C) 2007 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include "libvlc_internal.h"
+#include <vlc/libvlc.h>
+#include "vlc_arrays.h"
+
+/* XXX This API is in construction
+ * 
+ * It's goal is to represent a meta tag query
+ * It should be also able to say if a query can be matched in a media
+ * descriptor through libvlc_query_match.
+ */
+/*
+ * Public libvlc functions
+ */
+
+/**************************************************************************
+ *       libvlc_tag_query_new (Public)
+ *
+ * Init an object.
+ **************************************************************************/
+libvlc_tag_query_t *
+libvlc_tag_query_new( libvlc_instance_t * p_inst,
+                      libvlc_exception_t * p_e )
+{
+       (void)p_e;
+    libvlc_tag_query_t * p_q;
+
+       p_q = malloc(sizeof(libvlc_tag_query_t));
+
+       if( !p_q )
+               return NULL;
+       
+       p_q->p_libvlc_instance = p_inst;
+    p_q->i_refcount = 1;
+
+       return p_q;
+}
+
+/**************************************************************************
+ *       libvlc_media_list_release (Public)
+ *
+ * Release an object.
+ **************************************************************************/
+void libvlc_tag_query_release( libvlc_tag_query_t * p_q )
+{
+    p_q->i_refcount--;
+
+    if( p_q->i_refcount > 0 )
+        return;
+
+       free( p_q );
+}
+
+/**************************************************************************
+ *       libvlc_media_list_retain (Public)
+ *
+ * Release an object.
+ **************************************************************************/
+void libvlc_tag_query_retain( libvlc_tag_query_t * p_q )
+{
+       p_q->i_refcount++;
+}
+
+
+/**************************************************************************
+ *       libvlc_query_match (Public)
+ *
+ * Return true if the query p_q is matched in p_md
+ **************************************************************************/
+vlc_bool_t
+libvlc_tag_query_match( libvlc_tag_query_t * p_q,
+                        libvlc_media_descriptor_t * p_md,
+                        libvlc_exception_t * p_e )
+{
+       (void)p_q;
+       (void)p_md;
+       (void)p_e;
+    
+    /* In construction... */
+    return 1;
+}