[vlc-devel] [PATCH v3 2/3] Update media tree on browsing/preparsing
Romain Vimont
rom1v at videolabs.io
Thu Jun 28 10:55:31 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 | 122 ++++++++++++++++++++++++++++++++++--
3 files changed, 136 insertions(+), 6 deletions(-)
diff --git a/include/vlc_media_tree.h b/include/vlc_media_tree.h
index b265060abb5..e9a490ad177 100644
--- a/include/vlc_media_tree.h
+++ b/include/vlc_media_tree.h
@@ -56,6 +56,14 @@ typedef struct vlc_media_tree_callbacks_t
*/
void ( *pf_tree_connected )( 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
+ * pf_node_added() for every new node.
+ */
+ void ( *pf_subtree_added )( vlc_media_tree_t *, const input_item_node_t *, void *userdata );
+
/**
* Called when a new node is added to the media tree, with lock held.
*/
@@ -67,6 +75,11 @@ typedef struct vlc_media_tree_callbacks_t
*/
void ( *pf_node_removed )( vlc_media_tree_t *, const input_item_node_t *p_parent,
const input_item_node_t *, void *userdata );
+
+ /**
+ * Called when an input item is updated.
+ */
+ void ( *pf_input_updated )( vlc_media_tree_t *, const input_item_node_t *, void *userdata );
} vlc_media_tree_callbacks_t;
/**
@@ -75,6 +88,12 @@ typedef struct vlc_media_tree_callbacks_t
**/
VLC_API void vlc_media_tree_connected_default( vlc_media_tree_t *, void *userdata );
+/**
+ * Default implementation for pf_subtree_added(), which calls pf_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 );
+
/**
* Increase the media tree reference count.
*/
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 0a658ef22b2..934ba29ef61 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -764,3 +764,4 @@ vlc_media_tree_Lock
vlc_media_tree_Unlock
vlc_media_tree_Find
vlc_media_tree_connected_default
+vlc_media_tree_subtree_added_default
diff --git a/src/media_tree/media_tree.c b/src/media_tree/media_tree.c
index 3cedddb8085..e9b8e3da662 100644
--- a/src/media_tree/media_tree.c
+++ b/src/media_tree/media_tree.c
@@ -101,6 +101,26 @@ static void NotifyNodeRemoved( vlc_media_tree_t *p_tree, const input_item_node_t
p_conn->cbs->pf_node_removed( p_tree, p_parent, p_node, p_conn->userdata );
}
+static void NotifySubtreeAdded( vlc_media_tree_t *p_tree, const input_item_node_t *p_node )
+{
+ AssertLocked( p_tree );
+ media_tree_private_t *p_priv = mt_priv( p_tree );
+ vlc_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( vlc_media_tree_t *p_tree, const input_item_node_t *p_node )
+{
+ AssertLocked( p_tree );
+ media_tree_private_t *p_priv = mt_priv( p_tree );
+ vlc_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 bool FindNodeByInput( input_item_node_t *p_parent, const input_item_t *p_input,
input_item_node_t **pp_result, input_item_node_t **pp_result_parent )
{
@@ -122,11 +142,95 @@ static bool FindNodeByInput( input_item_node_t *p_parent, const input_item_t *p_
return false;
}
+static input_item_node_t *AddChild( vlc_media_tree_t *p_tree, input_item_node_t *p_parent, input_item_t *p_input );
+
+static void AddSubtree( vlc_media_tree_t *p_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 *p_node = AddChild( p_tree, p_to, p_child->p_item );
+ if( unlikely( !p_node ) )
+ abort(); /* what could we do? */
+
+ AddSubtree( p_tree, p_node, p_child );
+ }
+}
+
+static void input_item_subtree_added( const vlc_event_t *p_event, void *userdata )
+{
+ vlc_media_tree_t *p_tree = userdata;
+ input_item_t *p_input = p_event->p_obj;
+
+ vlc_media_tree_Lock( p_tree );
+ input_item_node_t *p_subtree_root;
+ // TODO retrieve the node without traversing the tree
+ bool found = FindNodeByInput( &p_tree->root, p_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( p_tree, p_subtree_root, p_from );
+ NotifySubtreeAdded( p_tree, p_subtree_root );
+ vlc_media_tree_Unlock( p_tree );
+}
+
+static void input_item_changed( const vlc_event_t *p_event, void *userdata )
+{
+ vlc_media_tree_t *p_tree = userdata;
+ input_item_t *p_input = p_event->p_obj;
+
+ vlc_media_tree_Lock( p_tree );
+ input_item_node_t *p_node;
+ // TODO retrieve the node without traversing the tree
+ bool found = FindNodeByInput( &p_tree->root, p_input, &p_node, NULL );
+ assert( found );
+ VLC_UNUSED( found );
+
+ NotifyInputChanged( p_tree, p_node );
+ vlc_media_tree_Unlock( p_tree );
+}
+
+static void RegisterInputEvents( vlc_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( vlc_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 );
+}
+
+/* same as input_item_node_Delete(), but also deregister input events for every node */
+static void DestroyNode( vlc_media_tree_t *p_tree, input_item_node_t *p_node )
+{
+ DeregisterInputEvents( p_tree, p_node->p_item );
+
+ for( int i = 0; i < p_node->i_children; ++i )
+ DestroyNode( p_tree, p_node->pp_children[i] );
+
+ input_item_Release( p_node->p_item );
+ free( p_node->pp_children );
+ free( p_node );
+}
+
static void DestroyRootNode( vlc_media_tree_t *p_tree )
{
input_item_node_t *p_root = &p_tree->root;
for( int i = 0; i < p_root->i_children; ++i )
- input_item_node_Delete( p_root->pp_children[i] );
+ DestroyNode( p_tree, p_root->pp_children[i] );
free( p_root->pp_children );
}
@@ -168,13 +272,14 @@ void vlc_media_tree_Unlock( vlc_media_tree_t *p_tree )
vlc_mutex_unlock( &p_priv->lock );
}
-static input_item_node_t *AddChild( input_item_node_t *p_parent, input_item_t *p_input )
+static input_item_node_t *AddChild( vlc_media_tree_t *p_tree, input_item_node_t *p_parent, input_item_t *p_input )
{
input_item_node_t *p_node = input_item_node_Create( p_input );
if( unlikely( !p_node ) )
return NULL;
input_item_node_AppendNode( p_parent, p_node );
+ RegisterInputEvents( p_tree, p_input );
return p_node;
}
@@ -191,7 +296,7 @@ static void NotifyChildren( vlc_media_tree_t *p_tree, const input_item_node_t *p
}
}
-void vlc_media_tree_connected_default( vlc_media_tree_t *p_tree, void *userdata )
+void vlc_media_tree_subtree_added_default( vlc_media_tree_t *p_tree, const input_item_node_t *p_node, void *userdata )
{
VLC_UNUSED( userdata );
AssertLocked( p_tree );
@@ -202,10 +307,15 @@ void vlc_media_tree_connected_default( vlc_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->root, p_conn );
+ NotifyChildren( p_tree, p_node, p_conn );
}
}
+void vlc_media_tree_connected_default( vlc_media_tree_t *p_tree, void *userdata )
+{
+ vlc_media_tree_subtree_added_default( p_tree, &p_tree->root, userdata );
+}
+
vlc_media_tree_connection_t *vlc_media_tree_Connect( vlc_media_tree_t *p_tree, const vlc_media_tree_callbacks_t *p_callbacks, void *userdata )
{
vlc_media_tree_connection_t *p_conn = malloc( sizeof( *p_conn ) );
@@ -238,7 +348,7 @@ input_item_node_t *vlc_media_tree_Add( vlc_media_tree_t *p_tree,
{
AssertLocked( p_tree );
- input_item_node_t *p_node = AddChild( p_parent, p_input );
+ input_item_node_t *p_node = AddChild( p_tree, p_parent, p_input );
if( unlikely( !p_node ) )
return NULL;
@@ -267,6 +377,6 @@ bool vlc_media_tree_Remove( vlc_media_tree_t *p_tree, input_item_t *p_input )
input_item_node_RemoveNode( p_parent, p_node );
NotifyNodeRemoved( p_tree, p_parent, p_node );
- input_item_node_Delete( p_node );
+ DestroyNode( p_tree, p_node );
return true;
}
--
2.18.0
More information about the vlc-devel
mailing list