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 );
/**
* \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.
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 *);
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
/**@} */
+/*****************************************************************************
+ * 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
*****************************************************************************/
/**@} */
+
/*****************************************************************************
* Media Instance
*****************************************************************************/
/**@} */
+/*****************************************************************************
+ * 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
typedef enum libvlc_event_type_t {
libvlc_MediaInstanceReachedEnd,
+ libvlc_MediaListItemAdded,
+ libvlc_MediaListItemDeleted,
+ libvlc_MediaListItemChanged,
} 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;
* \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 * );
/**@} */
{
/* 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;
}
{
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;
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
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 );
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 );
/**************************************************************************
* 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 )
input_DestroyThread( p_input_thread );
- libvlc_media_descriptor_destroy( p_mi->p_md );
+ libvlc_media_descriptor_release( p_mi->p_md );
free( 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
**************************************************************************/
release_input_thread( p_mi );
- libvlc_media_descriptor_destroy( p_mi->p_md );
+ libvlc_media_descriptor_release( p_mi->p_md );
if( !p_md )
{
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
**************************************************************************/
--- /dev/null
+/*****************************************************************************
+ * 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;
+}
+
--- /dev/null
+/*****************************************************************************
+ * 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 */
+}
+
--- /dev/null
+/*****************************************************************************
+ * 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;
+}