[vlc-devel] [PATCH v4 1/3] Introduce media source and media tree API

Romain Vimont rom1v at videolabs.io
Tue Jul 10 14:32:46 CEST 2018


Thank you for the review.

On Mon, Jul 09, 2018 at 07:54:04AM -0700, Hugo Beauzée-Luyssen wrote:
> 
> 
> On Mon, Jul 9, 2018, at 3:13 AM, Romain Vimont wrote:
> > Add an API to manage "services discovery" out of the playlist.
> > 
> > A "media source provider", associated to the libvlc instance, allows to
> > retrieve media sources (each associated to a services discovery module).
> > 
> > Requesting a services discovery that is not open will automatically open
> > it. If several "clients" request the same media source (i.e. by
> > requesting the same name), they will receive the same (refcounted) media
> > source instance.
> > 
> > As soon as a media source is released by all its clients, the associated
> > services discovery is closed.
> > 
> > Each media source holds a media tree, independant of the playlist, used
> > to store the input items detected by the services discovery. Clients may
> > listen to the tree to be notified of changes.
> > ---
> >  include/vlc_media_source.h       |  93 +++++++++++
> >  include/vlc_media_tree.h         | 126 +++++++++++++++
> >  include/vlc_services_discovery.h |   2 +
> >  src/Makefile.am                  |   6 +
> >  src/input/services_discovery.c   |   1 +
> >  src/libvlc.c                     |   9 ++
> >  src/libvlc.h                     |   2 +
> >  src/libvlccore.sym               |  10 ++
> >  src/media_source/media_source.c  | 248 +++++++++++++++++++++++++++++
> >  src/media_source/media_source.h  |  29 ++++
> >  src/media_tree/media_tree.c      | 261 +++++++++++++++++++++++++++++++
> >  src/media_tree/media_tree.h      |  34 ++++
> >  12 files changed, 821 insertions(+)
> >  create mode 100644 include/vlc_media_source.h
> >  create mode 100644 include/vlc_media_tree.h
> >  create mode 100644 src/media_source/media_source.c
> >  create mode 100644 src/media_source/media_source.h
> >  create mode 100644 src/media_tree/media_tree.c
> >  create mode 100644 src/media_tree/media_tree.h
> > 
> > diff --git a/include/vlc_media_source.h b/include/vlc_media_source.h
> > new file mode 100644
> > index 00000000000..963f80c5921
> > --- /dev/null
> > +++ b/include/vlc_media_source.h
> > @@ -0,0 +1,93 @@
> > +/
> > *****************************************************************************
> > + * vlc_media_source.h : Media source
> > + 
> > *****************************************************************************
> > + * Copyright (C) 2018 VLC authors and VideoLAN
> > + *
> > + * This program is free software; you can redistribute it and/or modify 
> > it
> > + * under the terms of the GNU Lesser General Public License as 
> > published by
> > + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser 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.
> > + 
> > *****************************************************************************/
> > +
> > +#ifndef VLC_MEDIA_SOURCE_H
> > +#define VLC_MEDIA_SOURCE_H
> > +
> > +#include <vlc_common.h>
> > +
> > +typedef struct vlc_media_tree_t vlc_media_tree_t;
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +/**
> > + * \defgroup media_source Media source
> > + * \ingroup input
> > + * @{
> > + */
> > +
> > +/**
> > + * Media source.
> > + *
> > + * A media source is associated to a "service discovery". It stores the
> > + * detected media in a media tree.
> > + */
> > +typedef struct vlc_media_source_t
> > +{
> > +    vlc_media_tree_t *tree;
> > +    const char *description;
> > +} vlc_media_source_t;
> > +
> > +/**
> > + * Increase the media source reference count.
> > + */
> > +VLC_API void vlc_media_source_Hold(vlc_media_source_t *);
> > +
> > +/**
> > + * Decrease the media source reference count.
> > + *
> > + * Destroy the media source and close the associated "service 
> > discovery" if it
> > + * reaches 0.
> > + */
> > +VLC_API void vlc_media_source_Release(vlc_media_source_t *);
> > +
> > +/**
> > + * Media source provider, used to get media sources.
> > + *
> > + * It's typically used as an opaque pointer.
> > + */
> > +typedef struct vlc_media_source_provider_t
> > +{
> > +    struct vlc_common_members obj;
> > +    /* all other fields are private */
> > +} vlc_media_source_provider_t;
> > +
> > +/**
> > + * Return the media source provider associated to the libvlc instance.
> > + */
> > +VLC_API vlc_media_source_provider_t 
> > *vlc_media_source_provider_Get(libvlc_int_t *);
> > +
> > +/**
> > + * Return the media source identified by psz_name.
> > + *
> > + * The resulting media source must be released by 
> > vlc_media_source_Release().
> > + */
> > +VLC_API vlc_media_source_t 
> > *vlc_media_source_provider_GetMediaSource(vlc_media_source_provider_t *, 
> > const char *name);
> > +
> > +/** @} */
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif
> > +
> > diff --git a/include/vlc_media_tree.h b/include/vlc_media_tree.h
> > new file mode 100644
> > index 00000000000..b9d2c6f194b
> > --- /dev/null
> > +++ b/include/vlc_media_tree.h
> > @@ -0,0 +1,126 @@
> > +/
> > *****************************************************************************
> > + * vlc_media_tree.h : Media tree
> > + 
> > *****************************************************************************
> > + * Copyright (C) 2018 VLC authors and VideoLAN
> > + *
> > + * This program is free software; you can redistribute it and/or modify 
> > it
> > + * under the terms of the GNU Lesser General Public License as 
> > published by
> > + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser 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.
> > + 
> > *****************************************************************************/
> > +
> > +#ifndef VLC_MEDIA_TREE_H
> > +#define VLC_MEDIA_TREE_H
> > +
> > +#include <vlc_common.h>
> > +#include <vlc_arrays.h>
> > +#include <vlc_input_item.h>
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +/**
> > + * \defgroup media_tree Media tree
> > + * \ingroup input
> > + * @{
> > + */
> > +
> > +/**
> > + * Media tree.
> > + *
> > + * Nodes must be traversed with locked held (vlc_media_tree_Lock()).
> > + */
> > +typedef struct vlc_media_tree_t {
> > +    input_item_node_t root;
> > +} vlc_media_tree_t;
> > +
> > +/**
> > + * Callbacks to receive media tree events.
> > + */
> > +typedef struct vlc_media_tree_callbacks_t
> > +{
> > +    /**
> > +     * Called on vlc_media_tree_AddListener(), with lock held.
> > +     *
> > +     * Use vlc_media_tree_listener_added_default implementation to call
> > +     * node_added() for every node.
> > +     */
> > +    void (*listener_added)(vlc_media_tree_t *, void *userdata);
> > +
> > +    /**
> > +     * Called after a new node has been added to the media tree, with 
> > lock held.
> > +     */
> > +    void (*node_added)(vlc_media_tree_t *, const input_item_node_t 
> > *parent,
> > +                       const input_item_node_t *, void *userdata);
> > +
> > +    /**
> > +     * Called after a node has been removed from the media tree, with 
> > lock held.
> > +     */
> > +    void (*node_removed)(vlc_media_tree_t *, const input_item_node_t 
> > *parent,
> > +                         const input_item_node_t *, void *userdata);
> > +} vlc_media_tree_callbacks_t;
> > +
> > +/**
> > + * Listener for media tree events.
> > + */
> > +typedef struct vlc_media_tree_listener_t
> > +{
> > +    const vlc_media_tree_callbacks_t *cbs;
> > +    void *userdata;
> > +} vlc_media_tree_listener_t;
> > +
> > +/**
> > + * Default implementation for listener_added(), which calls 
> > node_added() for
> > + * every existing node.
> > + **/
> > +VLC_API void vlc_media_tree_listener_added_default(vlc_media_tree_t *, 
> > void *userdata);
> > +
> > +/**
> > + * Add listener. The lock must NOT be held.
> > + */
> > +VLC_API void vlc_media_tree_AddListener(vlc_media_tree_t *, 
> > vlc_media_tree_listener_t *);
> > +
> > +/**
> > + * Remove listener. The lock must NOT be held.
> > + */
> > +VLC_API void vlc_media_tree_RemoveListener(vlc_media_tree_t *, 
> > vlc_media_tree_listener_t *);
> > +
> > +/**
> > + * Lock the media tree (non-recursive).
> > + */
> > +VLC_API void vlc_media_tree_Lock(vlc_media_tree_t *);
> > +
> > +/**
> > + * Unlock the media tree.
> > + */
> > +VLC_API void vlc_media_tree_Unlock(vlc_media_tree_t *);
> > +
> > +/**
> > + * Find the node containing the requested input item (and its parent).
> > + *
> > + * \param result point to the matching node if the function returns 
> > true [OUT]
> > + * \param result_parent if not NULL, point to the matching node parent
> > + *                      if the function returns true [OUT]
> > + *
> > + * \return true if found, false otherwise.
> > + */
> > +VLC_API bool vlc_media_tree_Find(vlc_media_tree_t *, const input_item_t 
> > *,
> > +                                 input_item_node_t **result, 
> > input_item_node_t **result_parent);
> > +
> > +/** @} */
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif
> > diff --git a/include/vlc_services_discovery.h b/include/
> > vlc_services_discovery.h
> > index 1f5305b788e..e117a1c0a52 100644
> > --- a/include/vlc_services_discovery.h
> > +++ b/include/vlc_services_discovery.h
> > @@ -149,6 +149,8 @@ VLC_API char ** vlc_sd_GetNames( vlc_object_t *, 
> > char ***, int ** ) VLC_USED;
> >  VLC_API services_discovery_t *vlc_sd_Create(vlc_object_t *parent,
> >      const char *chain, const struct services_discovery_owner_t *owner)
> >  VLC_USED;
> > +#define vlc_sd_Create( obj, a, b ) \
> > +        vlc_sd_Create( VLC_OBJECT( obj ), a, b )
> >  
> >  VLC_API void vlc_sd_Destroy( services_discovery_t * );
> >  
> > diff --git a/src/Makefile.am b/src/Makefile.am
> > index f9106a17c54..05866910842 100644
> > --- a/src/Makefile.am
> > +++ b/src/Makefile.am
> > @@ -62,10 +62,12 @@ pluginsinclude_HEADERS = \
> >  	../include/vlc_keystore.h \
> >  	../include/vlc_list.h \
> >  	../include/vlc_md5.h \
> > +	../include/vlc_media_source.h \
> >  	../include/vlc_messages.h \
> >  	../include/vlc_meta.h \
> >  	../include/vlc_meta_fetcher.h \
> >  	../include/vlc_media_library.h \
> > +	../include/vlc_media_tree.h \
> >  	../include/vlc_memstream.h \
> >  	../include/vlc_mime.h \
> >  	../include/vlc_modules.h \
> > @@ -203,6 +205,10 @@ libvlccore_la_SOURCES = \
> >  	config/getopt.c \
> >  	config/vlc_getopt.h \
> >  	extras/libc.c \
> > +	media_source/media_source.c \
> > +	media_source/media_source.h \
> > +	media_tree/media_tree.c \
> > +	media_tree/media_tree.h \
> >  	modules/modules.h \
> >  	modules/modules.c \
> >  	modules/bank.c \
> > diff --git a/src/input/services_discovery.c b/src/input/
> > services_discovery.c
> > index 12a029ef6e6..7d43e4ee7ab 100644
> > --- a/src/input/services_discovery.c
> > +++ b/src/input/services_discovery.c
> > @@ -103,6 +103,7 @@ char **vlc_sd_GetNames (vlc_object_t *obj, char 
> > ***pppsz_longnames, int **pp_cat
> >   * That's how the playlist get's Service Discovery information
> >   */
> >  
> > +#undef vlc_sd_Create
> >  services_discovery_t *vlc_sd_Create(vlc_object_t *parent, const char *cfg,
> >      const struct services_discovery_owner_t *restrict owner)
> >  {
> > diff --git a/src/libvlc.c b/src/libvlc.c
> > index 169bc37a7de..5e172b9fc9a 100644
> > --- a/src/libvlc.c
> > +++ b/src/libvlc.c
> > @@ -43,6 +43,7 @@
> >  #include "modules/modules.h"
> >  #include "config/configuration.h"
> >  #include "preparser/preparser.h"
> > +#include "media_source/media_source.h"
> >  
> >  #include <stdio.h>                                              /* sprintf() */
> >  #include <string.h>
> > @@ -93,6 +94,7 @@ libvlc_int_t * libvlc_InternalCreate( void )
> >      priv = libvlc_priv (p_libvlc);
> >      priv->playlist = NULL;
> >      priv->p_vlm = NULL;
> > +    priv->media_source_provider = NULL;
> >  
> >      vlc_ExitInit( &priv->exit );
> >  
> > @@ -230,6 +232,10 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, 
> > int i_argc,
> >      if( !priv->parser )
> >          goto error;
> >  
> > +    priv->media_source_provider = 
> > vlc_media_source_provider_Create( VLC_OBJECT( p_libvlc ) );
> > +    if( !priv->media_source_provider )
> > +        goto error;
> > +
> >      /* variables for signalling creation of new files */
> >      var_Create( p_libvlc, "snapshot-file", VLC_VAR_STRING );
> >      var_Create( p_libvlc, "record-file", VLC_VAR_STRING );
> > @@ -363,6 +369,9 @@ void libvlc_InternalCleanup( libvlc_int_t 
> > *p_libvlc )
> >      msg_Dbg( p_libvlc, "removing all interfaces" );
> >      intf_DestroyAll( p_libvlc );
> >  
> > +    if( priv->media_source_provider )
> > +        vlc_media_source_provider_Destroy( priv->media_source_provider );
> > +
> >      libvlc_InternalDialogClean( p_libvlc );
> >      libvlc_InternalKeystoreClean( p_libvlc );
> >  
> > diff --git a/src/libvlc.h b/src/libvlc.h
> > index 6d807cd8a8b..745fc33c502 100644
> > --- a/src/libvlc.h
> > +++ b/src/libvlc.h
> > @@ -172,6 +172,7 @@ void vlc_objres_remove(vlc_object_t *obj, void *data,
> >  typedef struct vlc_dialog_provider vlc_dialog_provider;
> >  typedef struct vlc_keystore vlc_keystore;
> >  typedef struct vlc_actions_t vlc_actions_t;
> > +typedef struct vlc_media_source_provider_t vlc_media_source_provider_t;
> >  
> >  typedef struct libvlc_priv_t
> >  {
> > @@ -184,6 +185,7 @@ typedef struct libvlc_priv_t
> >      vlc_keystore      *p_memory_keystore; ///< memory keystore
> >      struct playlist_t *playlist; ///< Playlist for interfaces
> >      struct input_preparser_t *parser; ///< Input item meta data handler
> > +    vlc_media_source_provider_t *media_source_provider;
> >      vlc_actions_t *actions; ///< Hotkeys handler
> >  
> >      /* Exit callback */
> > diff --git a/src/libvlccore.sym b/src/libvlccore.sym
> > index 4c0145d98b8..fd2d4bbe69c 100644
> > --- a/src/libvlccore.sym
> > +++ b/src/libvlccore.sym
> > @@ -755,3 +755,13 @@ vlc_rd_get_names
> >  vlc_rd_new
> >  vlc_rd_release
> >  vlc_rd_probe_add
> > +vlc_media_source_Hold
> > +vlc_media_source_Release
> > +vlc_media_source_provider_Get
> > +vlc_media_source_provider_GetMediaSource
> > +vlc_media_tree_AddListener
> > +vlc_media_tree_RemoveListener
> > +vlc_media_tree_Lock
> > +vlc_media_tree_Unlock
> > +vlc_media_tree_Find
> > +vlc_media_tree_listener_added_default
> > diff --git a/src/media_source/media_source.c b/src/media_source/
> > media_source.c
> > new file mode 100644
> > index 00000000000..e91bafd89e0
> > --- /dev/null
> > +++ b/src/media_source/media_source.c
> > @@ -0,0 +1,248 @@
> > +/
> > *****************************************************************************
> > + * media_source.c : Media source
> > + 
> > *****************************************************************************
> > + * Copyright (C) 2018 VLC authors and VideoLAN
> > + *
> > + * This program is free software; you can redistribute it and/or modify 
> > it
> > + * under the terms of the GNU Lesser General Public License as 
> > published by
> > + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser 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 "media_source.h"
> > +
> 
> You probably should include media_source after config.h

OK, done.

> > +#ifdef HAVE_CONFIG_H
> > +# include "config.h"
> > +#endif
> > +
> > +#include <assert.h>
> > +#include <vlc_atomic.h>
> > +#include <vlc_media_tree.h>
> > +#include <vlc_playlist.h>
> > +#include <vlc_services_discovery.h>
> > +#include "libvlc.h"
> > +#include "playlist/playlist_internal.h"
> > +#include "media_tree/media_tree.h"
> > +
> > +typedef struct
> > +{
> > +    vlc_media_source_t public_data;
> > +
> > +    services_discovery_t *sd;
> > +    vlc_atomic_rc_t rc;
> > +    vlc_media_source_provider_t *owner;
> > +    struct vlc_list siblings;
> > +    char name[];
> > +} media_source_private_t;
> > +
> > +#define ms_priv(ms) container_of(ms, media_source_private_t, 
> > public_data)
> > +
> > +typedef struct
> > +{
> > +    vlc_media_source_provider_t public_data;
> > +
> > +    vlc_mutex_t lock;
> > +    struct vlc_list media_sources;
> > +} media_source_provider_private_t;
> > +
> > +#define msp_priv(msp) container_of(msp, 
> > media_source_provider_private_t, public_data)
> > +
> > +/* A new item has been added to a certain services discovery */
> > +static void services_discovery_item_added(services_discovery_t *sd,
> > +                                          input_item_t *parent, 
> > input_item_t *input,
> > +                                          const char *cat)
> > +{
> > +    assert(!parent || !cat);
> > +    VLC_UNUSED(cat);
> > +
> > +    vlc_media_source_t *ms = sd->owner.sys;
> > +    vlc_media_tree_t *tree = ms->tree;
> > +
> > +    msg_Dbg(sd, "adding: %s", input->psz_name ? input->psz_name : 
> > "(null)");
> > +
> > +    vlc_media_tree_Lock(tree);
> > +
> > +    input_item_node_t *parent_node;
> > +    if (parent)
> > +        vlc_media_tree_Find(tree, parent, &parent_node, NULL);
> > +    else
> > +        parent_node = &tree->root;
> > +
> > +    vlc_media_tree_Add(tree, parent_node, input);
> > +
> > +    vlc_media_tree_Unlock(tree);
> > +}
> > +
> > +static void services_discovery_item_removed(services_discovery_t *sd, 
> > input_item_t *input)
> > +{
> > +    vlc_media_source_t *ms = sd->owner.sys;
> > +    vlc_media_tree_t *tree = ms->tree;
> > +
> > +    msg_Dbg(sd, "removing: %s", input->psz_name ? input->psz_name : 
> > "(null)");
> > +
> > +    vlc_media_tree_Lock(tree);
> > +    bool removed = vlc_media_tree_Remove(tree, input);
> > +    vlc_media_tree_Unlock(tree);
> > +
> > +    if (unlikely(!removed))
> > +    {
> > +        msg_Err(sd, "removing item not added"); /* SD plugin bug */
> > +        return;
> > +    }
> > +}
> > +
> > +static const struct services_discovery_callbacks 
> > media_source_provider_sd_cbs = {
> > +    .item_added = services_discovery_item_added,
> > +    .item_removed = services_discovery_item_removed,
> > +};
> > +
> > +static inline void AssertLocked(vlc_media_source_provider_t *msp)
> > +{
> > +    media_source_provider_private_t *priv = msp_priv(msp);
> > +    vlc_assert_locked(&priv->lock);
> > +}
> > +
> > +static vlc_media_source_t 
> > *MediaSourceCreate(vlc_media_source_provider_t *msp, const char *name)
> > +{
> > +    media_source_private_t *priv = malloc(sizeof(*priv) + strlen(name) 
> > + 1);
> > +    if (unlikely(!priv))
> > +        return NULL;
> > +
> > +    vlc_atomic_rc_init(&priv->rc);
> > +
> > +    vlc_media_source_t *ms = &priv->public_data;
> > +
> > +    /* vlc_sd_Create() may call services_discovery_item_added(), which 
> > will read its
> > +     * tree, so it must be initialized first */
> > +    ms->tree = vlc_media_tree_Create();
> > +    if (unlikely(!ms->tree))
> > +    {
> > +        free(ms);
> 
> I think it would be more readable to free 'priv'

Yes, of course, using "ms" was an error. Good catch.

> > +        return NULL;
> > +    }
> > +
> > +    strcpy(priv->name, name);
> > +
> > +    struct services_discovery_owner_t owner = {
> > +        .cbs = &media_source_provider_sd_cbs,
> > +        .sys = ms,
> > +    };
> > +
> > +    priv->sd = vlc_sd_Create(msp, name, &owner);
> > +    if (unlikely(!priv->sd))
> > +    {
> > +        vlc_media_tree_Release(ms->tree);
> > +        free(ms);
> > +        return NULL;
> > +    }
> > +
> > +    /* sd->description is set during vlc_sd_Create() */
> > +    ms->description = priv->sd->description;
> > +
> > +    priv->owner = msp;
> > +
> > +    return ms;
> > +}
> > +
> > +static void Remove(vlc_media_source_provider_t *, vlc_media_source_t 
> > *);
> 
> Could you reorder instead of having a forward declaration?

Yes, done.

> > +
> > +static void MediaSourceDestroy(vlc_media_source_t *ms)
> > +{
> > +    media_source_private_t *priv = ms_priv(ms);
> > +    Remove(priv->owner, ms);
> > +    vlc_sd_Destroy(priv->sd);
> > +    vlc_media_tree_Release(ms->tree);
> > +    free(priv);
> > +}
> > +
> > +void vlc_media_source_Hold(vlc_media_source_t *ms)
> > +{
> > +    media_source_private_t *priv = ms_priv(ms);
> > +    vlc_atomic_rc_inc(&priv->rc);
> > +}
> > +
> > +void vlc_media_source_Release(vlc_media_source_t *ms)
> > +{
> > +    media_source_private_t *priv = ms_priv(ms);
> > +    if (vlc_atomic_rc_dec(&priv->rc))
> > +        MediaSourceDestroy(ms);
> > +}
> > +
> > +static vlc_media_source_t *FindByName(media_source_provider_private_t 
> > *priv, const char *name)
> > +{
> > +    vlc_assert_locked(&priv->lock);
> > +    media_source_private_t *entry;
> > +    vlc_list_foreach(entry, &priv->media_sources, siblings)
> > +        if (!strcmp(name, entry->name))
> > +            return &entry->public_data;
> > +    return NULL;
> > +}
> > +
> > +vlc_media_source_provider_t *vlc_media_source_provider_Get(libvlc_int_t 
> > *libvlc)
> > +{
> > +    return libvlc_priv(libvlc)->media_source_provider;
> > +}
> > +
> > +vlc_media_source_provider_t 
> > *vlc_media_source_provider_Create(vlc_object_t *parent)
> > +{
> > +    media_source_provider_private_t *priv = vlc_custom_create(parent, 
> > sizeof(*priv), "media-source-provider");
> > +    if (unlikely(!priv))
> > +        return NULL;
> > +
> > +    vlc_mutex_init(&priv->lock);
> > +    vlc_list_init(&priv->media_sources);
> > +    return &priv->public_data;
> > +}
> > +
> > +void vlc_media_source_provider_Destroy(vlc_media_source_provider_t 
> > *msp)
> > +{
> > +    media_source_provider_private_t *priv = msp_priv(msp);
> > +
> > +    vlc_mutex_destroy(&priv->lock);
> > +    vlc_object_release(msp);
> > +}
> > +
> > +static vlc_media_source_t 
> > *AddServiceDiscovery(vlc_media_source_provider_t *msp, const char *name)
> > +{
> > +    AssertLocked(msp);
> > +
> > +    vlc_media_source_t *ms = MediaSourceCreate(msp, name);
> > +    if (unlikely(!ms))
> > +        return NULL;
> > +
> > +    media_source_provider_private_t *priv = msp_priv(msp);
> > +
> > +    vlc_list_append(&ms_priv(ms)->siblings, &priv->media_sources);
> > +    return ms;
> > +}
> > +
> > +vlc_media_source_t 
> > *vlc_media_source_provider_GetMediaSource(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);
> > +    if (!ms)
> > +        ms = AddServiceDiscovery(msp, name);
> > +    vlc_mutex_unlock(&priv->lock);
> > +
> > +    return ms;
> > +}
> > +
> > +static void Remove(vlc_media_source_provider_t *msp, vlc_media_source_t 
> > *ms)
> > +{
> > +    media_source_provider_private_t *priv = msp_priv(msp);
> > +
> > +    vlc_mutex_lock(&priv->lock);
> > +    vlc_list_remove(&ms_priv(ms)->siblings);
> > +    vlc_mutex_unlock(&priv->lock);
> > +}
> > diff --git a/src/media_source/media_source.h b/src/media_source/
> > media_source.h
> > new file mode 100644
> > index 00000000000..4a4672a7be0
> > --- /dev/null
> > +++ b/src/media_source/media_source.h
> > @@ -0,0 +1,29 @@
> > +/
> > *****************************************************************************
> > + * media_source.h : Media source
> > + 
> > *****************************************************************************
> > + * Copyright (C) 2018 VLC authors and VideoLAN
> > + *
> > + * This program is free software; you can redistribute it and/or modify 
> > it
> > + * under the terms of the GNU Lesser General Public License as 
> > published by
> > + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser 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.
> > + 
> > *****************************************************************************/
> > +
> > +#ifndef _MEDIA_SOURCE_H
> > +#define _MEDIA_SOURCE_H
> 
> This is a reserved identifier (and so is _MEDIA_TREE_H)

OK, I rename them to MEDIA_SOURCE_H and MEDIA_TREE_H.

> > +
> > +#include <vlc_media_source.h>
> > +
> > +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 *);
> > +
> > +#endif
> > diff --git a/src/media_tree/media_tree.c b/src/media_tree/media_tree.c
> > new file mode 100644
> > index 00000000000..dec2418efa6
> > --- /dev/null
> > +++ b/src/media_tree/media_tree.c
> > @@ -0,0 +1,261 @@
> > +/
> > *****************************************************************************
> > + * media_tree.c : Media tree
> > + 
> > *****************************************************************************
> > + * Copyright (C) 2018 VLC authors and VideoLAN
> > + *
> > + * This program is free software; you can redistribute it and/or modify 
> > it
> > + * under the terms of the GNU Lesser General Public License as 
> > published by
> > + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser 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.
> > + 
> > *****************************************************************************/
> > +
> 
> This is most likely missing an include to config.h

Thanks, I added it.

> > +#include "media_tree.h"
> > +
> > +#include <assert.h>
> > +#include <vlc_common.h>
> > +#include <vlc_arrays.h>
> > +#include <vlc_atomic.h>
> > +#include <vlc_input_item.h>
> > +#include <vlc_threads.h>
> > +#include "libvlc.h"
> > +
> > +TYPEDEF_ARRAY(vlc_media_tree_listener_t *, listener_array_t)
> > +
> > +typedef struct
> > +{
> > +    vlc_media_tree_t public_data;
> > +
> > +    listener_array_t listeners;
> > +    vlc_mutex_t lock;
> > +    vlc_atomic_rc_t rc;
> > +} media_tree_private_t;
> > +
> > +#define mt_priv(mt) container_of(mt, media_tree_private_t, 
> > public_data);
> > +
> > +vlc_media_tree_t *vlc_media_tree_Create(void)
> > +{
> > +    media_tree_private_t *priv = malloc(sizeof(*priv));
> > +    if (unlikely(!priv))
> > +        return NULL;
> > +
> > +    vlc_mutex_init(&priv->lock);
> > +    vlc_atomic_rc_init(&priv->rc);
> > +    ARRAY_INIT(priv->listeners);
> > +
> > +    vlc_media_tree_t *tree = &priv->public_data;
> > +    input_item_node_t *root = &tree->root;
> > +    root->p_item = NULL;
> > +    TAB_INIT(root->i_children, root->pp_children);
> > +
> > +    return tree;
> > +}
> > +
> > +static inline void AssertLocked(vlc_media_tree_t *tree)
> > +{
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    vlc_assert_locked(&priv->lock);
> > +}
> > +
> > +static void NotifyListenerAdded(vlc_media_tree_t *tree)
> > +{
> > +    AssertLocked(tree);
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +
> > +    FOREACH_ARRAY(vlc_media_tree_listener_t *listener, priv->listeners)
> > +        if (listener->cbs->listener_added)
> > +            listener->cbs->listener_added(tree, listener->userdata);
> > +    FOREACH_END();
> > +}
> > +
> > +static void NotifyNodeAdded(vlc_media_tree_t *tree, const 
> > input_item_node_t *parent,
> > +                            const input_item_node_t *node)
> > +{
> > +    AssertLocked(tree);
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +
> > +    FOREACH_ARRAY(vlc_media_tree_listener_t *listener, priv->listeners)
> > +        if (listener->cbs->node_added)
> > +            listener->cbs->node_added(tree, parent, node, listener-
> > >userdata);
> > +    FOREACH_END();
> > +}
> > +
> > +static void NotifyNodeRemoved(vlc_media_tree_t *tree, const 
> > input_item_node_t *parent,
> > +                              const input_item_node_t *node)
> > +{
> > +    AssertLocked(tree);
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +
> > +    FOREACH_ARRAY(vlc_media_tree_listener_t *listener, priv->listeners)
> > +        if (listener->cbs->node_removed)
> > +            listener->cbs->node_removed(tree, parent, node, listener-
> > >userdata);
> > +    FOREACH_END();
> > +}
> > +
> > +static bool FindNodeByInput(input_item_node_t *parent, const 
> > input_item_t *input,
> > +                            input_item_node_t **result, 
> > input_item_node_t **result_parent)
> > +{
> > +    for (int i = 0; i < parent->i_children; ++i)
> > +    {
> > +        input_item_node_t *p_child = parent->pp_children[i];
> > +        if (p_child->p_item == input)
> > +        {
> > +            *result = p_child;
> > +            if (result_parent)
> > +                *result_parent = parent;
> > +            return true;
> > +        }
> > +
> > +        if (FindNodeByInput(p_child, input, result, result_parent))
> > +            return true;
> > +    }
> > +
> > +    return false;
> > +}
> > +
> > +static void DestroyRootNode(vlc_media_tree_t *tree)
> > +{
> > +    input_item_node_t *root = &tree->root;
> > +    for (int i = 0; i < root->i_children; ++i)
> > +        input_item_node_Delete(root->pp_children[i]);
> > +
> > +    free(root->pp_children);
> > +}
> > +
> > +static void Destroy(vlc_media_tree_t *tree)
> > +{
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    ARRAY_RESET(priv->listeners);
> > +    DestroyRootNode(tree);
> > +    vlc_mutex_destroy(&priv->lock);
> > +    free(tree);
> > +}
> > +
> > +void vlc_media_tree_Hold(vlc_media_tree_t *tree)
> > +{
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    vlc_atomic_rc_inc(&priv->rc);
> > +}
> > +
> > +void vlc_media_tree_Release(vlc_media_tree_t *tree)
> > +{
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    if (vlc_atomic_rc_dec(&priv->rc))
> > +        Destroy(tree);
> > +}
> > +
> > +void vlc_media_tree_Lock(vlc_media_tree_t *tree)
> > +{
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    vlc_mutex_lock(&priv->lock);
> > +}
> > +
> > +void vlc_media_tree_Unlock(vlc_media_tree_t *tree)
> > +{
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    vlc_mutex_unlock(&priv->lock);
> > +}
> > +
> > +static input_item_node_t *AddChild(input_item_node_t *parent, 
> > input_item_t *input)
> > +{
> > +    input_item_node_t *node = input_item_node_Create(input);
> > +    if (unlikely(!node))
> > +        return NULL;
> > +
> > +    input_item_node_AppendNode(parent, node);
> > +
> > +    return node;
> > +}
> > +
> > +static void NotifyChildren(vlc_media_tree_t *tree, const 
> > input_item_node_t *node,
> > +                           const vlc_media_tree_listener_t *listener)
> > +{
> > +    AssertLocked(tree);
> > +    for (int i = 0; i < node->i_children; ++i)
> > +    {
> > +        input_item_node_t *p_child = node->pp_children[i];
> > +        listener->cbs->node_added(tree, node, p_child, listener-
> > >userdata);
> > +        NotifyChildren(tree, p_child, listener);
> > +    }
> > +}
> > +
> > +void vlc_media_tree_listener_added_default(vlc_media_tree_t *tree, void 
> > *userdata)
> > +{
> > +    VLC_UNUSED(userdata);
> > +    AssertLocked(tree);
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    FOREACH_ARRAY(vlc_media_tree_listener_t *listener, priv->listeners)
> > +        /* notify "node added" for every node */
> > +        if (listener->cbs->node_added)
> > +            NotifyChildren(tree, &tree->root, listener);
> > +    FOREACH_END();
> > +}
> > +
> > +void vlc_media_tree_AddListener(vlc_media_tree_t *tree, 
> > vlc_media_tree_listener_t *listener)
> > +{
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    vlc_media_tree_Lock(tree);
> > +    ARRAY_APPEND(priv->listeners, listener);
> > +    NotifyListenerAdded(tree);
> > +    vlc_media_tree_Unlock(tree);
> > +}
> > +
> > +void vlc_media_tree_RemoveListener(vlc_media_tree_t *tree, 
> > vlc_media_tree_listener_t *listener)
> > +{
> > +    media_tree_private_t *priv = mt_priv(tree);
> > +    vlc_media_tree_Lock(tree);
> > +    for (int i = 0; i < priv->listeners.i_size; ++i)
> > +    {
> > +        if (ARRAY_VAL(priv->listeners, i) == listener)
> > +        {
> > +            ARRAY_REMOVE(priv->listeners, i);
> > +            break;
> > +        }
> > +    }
> > +    vlc_media_tree_Unlock(tree);
> > +}
> > +
> > +input_item_node_t *vlc_media_tree_Add(vlc_media_tree_t *tree, 
> > input_item_node_t *parent, input_item_t *input)
> > +{
> > +    AssertLocked(tree);
> > +
> > +    input_item_node_t *node = AddChild(parent, input);
> > +    if (unlikely(!node))
> > +        return NULL;
> > +
> > +    NotifyNodeAdded(tree, parent, node);
> > +
> > +    return node;
> > +}
> > +
> > +bool vlc_media_tree_Find(vlc_media_tree_t *tree, const input_item_t 
> > *input,
> > +                         input_item_node_t **result, input_item_node_t 
> > **result_parent)
> > +{
> > +    AssertLocked(tree);
> > +
> > +    /* quick & dirty depth-first O(n) implementation, with n the number 
> > of nodes in the tree */
> > +    return FindNodeByInput(&tree->root, input, result, result_parent);
> > +}
> > +
> > +bool vlc_media_tree_Remove(vlc_media_tree_t *tree, input_item_t *input)
> > +{
> > +    AssertLocked(tree);
> > +
> > +    input_item_node_t *node;
> > +    input_item_node_t *parent;
> > +    if (!FindNodeByInput(&tree->root, input, &node, &parent))
> > +        return false;
> > +
> > +    input_item_node_RemoveNode(parent, node);
> > +    NotifyNodeRemoved(tree, parent, node);
> > +    input_item_node_Delete(node);
> > +    return true;
> > +}
> > diff --git a/src/media_tree/media_tree.h b/src/media_tree/media_tree.h
> > new file mode 100644
> > index 00000000000..bda25f58910
> > --- /dev/null
> > +++ b/src/media_tree/media_tree.h
> > @@ -0,0 +1,34 @@
> > +/
> > *****************************************************************************
> > + * media_tree.h : Media tree
> > + 
> > *****************************************************************************
> > + * Copyright (C) 2018 VLC authors and VideoLAN
> > + *
> > + * This program is free software; you can redistribute it and/or modify 
> > it
> > + * under the terms of the GNU Lesser General Public License as 
> > published by
> > + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser 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.
> > + 
> > *****************************************************************************/
> > +
> > +#ifndef _MEDIA_TREE_H
> > +#define _MEDIA_TREE_H
> > +
> > +#include <vlc_media_tree.h>
> > +
> > +vlc_media_tree_t *vlc_media_tree_Create(void);
> > +
> > +void vlc_media_tree_Hold(vlc_media_tree_t *);
> > +void vlc_media_tree_Release(vlc_media_tree_t *);
> > +
> > +input_item_node_t *vlc_media_tree_Add(vlc_media_tree_t *, 
> > input_item_node_t *parent, input_item_t *);
> > +bool vlc_media_tree_Remove(vlc_media_tree_t *, input_item_t *input);
> > +
> > +#endif
> > -- 
> > 2.18.0
> > 
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> 
> 
> -- 
>   Hugo Beauzée-Luyssen
>   hugo at beauzee.fr



More information about the vlc-devel mailing list