[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