[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