[vlc-devel] [PATCH v4 2/3] Update media tree on browsing/preparsing

Romain Vimont rom1v at videolabs.io
Mon Jul 9 12:13:53 CEST 2018


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? */
+
+        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



More information about the vlc-devel mailing list