[vlc-devel] [PATCH v4 3/3] Use new media source API from the playlist

Romain Vimont rom1v at videolabs.io
Mon Jul 9 12:13:54 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 | 277 ++++++++++++++----------------
 7 files changed, 194 insertions(+), 152 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..d9a32175135 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 e91bafd89e0..d723783631d 100644
--- a/src/media_source/media_source.c
+++ b/src/media_source/media_source.c
@@ -246,3 +246,31 @@ static void Remove(vlc_media_source_provider_t *msp, vlc_media_source_t *ms)
     vlc_list_remove(&ms_priv(ms)->siblings);
     vlc_mutex_unlock(&priv->lock);
 }
+
+bool vlc_media_source_provider_IsServicesDiscoveryLoaded(vlc_media_source_provider_t *msp, const char *name)
+{
+    media_source_provider_private_t *priv = msp_priv(msp);
+
+    vlc_mutex_lock(&priv->lock);
+    vlc_media_source_t *ms = FindByName(priv, name);
+    vlc_mutex_unlock(&priv->lock);
+
+    return ms != NULL;
+}
+
+int vlc_media_source_provider_vaControl(vlc_media_source_provider_t *msp, const char *name, int query, va_list args)
+{
+    media_source_provider_private_t *priv = msp_priv(msp);
+
+    vlc_mutex_lock(&priv->lock);
+
+    vlc_media_source_t *ms = FindByName(priv, name);
+    assert(ms);
+
+    media_source_private_t *p = ms_priv(ms);
+    int ret = vlc_sd_control(p->sd, query, args);
+
+    vlc_mutex_unlock(&priv->lock);
+
+    return ret;
+}
diff --git a/src/media_source/media_source.h b/src/media_source/media_source.h
index 4a4672a7be0..b9eec4c40de 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 *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 *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 c5f9879a966..4fa55811d59 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 659b86dab71..8249e75c9a7 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 0cc72986672..cf3e7ff9ad8 100644
--- a/src/playlist/services_discovery.c
+++ b/src/playlist/services_discovery.c
@@ -26,218 +26,207 @@
 #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_t 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,
+    .input_updated = NULL, /* already managed by the playlist */
 };
 
-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.cbs = &media_tree_callbacks;
+    p->listener.userdata = p;
+    vlc_media_tree_AddListener(ms->tree, &p->listener);
 
-    /* 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