[vlc-devel] [PATCH v5 3/3] Use new media source API from the playlist
Romain Vimont
rom1v at videolabs.io
Tue Aug 21 16:29:30 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 | 24 +++
src/media_source/media_source.h | 17 ++
src/playlist/engine.c | 6 +-
src/playlist/playlist_internal.h | 8 +-
src/playlist/services_discovery.c | 281 +++++++++++++++---------------
7 files changed, 194 insertions(+), 152 deletions(-)
diff --git a/include/vlc_playlist.h b/include/vlc_playlist.h
index 51f1d0e82b..2fd985b37e 100644
--- a/include/vlc_playlist.h
+++ b/include/vlc_playlist.h
@@ -344,13 +344,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 9910463065..d9a3217513 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 *msp = libvlc_priv(libvlc)->media_source_provider;
+ assert(msp);
+ playlist = playlist_Create(VLC_OBJECT(libvlc), 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 d87f369eab..8a1fce24f0 100644
--- a/src/media_source/media_source.c
+++ b/src/media_source/media_source.c
@@ -230,3 +230,27 @@ vlc_media_source_t *vlc_media_source_provider_GetMediaSource(vlc_media_source_pr
return ms;
}
+
+bool vlc_media_source_provider_IsServicesDiscoveryLoaded(vlc_media_source_provider_t *provider, const char *name)
+{
+ vlc_mutex_lock(&provider->lock);
+ vlc_media_source_t *ms = FindByName(provider, name);
+ vlc_mutex_unlock(&provider->lock);
+
+ return ms != NULL;
+}
+
+int vlc_media_source_provider_vaControl(vlc_media_source_provider_t *provider, const char *name, int query, va_list args)
+{
+ vlc_mutex_lock(&provider->lock);
+
+ vlc_media_source_t *ms = FindByName(provider, name);
+ assert(ms);
+
+ media_source_private_t *p = ms_priv(ms);
+ int ret = vlc_sd_control(p->sd, query, args);
+
+ vlc_mutex_unlock(&provider->lock);
+
+ return ret;
+}
diff --git a/src/media_source/media_source.h b/src/media_source/media_source.h
index 242c7bace3..9dc911b6f2 100644
--- a/src/media_source/media_source.h
+++ b/src/media_source/media_source.h
@@ -28,4 +28,21 @@ vlc_media_source_provider_t *vlc_media_source_provider_Create(vlc_object_t *pare
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 *name) VLC_DEPRECATED;
+
+/** Query a services discovery */
+int vlc_media_source_provider_vaControl(vlc_media_source_provider_t *, const char *name, int query, va_list args);
+
+static inline int vlc_media_source_provider_Control(vlc_media_source_provider_t *msp, const char *name, int query, ...)
+{
+ va_list args;
+ va_start(args, query);
+ int ret = vlc_media_source_provider_vaControl(msp, name, query, args);
+ va_end(args);
+ return ret;
+}
+
#endif
diff --git a/src/playlist/engine.c b/src/playlist/engine.c
index 400396a41f..a4a7c19546 100644
--- a/src/playlist/engine.c
+++ b/src/playlist/engine.c
@@ -194,7 +194,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 *media_source_provider )
{
playlist_t *p_playlist;
playlist_private_t *p;
@@ -209,7 +209,9 @@ playlist_t *playlist_Create( vlc_object_t *p_parent )
p->input_tree = NULL;
p->id_tree = NULL;
- vlc_list_init(&p->sds);
+ p->media_source_provider = 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 793ed6a514..9b62cb43d4 100644
--- a/src/playlist/playlist_internal.h
+++ b/src/playlist/playlist_internal.h
@@ -38,6 +38,7 @@
#include <assert.h>
#include "preparser/preparser.h"
+#include "media_source/media_source.h"
void playlist_ServicesDiscoveryKillAll( playlist_t *p_playlist );
@@ -50,7 +51,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 *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 0cc7298667..03b80afbfc 100644
--- a/src/playlist/services_discovery.c
+++ b/src/playlist/services_discovery.c
@@ -26,218 +26,211 @@
#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 *playlist;
+ playlist_item_t *root;
+ vlc_media_source_t *ms;
+ vlc_media_tree_listener_id *listener;
+ const char *name;
+ struct vlc_list siblings;
+} playlist_sd_entry_t;
+
+static void media_tree_node_added(vlc_media_tree_t *tree,
+ const input_item_node_t *parent,
+ const input_item_node_t *node,
+ void *userdata)
{
- assert(parent == NULL || psz_cat == NULL);
+ assert(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->playlist);
- msg_Dbg(sd, "adding: %s", p_input->psz_name ? p_input->psz_name : "(null)");
+ playlist_item_t *parent_item;
+ if (parent != &tree->root)
+ parent_item = playlist_ItemGetByInput(p->playlist, parent->p_item);
+ else
+ parent_item = 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 (parent_item->i_children == -1)
+ 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->playlist, node->p_item, parent_item, PLAYLIST_END);
- playlist_NodeAddInput(playlist, p_input, node, PLAYLIST_END);
- playlist_Unlock(playlist);
+ playlist_Unlock(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 *tree,
+ const input_item_node_t *node_parent,
+ const input_item_node_t *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(tree);
+ VLC_UNUSED(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->playlist);
- playlist_Lock(playlist);
- item = playlist_ItemGetByInput(playlist, p_input);
- if (unlikely(item == NULL))
+ playlist_item_t *item = playlist_ItemGetByInput(p->playlist, node->p_item);
+ if (unlikely(!item))
{
- msg_Err(sd, "removing item not added"); /* SD plugin bug */
- playlist_Unlock(playlist);
+ msg_Err(p->playlist, "removing item not added"); /* SD plugin bug */
+ playlist_Unlock(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 *pi = item->p_parent; pi != p->root; pi = pi->p_parent)
+ assert(pi);
#endif
- node = item->p_parent;
+ playlist_item_t *parent = 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 (parent != p->root && parent->i_children == 1)
+ item = parent;
+
+ playlist_NodeDeleteExplicit(p->playlist, item, PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT);
+
+ playlist_Unlock(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 = {
+ .listener_added = vlc_media_tree_listener_added_default,
+ .subtree_added = NULL, /* already managed by the playlist */
+ .node_added = media_tree_node_added,
+ .node_removed = media_tree_node_removed,
};
-int playlist_ServicesDiscoveryAdd(playlist_t *playlist, const char *chain)
+int playlist_ServicesDiscoveryAdd(playlist_t *playlist, const char *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->playlist = playlist;
- struct services_discovery_owner_t owner = {
- &playlist_sd_cbs,
- sds,
- };
+ p->name = strdup(name);
+ if (unlikely(!p->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 *msp = pl_priv(playlist)->media_source_provider;
+ vlc_media_source_t *ms = vlc_media_source_provider_GetMediaSource(msp, name);
+ if (!ms)
{
- free(sds);
+ free(p);
return VLC_ENOMEM;
}
+ p->ms = ms;
- strcpy(sds->name, chain);
+ const char *description = ms->description ? ms->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);
-
- vlc_list_append(&sds->siblings, &pl_priv(playlist)->sds);
+ p->root = playlist_NodeCreate(playlist, description, &playlist->root,
+ PLAYLIST_END, PLAYLIST_RO_FLAG);
playlist_Unlock(playlist);
- return VLC_SUCCESS;
-}
-static void playlist_ServicesDiscoveryInternalRemove(playlist_t *playlist,
- vlc_sd_internal_t *sds)
-{
- assert(sds->sd != NULL);
- vlc_sd_Destroy(sds->sd);
+ p->listener = vlc_media_tree_AddListener(ms->tree, &media_tree_callbacks, p);
+ if (unlikely(!p->listener))
+ {
+ vlc_media_source_Release(p->ms);
+ playlist_NodeDelete(playlist, p->root);
+ free(p);
+ return VLC_ENOMEM;
+ }
- /* Remove the sd playlist node if it exists */
+ /* use the same big playlist lock for this temporary stuff */
+ playlist_private_t *priv = pl_priv(playlist);
playlist_Lock(playlist);
- if (sds->node != NULL)
- playlist_NodeDeleteExplicit(playlist, sds->node,
- PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT );
+ vlc_list_append(&p->siblings, &priv->sd_entries);
playlist_Unlock(playlist);
- free(sds);
+ return VLC_SUCCESS;
}
-
-int playlist_ServicesDiscoveryRemove(playlist_t *playlist, const char *name)
+static playlist_sd_entry_t *RemoveEntry(playlist_t *playlist, const char *name)
{
+ playlist_AssertLocked(playlist);
playlist_private_t *priv = pl_priv(playlist);
- vlc_sd_internal_t *sds = NULL, *entry;
- playlist_Lock(playlist);
- vlc_list_foreach(entry, &priv->sds, siblings)
- if (!strcmp(name, entry->name))
+ playlist_sd_entry_t *p_matching = NULL;
+ playlist_sd_entry_t *p_entry;
+ vlc_list_foreach(p_entry, &priv->sd_entries, siblings)
+ {
+ if (!strcmp(name, p_entry->name))
{
- sds = entry;
- vlc_list_remove(&sds->siblings);
+ p_matching = p_entry;
+ vlc_list_remove(&p_entry->siblings);
break;
}
- playlist_Unlock(playlist);
-
- if (sds == NULL)
- {
- msg_Warn(playlist, "discovery %s is not loaded", name);
- return VLC_EGENERIC;
}
- playlist_ServicesDiscoveryInternalRemove(playlist, sds);
- return VLC_SUCCESS;
+ return p_matching;
}
-bool playlist_IsServicesDiscoveryLoaded( playlist_t * playlist,
- const char *psz_name )
+int playlist_ServicesDiscoveryRemove(playlist_t *playlist, const char *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_sd_entry_t *p = RemoveEntry(playlist, name);
+ assert(p);
+
+ playlist_NodeDeleteExplicit(playlist, p->root,
+ PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT);
+
playlist_Unlock(playlist);
- return found;
+
+ vlc_media_tree_RemoveListener(p->ms->tree, p->listener);
+ vlc_media_source_Release(p->ms);
+
+ free((void *) p->name);
+ free(p);
+
+ return VLC_SUCCESS;
}
-int playlist_ServicesDiscoveryControl( playlist_t *playlist, const char *psz_name, int i_control, ... )
+bool playlist_IsServicesDiscoveryLoaded(playlist_t *playlist, const char *name)
{
- 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);
+ playlist_private_t *priv = pl_priv(playlist);
+ return vlc_media_source_provider_IsServicesDiscoveryLoaded(priv->media_source_provider, name);
+}
- return i_ret;
+int playlist_ServicesDiscoveryControl(playlist_t *playlist, const char *name, int control, ...)
+{
+ playlist_private_t *priv = pl_priv(playlist);
+ va_list args;
+ va_start(args, control);
+ int ret = vlc_media_source_provider_vaControl(priv->media_source_provider, name, control, args);
+ va_end(args);
+ return ret;
}
void playlist_ServicesDiscoveryKillAll(playlist_t *playlist)
{
playlist_private_t *priv = pl_priv(playlist);
- vlc_sd_internal_t *sds;
- vlc_list_foreach(sds, &priv->sds, siblings)
- playlist_ServicesDiscoveryInternalRemove(playlist, sds);
+ playlist_Lock(playlist);
+
+ playlist_sd_entry_t *p_entry;
+ vlc_list_foreach(p_entry, &priv->sd_entries, siblings)
+ {
+ vlc_media_tree_RemoveListener(p_entry->ms->tree, p_entry->listener);
+ vlc_media_source_Release(p_entry->ms);
+ playlist_NodeDeleteExplicit(playlist, p_entry->root,
+ PLAYLIST_DELETE_FORCE | PLAYLIST_DELETE_STOP_IF_CURRENT);
+ free((void *) p_entry->name);
+ free(p_entry);
+ }
+ vlc_list_init(&priv->sd_entries); /* reset */
+ playlist_Unlock(playlist);
}
--
2.18.0
More information about the vlc-devel
mailing list