[vlc-devel] [PATCH v4 2/3] Update media tree on browsing/preparsing
Romain Vimont
rom1v at videolabs.io
Mon Jul 9 14:38:51 CEST 2018
On Mon, Jul 09, 2018 at 12:13:53PM +0200, Romain Vimont wrote:
> Browsing and preparsing, started by libvlc_MetadataRequest(), trigger
> input item events.
>
> Listen to these events to update the media tree accordingly.
> ---
> include/vlc_media_tree.h | 19 ++++++
> src/libvlccore.sym | 1 +
> src/media_tree/media_tree.c | 124 ++++++++++++++++++++++++++++++++++--
> 3 files changed, 138 insertions(+), 6 deletions(-)
>
> diff --git a/include/vlc_media_tree.h b/include/vlc_media_tree.h
> index b9d2c6f194b..2c9097480ba 100644
> --- a/include/vlc_media_tree.h
> +++ b/include/vlc_media_tree.h
> @@ -57,6 +57,14 @@ typedef struct vlc_media_tree_callbacks_t
> */
> void (*listener_added)(vlc_media_tree_t *, void *userdata);
>
> + /**
> + * Called when an input item notifies that a subtree has been added.
> + *
> + * Use vlc_media_tree_subtree_added_default implementation to call
> + * node_added() for every new node.
> + */
> + void (*subtree_added)(vlc_media_tree_t *, const input_item_node_t *, void *userdata);
> +
> /**
> * Called after a new node has been added to the media tree, with lock held.
> */
> @@ -68,6 +76,11 @@ typedef struct vlc_media_tree_callbacks_t
> */
> void (*node_removed)(vlc_media_tree_t *, const input_item_node_t *parent,
> const input_item_node_t *, void *userdata);
> +
> + /**
> + * Called when an input item notifies that it has been updated.
> + */
> + void (*input_updated)(vlc_media_tree_t *, const input_item_node_t *, void *userdata);
> } vlc_media_tree_callbacks_t;
>
> /**
> @@ -85,6 +98,12 @@ typedef struct vlc_media_tree_listener_t
> **/
> VLC_API void vlc_media_tree_listener_added_default(vlc_media_tree_t *, void *userdata);
>
> +/**
> + * Default implementation for subtree_added(), which calls node_added()
> + * for every new node.
> + **/
> +VLC_API void vlc_media_tree_subtree_added_default(vlc_media_tree_t *, const input_item_node_t *, void *userdata);
> +
> /**
> * Add listener. The lock must NOT be held.
> */
> diff --git a/src/libvlccore.sym b/src/libvlccore.sym
> index fd2d4bbe69c..802dcaee08f 100644
> --- a/src/libvlccore.sym
> +++ b/src/libvlccore.sym
> @@ -765,3 +765,4 @@ vlc_media_tree_Lock
> vlc_media_tree_Unlock
> vlc_media_tree_Find
> vlc_media_tree_listener_added_default
> +vlc_media_tree_subtree_added_default
> diff --git a/src/media_tree/media_tree.c b/src/media_tree/media_tree.c
> index dec2418efa6..316bc794adb 100644
> --- a/src/media_tree/media_tree.c
> +++ b/src/media_tree/media_tree.c
> @@ -100,6 +100,28 @@ static void NotifyNodeRemoved(vlc_media_tree_t *tree, const input_item_node_t *p
> FOREACH_END();
> }
>
> +static void NotifySubtreeAdded(vlc_media_tree_t *tree, 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->subtree_added)
> + listener->cbs->subtree_added(tree, node, listener->userdata);
> + FOREACH_END();
> +}
> +
> +static void NotifyInputChanged(vlc_media_tree_t *tree, 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->input_updated)
> + listener->cbs->input_updated(tree, 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)
> {
> @@ -121,11 +143,95 @@ static bool FindNodeByInput(input_item_node_t *parent, const input_item_t *input
> return false;
> }
>
> +static input_item_node_t *AddChild(vlc_media_tree_t *tree, input_item_node_t *parent, input_item_t *input);
> +
> +static void AddSubtree(vlc_media_tree_t *tree, input_item_node_t *p_to, input_item_node_t *p_from)
> +{
> + for(int i = 0; i < p_from->i_children; ++i)
> + {
> + input_item_node_t *p_child = p_from->pp_children[i];
> + input_item_node_t *node = AddChild(tree, p_to, p_child->p_item);
> + if (unlikely(!node))
> + abort(); /* what could we do? */
Just to highlight: this is wrong, but what should we do instead if the
malloc fails?
This function is called by the callback input_item_subtree_added().
(Also, since vlc_media_tree_t is not a vlc_object_t, we cannot easily
log.)
> +
> + AddSubtree(tree, node, p_child);
> + }
> +}
> +
> +static void input_item_subtree_added(const vlc_event_t *p_event, void *userdata)
> +{
> + vlc_media_tree_t *tree = userdata;
> + input_item_t *input = p_event->p_obj;
> +
> + vlc_media_tree_Lock(tree);
> + input_item_node_t *p_subtree_root;
> + // TODO retrieve the node without traversing the tree
> + bool found = FindNodeByInput(&tree->root, input, &p_subtree_root, NULL);
> + assert(found);
> + VLC_UNUSED(found);
> +
> + input_item_node_t *p_from = p_event->u.input_item_subitem_tree_added.p_root;
> + AddSubtree(tree, p_subtree_root, p_from);
> + NotifySubtreeAdded(tree, p_subtree_root);
> + vlc_media_tree_Unlock(tree);
> +}
> +
> +static void input_item_changed(const vlc_event_t *p_event, void *userdata)
> +{
> + vlc_media_tree_t *tree = userdata;
> + input_item_t *input = p_event->p_obj;
> +
> + vlc_media_tree_Lock(tree);
> + input_item_node_t *node;
> + // TODO retrieve the node without traversing the tree
> + bool found = FindNodeByInput(&tree->root, input, &node, NULL);
> + assert(found);
> + VLC_UNUSED(found);
> +
> + NotifyInputChanged(tree, node);
> + vlc_media_tree_Unlock(tree);
> +}
> +
> +static void RegisterInputEvents(vlc_media_tree_t *tree, input_item_t *input)
> +{
> + vlc_event_manager_t *p_em = &input->event_manager;
> + vlc_event_attach(p_em, vlc_InputItemSubItemTreeAdded, input_item_subtree_added, tree);
> + vlc_event_attach(p_em, vlc_InputItemDurationChanged, input_item_changed, tree);
> + vlc_event_attach(p_em, vlc_InputItemMetaChanged, input_item_changed, tree);
> + vlc_event_attach(p_em, vlc_InputItemNameChanged, input_item_changed, tree);
> + vlc_event_attach(p_em, vlc_InputItemInfoChanged, input_item_changed, tree);
> + vlc_event_attach(p_em, vlc_InputItemErrorWhenReadingChanged, input_item_changed, tree);
> +}
> +
> +static void DeregisterInputEvents(vlc_media_tree_t *tree, input_item_t *input)
> +{
> + vlc_event_manager_t *p_em = &input->event_manager;
> + vlc_event_detach(p_em, vlc_InputItemSubItemTreeAdded, input_item_subtree_added, tree);
> + vlc_event_detach(p_em, vlc_InputItemDurationChanged, input_item_changed, tree);
> + vlc_event_detach(p_em, vlc_InputItemMetaChanged, input_item_changed, tree);
> + vlc_event_detach(p_em, vlc_InputItemNameChanged, input_item_changed, tree);
> + vlc_event_detach(p_em, vlc_InputItemInfoChanged, input_item_changed, tree);
> + vlc_event_detach(p_em, vlc_InputItemErrorWhenReadingChanged, input_item_changed, tree);
> +}
> +
> +/* same as input_item_node_Delete(), but also deregister input events for every node */
> +static void DestroyNode(vlc_media_tree_t *tree, input_item_node_t *node)
> +{
> + DeregisterInputEvents(tree, node->p_item);
> +
> + for (int i = 0; i < node->i_children; ++i)
> + DestroyNode(tree, node->pp_children[i]);
> +
> + input_item_Release(node->p_item);
> + free(node->pp_children);
> + free(node);
> +}
> +
> 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]);
> + DestroyNode(tree, root->pp_children[i]);
>
> free(root->pp_children);
> }
> @@ -164,13 +270,14 @@ void vlc_media_tree_Unlock(vlc_media_tree_t *tree)
> vlc_mutex_unlock(&priv->lock);
> }
>
> -static input_item_node_t *AddChild(input_item_node_t *parent, input_item_t *input)
> +static input_item_node_t *AddChild(vlc_media_tree_t *tree, 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);
> + RegisterInputEvents(tree, input);
>
> return node;
> }
> @@ -187,7 +294,7 @@ static void NotifyChildren(vlc_media_tree_t *tree, const input_item_node_t *node
> }
> }
>
> -void vlc_media_tree_listener_added_default(vlc_media_tree_t *tree, void *userdata)
> +void vlc_media_tree_subtree_added_default(vlc_media_tree_t *tree, const input_item_node_t *node, void *userdata)
> {
> VLC_UNUSED(userdata);
> AssertLocked(tree);
> @@ -195,10 +302,15 @@ void vlc_media_tree_listener_added_default(vlc_media_tree_t *tree, void *userdat
> 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);
> + NotifyChildren(tree, node, listener);
> FOREACH_END();
> }
>
> +void vlc_media_tree_listener_added_default(vlc_media_tree_t *tree, void *userdata)
> +{
> + vlc_media_tree_subtree_added_default(tree, &tree->root, userdata);
> +}
> +
> void vlc_media_tree_AddListener(vlc_media_tree_t *tree, vlc_media_tree_listener_t *listener)
> {
> media_tree_private_t *priv = mt_priv(tree);
> @@ -227,7 +339,7 @@ input_item_node_t *vlc_media_tree_Add(vlc_media_tree_t *tree, input_item_node_t
> {
> AssertLocked(tree);
>
> - input_item_node_t *node = AddChild(parent, input);
> + input_item_node_t *node = AddChild(tree, parent, input);
> if (unlikely(!node))
> return NULL;
>
> @@ -256,6 +368,6 @@ bool vlc_media_tree_Remove(vlc_media_tree_t *tree, input_item_t *input)
>
> input_item_node_RemoveNode(parent, node);
> NotifyNodeRemoved(tree, parent, node);
> - input_item_node_Delete(node);
> + DestroyNode(tree, node);
> return true;
> }
> --
> 2.18.0
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list