[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