[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