[vlc-devel] [PATCH v3 3/3] Use new media source API from the playlist
Romain Vimont
rom1v at videolabs.io
Thu Jun 28 10:55:32 CEST 2018
A future UI would use media trees instead of the playlist (currently, in
PLModel for Qt).
As an incremental step, in order not to break the current UI, make the
playlist a client of the new API, so that every changes applied to the
media trees are reflected to the playlist. That way, the media detected
by services discovery are still displayed in the UI.
This is a transitional implementation to be able to update the UI (Qt
and MacOS) separately.
---
include/vlc_playlist.h | 6 +-
src/interface/interface.c | 4 +-
src/media_source/media_source.c | 28 +++
src/media_source/media_source.h | 17 ++
src/playlist/engine.c | 6 +-
src/playlist/playlist_internal.h | 8 +-
src/playlist/services_discovery.c | 296 +++++++++++++++---------------
7 files changed, 206 insertions(+), 159 deletions(-)
diff --git a/include/vlc_playlist.h b/include/vlc_playlist.h
index 5a94eaaae40..dc72759700f 100644
--- a/include/vlc_playlist.h
+++ b/include/vlc_playlist.h
@@ -350,13 +350,13 @@ VLC_API int playlist_Import( playlist_t *p_playlist, const char *psz_file );
/********************** Services discovery ***********************/
/** Add a service discovery module */
-VLC_API int playlist_ServicesDiscoveryAdd(playlist_t *, const char *);
+VLC_API int playlist_ServicesDiscoveryAdd(playlist_t *, const char *) VLC_DEPRECATED;
/** Remove a services discovery module by name */
-VLC_API int playlist_ServicesDiscoveryRemove(playlist_t *, const char *);
+VLC_API int playlist_ServicesDiscoveryRemove(playlist_t *, const char *) VLC_DEPRECATED;
/** Check whether a given SD is loaded */
VLC_API bool playlist_IsServicesDiscoveryLoaded( playlist_t *,const char *) VLC_DEPRECATED;
/** Query a services discovery */
-VLC_API int playlist_ServicesDiscoveryControl( playlist_t *, const char *, int, ... );
+VLC_API int playlist_ServicesDiscoveryControl( playlist_t *, const char *, int, ... ) VLC_DEPRECATED;
/********************** Renderer ***********************/
/**
diff --git a/src/interface/interface.c b/src/interface/interface.c
index 99104630658..c4c3705b6c1 100644
--- a/src/interface/interface.c
+++ b/src/interface/interface.c
@@ -138,7 +138,9 @@ static playlist_t *intf_GetPlaylist(libvlc_int_t *libvlc)
playlist = libvlc_priv(libvlc)->playlist;
if (playlist == NULL)
{
- playlist = playlist_Create(VLC_OBJECT(libvlc));
+ vlc_media_source_provider_t *p_msp = libvlc_priv( libvlc )->p_media_source_provider;
+ assert( p_msp );
+ playlist = playlist_Create( VLC_OBJECT( libvlc ), p_msp );
libvlc_priv(libvlc)->playlist = playlist;
}
vlc_mutex_unlock(&lock);
diff --git a/src/media_source/media_source.c b/src/media_source/media_source.c
index 14a9e16dddb..03f9d772831 100644
--- a/src/media_source/media_source.c
+++ b/src/media_source/media_source.c
@@ -255,3 +255,31 @@ static void Remove( vlc_media_source_provider_t *p_msp, vlc_media_source_t *p_ms
vlc_list_remove( &ms_priv( p_ms )->siblings );
vlc_mutex_unlock( &p_priv->lock );
}
+
+bool vlc_media_source_provider_IsServicesDiscoveryLoaded( vlc_media_source_provider_t *p_msp, const char *psz_name )
+{
+ media_source_provider_private_t *p_priv = msp_priv( p_msp );
+
+ vlc_mutex_lock( &p_priv->lock );
+ vlc_media_source_t *p_ms = FindByName( p_priv, psz_name );
+ vlc_mutex_unlock( &p_priv->lock );
+
+ return p_ms != NULL;
+}
+
+int vlc_media_source_provider_vaControl( vlc_media_source_provider_t *p_msp, const char *psz_name, int i_query, va_list args )
+{
+ media_source_provider_private_t *p_priv = msp_priv( p_msp );
+
+ vlc_mutex_lock( &p_priv->lock );
+
+ vlc_media_source_t *p_ms = FindByName( p_priv, psz_name );
+ assert( p_ms );
+
+ media_source_private_t *p = ms_priv( p_ms );
+ int ret = vlc_sd_control( p->p_sd, i_query, args );
+
+ vlc_mutex_unlock( &p_priv->lock );
+
+ return ret;
+}
diff --git a/src/media_source/media_source.h b/src/media_source/media_source.h
index 821d0a8bd9c..86e2987340b 100644
--- a/src/media_source/media_source.h
+++ b/src/media_source/media_source.h
@@ -26,4 +26,21 @@
vlc_media_source_provider_t *vlc_media_source_provider_Create( vlc_object_t *p_parent );
void vlc_media_source_provider_Destroy( vlc_media_source_provider_t * );
+// TODO remove below (it's for temporary compatibility)
+
+/** Check whether a given services discovery is loaded */
+bool vlc_media_source_provider_IsServicesDiscoveryLoaded( vlc_media_source_provider_t *, const char *psz_name ) VLC_DEPRECATED;
+
+/** Query a services discovery */
+int vlc_media_source_provider_vaControl( vlc_media_source_provider_t *, const char *psz_name, int i_query, va_list args );
+
+static inline int vlc_media_source_provider_Control( vlc_media_source_provider_t *p_msp, const char *psz_name, int i_query, ... )
+{
+ va_list args;
+ va_start( args, i_query );
+ int ret = vlc_media_source_provider_vaControl( p_msp, psz_name, i_query, args );
+ va_end( args );
+ return ret;
+}
+
#endif
diff --git a/src/playlist/engine.c b/src/playlist/engine.c
index 10c4cf03e68..c94001aab8b 100644
--- a/src/playlist/engine.c
+++ b/src/playlist/engine.c
@@ -184,7 +184,7 @@ static int VideoSplitterCallback( vlc_object_t *p_this, char const *psz_cmd,
* \param p_parent the vlc object that is to be the parent of this playlist
* \return a pointer to the created playlist, or NULL on error
*/
-playlist_t *playlist_Create( vlc_object_t *p_parent )
+playlist_t *playlist_Create( vlc_object_t *p_parent, vlc_media_source_provider_t *p_media_source_provider )
{
playlist_t *p_playlist;
playlist_private_t *p;
@@ -199,7 +199,9 @@ playlist_t *playlist_Create( vlc_object_t *p_parent )
p->input_tree = NULL;
p->id_tree = NULL;
- vlc_list_init(&p->sds);
+ p->p_media_source_provider = p_media_source_provider;
+
+ vlc_list_init( &p->sd_entries );
VariablesInit( p_playlist );
vlc_mutex_init( &p->lock );
diff --git a/src/playlist/playlist_internal.h b/src/playlist/playlist_internal.h
index 6432c6e0832..8e0301a2f10 100644
--- a/src/playlist/playlist_internal.h
+++ b/src/playlist/playlist_internal.h
@@ -39,6 +39,7 @@
#include "art.h"
#include "preparser.h"
+#include "media_source/media_source.h"
void playlist_ServicesDiscoveryKillAll( playlist_t *p_playlist );
@@ -51,7 +52,10 @@ typedef struct playlist_private_t
to playlist item mapping */
void *id_tree; /**< Search tree for item ID to item mapping */
- struct vlc_list sds;
+ /* temporary, will be removed from the playlist later */
+ vlc_media_source_provider_t *p_media_source_provider;
+ struct vlc_list sd_entries;
+
input_thread_t * p_input; /**< the input thread associated
* with the current item */
input_resource_t * p_input_resource; /**< input resources */
@@ -95,7 +99,7 @@ typedef struct playlist_private_t
*****************************************************************************/
/* Creation/Deletion */
-playlist_t *playlist_Create( vlc_object_t * );
+playlist_t *playlist_Create( vlc_object_t *, vlc_media_source_provider_t * );
void playlist_Destroy( playlist_t * );
void playlist_Activate( playlist_t * );
diff --git a/src/playlist/services_discovery.c b/src/playlist/services_discovery.c
index 0cc72986672..040ff7a85ee 100644
--- a/src/playlist/services_discovery.c
+++ b/src/playlist/services_discovery.c
@@ -26,218 +26,212 @@
#include <assert.h>
#include <vlc_common.h>
+#include <vlc_media_tree.h>
#include <vlc_playlist.h>
#include <vlc_services_discovery.h>
#include "playlist_internal.h"
-
-typedef struct vlc_sd_internal_t
-{
- /* the playlist items for category and onelevel */
- playlist_item_t *node;
- services_discovery_t *sd; /**< Loaded service discovery modules */
- struct vlc_list siblings;
- char name[];
-} vlc_sd_internal_t;
-
- /* A new item has been added to a certain sd */
-static void playlist_sd_item_added(services_discovery_t *sd,
- input_item_t *parent, input_item_t *p_input,
- const char *psz_cat)
+#include "media_source/media_source.h"
+
+typedef struct {
+ playlist_t *p_playlist;
+ playlist_item_t *p_root;
+ vlc_media_source_t *p_ms;
+ vlc_media_tree_connection_t *p_conn;
+ const char *psz_name;
+ struct vlc_list siblings;
+} playlist_sd_entry_t;
+
+static void media_tree_node_added( vlc_media_tree_t *p_tree,
+ const input_item_node_t *p_parent,
+ const input_item_node_t *p_node,
+ void *userdata )
{
- assert(parent == NULL || psz_cat == NULL);
+ assert( p_parent );
+ playlist_sd_entry_t *p = userdata;
- vlc_sd_internal_t *sds = sd->owner.sys;
- playlist_t *playlist = (playlist_t *)sd->obj.parent;
- playlist_item_t *node;
- const char *longname = (sd->description != NULL) ? sd->description : "?";
+ playlist_Lock( p->p_playlist );
- msg_Dbg(sd, "adding: %s", p_input->psz_name ? p_input->psz_name : "(null)");
+ playlist_item_t *p_parent_item;
+ if( p_parent != &p_tree->root )
+ p_parent_item = playlist_ItemGetByInput( p->p_playlist, p_parent->p_item );
+ else
+ p_parent_item = p->p_root;
- playlist_Lock(playlist);
- if (sds->node == NULL)
- sds->node = playlist_NodeCreate(playlist, longname, &playlist->root,
- PLAYLIST_END, PLAYLIST_RO_FLAG);
+ /* this is a hack, but this whole media_tree-to-playlist adapter is temporary */
+ if( p_parent_item->i_children == -1)
+ p_parent_item->i_children = 0; /* it's a node! */
- if (parent != NULL)
- node = playlist_ItemGetByInput(playlist, parent);
- else
- if (psz_cat == NULL)
- node = sds->node;
- else
- { /* Parent is NULL (root) and category is specified.
- * This is clearly a hack. TODO: remove this. */
- node = playlist_ChildSearchName(sds->node, psz_cat);
- if (node == NULL)
- node = playlist_NodeCreate(playlist, psz_cat, sds->node,
- PLAYLIST_END, PLAYLIST_RO_FLAG);
- }
+ playlist_NodeAddInput( p->p_playlist, p_node->p_item, p_parent_item, PLAYLIST_END );
- playlist_NodeAddInput(playlist, p_input, node, PLAYLIST_END);
- playlist_Unlock(playlist);
+ playlist_Unlock( p->p_playlist );
}
- /* A new item has been removed from a certain sd */
-static void playlist_sd_item_removed(services_discovery_t *sd,
- input_item_t *p_input)
+static void media_tree_node_removed( vlc_media_tree_t *p_tree,
+ const input_item_node_t *p_node_parent,
+ const input_item_node_t *p_node,
+ void *userdata )
{
- vlc_sd_internal_t *sds = sd->owner.sys;
- playlist_t *playlist = (playlist_t *)sd->obj.parent;
- playlist_item_t *node, *item;
+ VLC_UNUSED( p_tree );
+ VLC_UNUSED( p_node_parent );
+ playlist_sd_entry_t *p = userdata;
- msg_Dbg(sd, "removing: %s", p_input->psz_name ? p_input->psz_name : "(null)");
+ playlist_Lock( p->p_playlist );
- playlist_Lock(playlist);
- item = playlist_ItemGetByInput(playlist, p_input);
- if (unlikely(item == NULL))
+ playlist_item_t *p_item = playlist_ItemGetByInput( p->p_playlist, p_node->p_item );
+ if( unlikely( !p_item ) )
{
- msg_Err(sd, "removing item not added"); /* SD plugin bug */
- playlist_Unlock(playlist);
+ msg_Err( p->p_playlist, "removing item not added" ); /* SD plugin bug */
+ playlist_Unlock( p->p_playlist );
return;
}
#ifndef NDEBUG
/* Check that the item belonged to the SD */
- for (playlist_item_t *i = item->p_parent; i != sds->node; i = i->p_parent)
- assert(i != NULL);
+ for( playlist_item_t *p_i = p_item->p_parent; p_i != p->p_root; p_i = p_i->p_parent )
+ assert( p_i );
#endif
- node = item->p_parent;
+ playlist_item_t *p_parent = p_item->p_parent;
/* if the item was added under a category and the category node
becomes empty, delete that node as well */
- if (node != sds->node && node->i_children == 1)
- item = node;
- playlist_NodeDeleteExplicit(playlist, item,
- PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT );
- playlist_Unlock(playlist);
+ if( p_parent != p->p_root && p_parent->i_children == 1 )
+ p_item = p_parent;
+
+ playlist_NodeDeleteExplicit( p->p_playlist, p_item, PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT );
+
+ playlist_Unlock( p->p_playlist );
}
-static const struct services_discovery_callbacks playlist_sd_cbs = {
- .item_added = playlist_sd_item_added,
- .item_removed = playlist_sd_item_removed,
+static const vlc_media_tree_callbacks_t media_tree_callbacks = {
+ .pf_tree_connected = vlc_media_tree_connected_default,
+ .pf_subtree_added = NULL, /* already managed by the playlist */
+ .pf_node_added = media_tree_node_added,
+ .pf_node_removed = media_tree_node_removed,
+ .pf_input_updated = NULL, /* already managed by the playlist */
};
-int playlist_ServicesDiscoveryAdd(playlist_t *playlist, const char *chain)
+int playlist_ServicesDiscoveryAdd( playlist_t *p_playlist, const char *psz_name )
{
- vlc_sd_internal_t *sds = malloc(sizeof (*sds) + strlen(chain) + 1);
- if (unlikely(sds == NULL))
+ playlist_sd_entry_t *p = malloc( sizeof( *p ) );
+ if( unlikely( !p ) )
return VLC_ENOMEM;
- sds->node = NULL;
+ p->p_playlist = p_playlist;
- struct services_discovery_owner_t owner = {
- &playlist_sd_cbs,
- sds,
- };
+ p->psz_name = strdup( psz_name );
+ if( unlikely( !p->psz_name ) )
+ {
+ free( p );
+ return VLC_ENOMEM;
+ }
- /* Perform the addition */
- sds->sd = vlc_sd_Create(VLC_OBJECT(playlist), chain, &owner);
- if (unlikely(sds->sd == NULL))
+ vlc_media_source_provider_t *p_msp = pl_priv( p_playlist )->p_media_source_provider;
+ vlc_media_source_t *p_ms = vlc_media_source_provider_GetMediaSource( p_msp, psz_name );
+ if( !p_ms )
{
- free(sds);
+ free( p );
return VLC_ENOMEM;
}
+ p->p_ms = p_ms;
- strcpy(sds->name, chain);
+ const char *psz_description = p_ms->psz_description ? p_ms->psz_description : "?";
- playlist_Lock(playlist);
- /* Backward compatibility with Qt UI: create the node even if the SD
- * has not discovered any item. */
- if (sds->node == NULL && sds->sd->description != NULL)
- sds->node = playlist_NodeCreate(playlist, sds->sd->description,
- &playlist->root, PLAYLIST_END,
- PLAYLIST_RO_FLAG);
+ playlist_Lock( p_playlist );
+ p->p_root = playlist_NodeCreate( p_playlist, psz_description, &p_playlist->root,
+ PLAYLIST_END, PLAYLIST_RO_FLAG );
+ playlist_Unlock( p_playlist );
+
+ p->p_conn = vlc_media_tree_Connect( p_ms->p_tree, &media_tree_callbacks, p );
+ if( !p->p_conn )
+ {
+ vlc_media_source_Release( p->p_ms );
+ free( p );
+ return VLC_ENOMEM;
+ }
+
+ /* use the same big playlist lock for this temporary stuff */
+ playlist_private_t *p_priv = pl_priv( p_playlist );
+ playlist_Lock( p_playlist );
+ vlc_list_append( &p->siblings, &p_priv->sd_entries );
+ playlist_Unlock( p_playlist );
- vlc_list_append(&sds->siblings, &pl_priv(playlist)->sds);
- playlist_Unlock(playlist);
return VLC_SUCCESS;
}
-static void playlist_ServicesDiscoveryInternalRemove(playlist_t *playlist,
- vlc_sd_internal_t *sds)
+static playlist_sd_entry_t *RemoveEntry( playlist_t *p_playlist, const char *psz_name )
{
- assert(sds->sd != NULL);
- vlc_sd_Destroy(sds->sd);
+ playlist_AssertLocked( p_playlist );
+ playlist_private_t *p_priv = pl_priv( p_playlist );
- /* Remove the sd playlist node if it exists */
- playlist_Lock(playlist);
- if (sds->node != NULL)
- playlist_NodeDeleteExplicit(playlist, sds->node,
- PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT );
- playlist_Unlock(playlist);
+ playlist_sd_entry_t *p_matching = NULL;
+ playlist_sd_entry_t *p_entry;
+ vlc_list_foreach( p_entry, &p_priv->sd_entries, siblings )
+ {
+ if( !strcmp( psz_name, p_entry->psz_name ) )
+ {
+ p_matching = p_entry;
+ vlc_list_remove( &p_entry->siblings );
+ break;
+ }
+ }
- free(sds);
+ return p_matching;
}
-
-int playlist_ServicesDiscoveryRemove(playlist_t *playlist, const char *name)
+int playlist_ServicesDiscoveryRemove( playlist_t *p_playlist, const char *psz_name )
{
- playlist_private_t *priv = pl_priv(playlist);
- vlc_sd_internal_t *sds = NULL, *entry;
+ playlist_Lock( p_playlist );
- playlist_Lock(playlist);
- vlc_list_foreach(entry, &priv->sds, siblings)
- if (!strcmp(name, entry->name))
- {
- sds = entry;
- vlc_list_remove(&sds->siblings);
- break;
- }
- playlist_Unlock(playlist);
+ playlist_sd_entry_t *p = RemoveEntry( p_playlist, psz_name );
+ assert( p );
- if (sds == NULL)
- {
- msg_Warn(playlist, "discovery %s is not loaded", name);
- return VLC_EGENERIC;
- }
+ playlist_NodeDeleteExplicit( p_playlist, p->p_root,
+ PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT );
+
+ playlist_Unlock( p_playlist );
+
+ vlc_media_tree_Disconnect( p->p_ms->p_tree, p->p_conn );
+ vlc_media_source_Release( p->p_ms );
+
+ free( ( void * )p->psz_name );
+ free( p );
- playlist_ServicesDiscoveryInternalRemove(playlist, sds);
return VLC_SUCCESS;
}
-bool playlist_IsServicesDiscoveryLoaded( playlist_t * playlist,
+bool playlist_IsServicesDiscoveryLoaded( playlist_t *p_playlist,
const char *psz_name )
{
- playlist_private_t *priv = pl_priv( playlist );
- vlc_sd_internal_t *sds;
- bool found = false;
-
- playlist_Lock(playlist);
- vlc_list_foreach(sds, &priv->sds, siblings)
- if (!strcmp(psz_name, sds->name))
- {
- found = true;
- break;
- }
- playlist_Unlock(playlist);
- return found;
+ playlist_private_t *p_priv = pl_priv( p_playlist );
+ return vlc_media_source_provider_IsServicesDiscoveryLoaded( p_priv->p_media_source_provider, psz_name );
}
-int playlist_ServicesDiscoveryControl( playlist_t *playlist, const char *psz_name, int i_control, ... )
+int playlist_ServicesDiscoveryControl( playlist_t *p_playlist, const char *psz_name, int i_control, ... )
{
- playlist_private_t *priv = pl_priv( playlist );
- vlc_sd_internal_t *sds;
- int i_ret = VLC_EGENERIC;
-
- playlist_Lock(playlist);
- vlc_list_foreach(sds, &priv->sds, siblings)
- if (!strcmp(psz_name, sds->name))
- {
- va_list args;
- va_start( args, i_control );
- i_ret = vlc_sd_control(sds->sd, i_control, args );
- va_end( args );
- break;
- }
- playlist_Unlock(playlist);
-
- return i_ret;
+ playlist_private_t *p_priv = pl_priv( p_playlist );
+ va_list args;
+ va_start( args, i_control );
+ int ret = vlc_media_source_provider_vaControl( p_priv->p_media_source_provider, psz_name, i_control, args );
+ va_end( args );
+ return ret;
}
-void playlist_ServicesDiscoveryKillAll(playlist_t *playlist)
+void playlist_ServicesDiscoveryKillAll( playlist_t *p_playlist )
{
- playlist_private_t *priv = pl_priv(playlist);
- vlc_sd_internal_t *sds;
+ playlist_private_t *p_priv = pl_priv( p_playlist );
+
+ playlist_Lock( p_playlist );
- vlc_list_foreach(sds, &priv->sds, siblings)
- playlist_ServicesDiscoveryInternalRemove(playlist, sds);
+ playlist_sd_entry_t *p_entry;
+ vlc_list_foreach( p_entry, &p_priv->sd_entries, siblings )
+ {
+ vlc_media_tree_Disconnect( p_entry->p_ms->p_tree, p_entry->p_conn );
+ vlc_media_source_Release( p_entry->p_ms );
+ playlist_NodeDeleteExplicit( p_playlist, p_entry->p_root,
+ PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT );
+ free( ( void * )p_entry->psz_name );
+ free( p_entry );
+ }
+ vlc_list_init( &p_priv->sd_entries ); /* reset */
+ playlist_Unlock( p_playlist );
}
--
2.18.0
More information about the vlc-devel
mailing list