[vlc-devel] [PATCH v4 2/3] Update media tree on browsing/preparsing
Steve Lhomme
robux4 at ycbcr.xyz
Mon Jul 9 15:26:17 CEST 2018
On 2018-07-09 14:38, Romain Vimont wrote:
> 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.)
Not much you can do. Just return so the NULL pointer is not used. If
you're that short in memory you'll end up getting other malloc issues
elsewhere.
>> +
>> + 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
> _______________________________________________
> 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