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

Hugo Beauzée-Luyssen hugo at beauzee.fr
Mon Jul 9 16:54:04 CEST 2018



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

> +#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'

> +        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?

> +
> +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)

> +
> +#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

> +#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