[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