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

Romain Vimont rom1v at videolabs.io
Fri Jun 22 14:30:00 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..5de8f3586a6 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));
+        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 f6a9a5c9cbe..1e6a3a14e7b 100644
--- a/src/media_source/media_source.c
+++ b/src/media_source/media_source.c
@@ -255,3 +255,31 @@ static void Remove( media_source_provider_t *p_msp, media_source_t *p_ms )
     vlc_list_remove( &ms_priv( p_ms )->siblings );
     vlc_mutex_unlock( &p_priv->lock );
 }
+
+bool media_source_provider_IsServicesDiscoveryLoaded( 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 );
+    media_source_t *p_ms = FindByName( p_priv, psz_name );
+    vlc_mutex_unlock( &p_priv->lock );
+
+    return p_ms != NULL;
+}
+
+int media_source_provider_vaControl( 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 );
+
+    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 a9bf73718a3..ad14e8b414c 100644
--- a/src/media_source/media_source.h
+++ b/src/media_source/media_source.h
@@ -26,4 +26,21 @@
 media_source_provider_t *media_source_provider_Create( vlc_object_t *p_parent );
 void media_source_provider_Destroy( media_source_provider_t * );
 
+// TODO remove below (it's for temporary compatibility)
+
+/** Check whether a given services discovery is loaded */
+bool media_source_provider_IsServicesDiscoveryLoaded( media_source_provider_t *, const char *psz_name ) VLC_DEPRECATED;
+
+/** Query a services discovery */
+int media_source_provider_vaControl( media_source_provider_t *, const char *psz_name, int i_query, va_list args );
+
+static inline int media_source_provider_Control( media_source_provider_t *p_msp, const char *psz_name, int i_query, ... )
+{
+    va_list args;
+    va_start( args, i_query );
+    int ret = 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..e1373791083 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, 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..56f9621f7ec 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 */
+    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 *, 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..30bc3d1a59a 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;
+    media_source_t *p_ms;
+    media_tree_connection_t *p_conn;
+    const char *psz_name;
+    struct vlc_list siblings;
+} playlist_sd_entry_t;
+
+static void media_tree_node_added( 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( 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 media_tree_callbacks_t media_tree_callbacks = {
+    .pf_tree_connected = 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))
+    media_source_provider_t *p_msp = pl_priv( p_playlist )->p_media_source_provider;
+    media_source_t *p_ms = 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 = media_tree_Connect( p_ms->p_tree, &media_tree_callbacks, p );
+    if( !p->p_conn )
+    {
+        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 );
+
+    media_tree_Disconnect( p->p_ms->p_tree, p->p_conn );
+    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 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 = 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 )
+    {
+        media_tree_Disconnect( p_entry->p_ms->p_tree, p_entry->p_conn );
+        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.rc2



More information about the vlc-devel mailing list