[vlc-devel] [PATCH 2/3] Update media tree on browsing/preparsing
Romain Vimont
rom1v at videolabs.io
Tue Jun 19 19:00:16 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 | 130 ++++++++++++++++++++++++++++++++----
3 files changed, 138 insertions(+), 12 deletions(-)
diff --git a/include/vlc_media_tree.h b/include/vlc_media_tree.h
index aaf877e82f8..4dc3311799a 100644
--- a/include/vlc_media_tree.h
+++ b/include/vlc_media_tree.h
@@ -72,6 +72,14 @@ typedef struct media_tree_callbacks_t
*/
void ( *pf_tree_connected )( media_tree_t *, void *userdata );
+ /**
+ * Called when an input item notifies that a subtree has been added.
+ *
+ * Use media_tree_subtree_added_default implementation to call
+ * pf_node_added() for every new node.
+ */
+ void ( *pf_subtree_added )( media_tree_t *, const media_node_t *, void *userdata );
+
/**
* Called when a new node is added to the media tree, with lock held.
*/
@@ -81,6 +89,11 @@ typedef struct media_tree_callbacks_t
* Called when a node is removed from the media tree, with lock held.
*/
void ( *pf_node_removed )( media_tree_t *, const media_node_t *, void *userdata );
+
+ /**
+ * Called when an input item is updated.
+ */
+ void ( *pf_input_updated )( media_tree_t *, const media_node_t *, void *userdata );
} media_tree_callbacks_t;
/**
@@ -89,6 +102,12 @@ typedef struct media_tree_callbacks_t
**/
VLC_API void media_tree_connected_default( media_tree_t *, void *userdata );
+/**
+ * Default implementation for pf_subtree_added(), which calls pf_node_added()
+ * for every new node.
+ **/
+VLC_API void media_tree_subtree_added_default( media_tree_t *, const media_node_t *, void *userdata );
+
/**
* Increase the media tree reference count.
*/
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index dc23e5f0d6e..0985afd26bd 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -764,3 +764,4 @@ media_tree_Lock
media_tree_Unlock
media_tree_Find
media_tree_connected_default
+media_tree_subtree_added_default
diff --git a/src/media_tree/media_tree.c b/src/media_tree/media_tree.c
index 48ac7695565..6ebf93231bf 100644
--- a/src/media_tree/media_tree.c
+++ b/src/media_tree/media_tree.c
@@ -100,6 +100,26 @@ static void NotifyNodeRemoved( media_tree_t *p_tree, media_node_t *p_node )
p_conn->cbs->pf_node_removed( p_tree, p_node, p_conn->userdata );
}
+static void NotifySubtreeAdded( media_tree_t *p_tree, media_node_t *p_node )
+{
+ AssertLocked( p_tree );
+ media_tree_private_t *p_priv = mt_priv( p_tree );
+ media_tree_connection_t *p_conn;
+ vlc_list_foreach( p_conn, &p_priv->connections, siblings )
+ if( p_conn->cbs->pf_subtree_added )
+ p_conn->cbs->pf_subtree_added( p_tree, p_node, p_conn->userdata );
+}
+
+static void NotifyInputChanged( media_tree_t *p_tree, media_node_t *p_node )
+{
+ AssertLocked( p_tree );
+ media_tree_private_t *p_priv = mt_priv( p_tree );
+ media_tree_connection_t *p_conn;
+ vlc_list_foreach( p_conn, &p_priv->connections, siblings )
+ if( p_conn->cbs->pf_input_updated )
+ p_conn->cbs->pf_input_updated( p_tree, p_node, p_conn->userdata );
+}
+
static media_node_t *FindNodeByInput( media_node_t *p_node, input_item_t *p_input )
{
if( p_node->p_input == p_input )
@@ -114,18 +134,98 @@ static media_node_t *FindNodeByInput( media_node_t *p_node, input_item_t *p_inpu
return NULL;
}
-static void DestroyNodeAndChildren( media_node_t * );
+static media_node_t *AddChild( media_tree_t *p_tree, input_item_t *p_input, media_node_t *p_parent, int i_pos );
+
+static void AddSubtree( media_tree_t *p_tree, media_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];
+ media_node_t *p_node = AddChild( p_tree, p_child->p_item, p_to, MEDIA_TREE_END );
+ if( unlikely( !p_node ) )
+ {
+ msg_Warn( p_tree, "Cannot create node");
+ continue;
+ }
+ AddSubtree( p_tree, p_node, p_child );
+ }
+}
+
+static void input_item_subtree_added( const vlc_event_t *p_event, void *userdata )
+{
+ media_tree_t *p_tree = userdata;
+ input_item_t *p_input = p_event->p_obj;
+ input_item_node_t *p_from = p_event->u.input_item_subitem_tree_added.p_root;
+
+ media_tree_Lock( p_tree );
+ // TODO retrieve the node without traversing the tree
+ media_node_t *p_subtree_root = FindNodeByInput( &p_tree->p_root, p_input );
+ if( unlikely( !p_subtree_root ) )
+ {
+ msg_Warn( p_tree, "Cannot find expected node for subtree");
+ media_tree_Unlock( p_tree );
+ return;
+ }
+
+ AddSubtree( p_tree, p_subtree_root, p_from );
+ NotifySubtreeAdded( p_tree, p_subtree_root );
+ media_tree_Unlock( p_tree );
+}
+
+static void input_item_changed( const vlc_event_t *p_event, void *userdata )
+{
+ media_tree_t *p_tree = userdata;
+ input_item_t *p_input = p_event->p_obj;
+
+ media_tree_Lock( p_tree );
+ // TODO retrieve the node without traversing the tree
+ media_node_t *p_node = FindNodeByInput( &p_tree->p_root, p_input );
+ if( unlikely( !p_node ) )
+ {
+ msg_Warn( p_tree, "Cannot find expected node");
+ media_tree_Unlock( p_tree );
+ return;
+ }
+
+ NotifyInputChanged( p_tree, p_node );
+ media_tree_Unlock( p_tree );
+}
-static void DestroyChildren( media_node_t *p_node )
+static void RegisterInputEvents( media_tree_t *p_tree, input_item_t *p_input )
+{
+ vlc_event_manager_t *p_em = &p_input->event_manager;
+ vlc_event_attach( p_em, vlc_InputItemSubItemTreeAdded, input_item_subtree_added, p_tree );
+ vlc_event_attach( p_em, vlc_InputItemDurationChanged, input_item_changed, p_tree );
+ vlc_event_attach( p_em, vlc_InputItemMetaChanged, input_item_changed, p_tree );
+ vlc_event_attach( p_em, vlc_InputItemNameChanged, input_item_changed, p_tree );
+ vlc_event_attach( p_em, vlc_InputItemInfoChanged, input_item_changed, p_tree );
+ vlc_event_attach( p_em, vlc_InputItemErrorWhenReadingChanged, input_item_changed, p_tree );
+}
+
+static void DeregisterInputEvents( media_tree_t *p_tree, input_item_t *p_input )
+{
+ vlc_event_manager_t *p_em = &p_input->event_manager;
+ vlc_event_detach( p_em, vlc_InputItemSubItemTreeAdded, input_item_subtree_added, p_tree );
+ vlc_event_detach( p_em, vlc_InputItemDurationChanged, input_item_changed, p_tree );
+ vlc_event_detach( p_em, vlc_InputItemMetaChanged, input_item_changed, p_tree );
+ vlc_event_detach( p_em, vlc_InputItemNameChanged, input_item_changed, p_tree );
+ vlc_event_detach( p_em, vlc_InputItemInfoChanged, input_item_changed, p_tree );
+ vlc_event_detach( p_em, vlc_InputItemErrorWhenReadingChanged, input_item_changed, p_tree );
+}
+
+static void DestroyNodeAndChildren( media_tree_t *, media_node_t * );
+
+static void DestroyChildren( media_tree_t *p_tree, media_node_t *p_node )
{
FOREACH_ARRAY( media_node_t *p_child, p_node->children )
- DestroyNodeAndChildren( p_child );
+ DestroyNodeAndChildren( p_tree, p_child );
FOREACH_END()
}
-static void DestroyNodeAndChildren( media_node_t *p_node )
+static void DestroyNodeAndChildren( media_tree_t *p_tree, media_node_t *p_node )
{
- DestroyChildren( p_node );
+ DestroyChildren( p_tree, p_node );
+ DeregisterInputEvents( p_tree, p_node->p_input );
input_item_Release( p_node->p_input );
free( p_node );
}
@@ -137,7 +237,7 @@ static void Destroy( media_tree_t *p_tree )
vlc_list_foreach( p_conn, &p_priv->connections, siblings )
free( p_conn );
vlc_list_init( &p_priv->connections ); /* reset */
- DestroyChildren( &p_tree->p_root );
+ DestroyChildren( p_tree, &p_tree->p_root );
vlc_mutex_destroy( &p_priv->lock );
vlc_object_release( p_tree );
}
@@ -175,7 +275,7 @@ static inline void AssertBelong( media_tree_t *p_tree, media_node_t *p_node )
#endif
}
-static media_node_t *AddChild( input_item_t *p_input, media_node_t *p_parent, int i_pos )
+static media_node_t *AddChild( media_tree_t *p_tree, input_item_t *p_input, media_node_t *p_parent, int i_pos )
{
media_node_t *p_node = malloc( sizeof( *p_node ) );
if( unlikely( !p_node ) )
@@ -190,6 +290,7 @@ static media_node_t *AddChild( input_item_t *p_input, media_node_t *p_parent, in
ARRAY_INSERT( p_parent->children, p_node, i_pos );
input_item_Hold( p_input );
+ RegisterInputEvents( p_tree, p_input );
return p_node;
}
@@ -206,7 +307,7 @@ static int FindNodeIndex( media_node_array_t *p_array, media_node_t *p_node )
return -1;
}
-static void NotifyChildren( media_tree_t *p_tree, media_node_t *p_node, const media_tree_connection_t *p_conn )
+static void NotifyChildren( media_tree_t *p_tree, const media_node_t *p_node, const media_tree_connection_t *p_conn )
{
AssertLocked( p_tree );
FOREACH_ARRAY( media_node_t *p_child, p_node->children )
@@ -215,7 +316,7 @@ static void NotifyChildren( media_tree_t *p_tree, media_node_t *p_node, const me
FOREACH_END()
}
-void media_tree_connected_default( media_tree_t *p_tree, void *userdata )
+void media_tree_subtree_added_default( media_tree_t *p_tree, const media_node_t *p_node, void *userdata )
{
VLC_UNUSED( userdata );
AssertLocked( p_tree );
@@ -226,10 +327,15 @@ void media_tree_connected_default( media_tree_t *p_tree, void *userdata )
if( !p_conn->cbs->pf_node_added)
break; /* nothing to do for this listener */
/* notify "node added" for every node */
- NotifyChildren( p_tree, &p_tree->p_root, p_conn );
+ NotifyChildren( p_tree, p_node, p_conn );
}
}
+void media_tree_connected_default( media_tree_t *p_tree, void *userdata )
+{
+ media_tree_subtree_added_default( p_tree, &p_tree->p_root, userdata );
+}
+
media_tree_connection_t *media_tree_Connect( media_tree_t *p_tree, const media_tree_callbacks_t *p_callbacks, void *userdata )
{
media_tree_connection_t *p_conn = malloc( sizeof( *p_conn ) );
@@ -263,7 +369,7 @@ media_node_t *media_tree_Add( media_tree_t *p_tree,
{
AssertLocked( p_tree );
- media_node_t *p_node = AddChild( p_input, p_parent, i_pos );
+ media_node_t *p_node = AddChild( p_tree, p_input, p_parent, i_pos );
if( unlikely( !p_node ) )
return NULL;
@@ -295,5 +401,5 @@ void media_tree_Remove( media_tree_t *p_tree, media_node_t *p_node )
NotifyNodeRemoved( p_tree, p_node );
- DestroyNodeAndChildren( p_node );
+ DestroyNodeAndChildren( p_tree, p_node );
}
--
2.18.0.rc2
More information about the vlc-devel
mailing list