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

Romain Vimont rom1v at videolabs.io
Fri Jun 22 14:29:59 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 b34e4aa7a26..ae585200a75 100644
--- a/include/vlc_media_tree.h
+++ b/include/vlc_media_tree.h
@@ -56,6 +56,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 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 media_tree_callbacks_t
      */
     void ( *pf_node_removed )( 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 )( media_tree_t *, const input_item_node_t *, void *userdata );
 } media_tree_callbacks_t;
 
 /**
@@ -75,6 +88,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 input_item_node_t *, void *userdata );
+
 /**
  * Increase the media tree reference count.
  */
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index ab2b60145f1..a3c367b9ef1 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 900675dc949..dd3af3b71df 100644
--- a/src/media_tree/media_tree.c
+++ b/src/media_tree/media_tree.c
@@ -101,6 +101,26 @@ static void NotifyNodeRemoved( media_tree_t *p_tree, const input_item_node_t *p_
             p_conn->cbs->pf_node_removed( p_tree, p_parent, p_node, p_conn->userdata );
 }
 
+static void NotifySubtreeAdded( 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 );
+    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, const input_item_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 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( media_tree_t *p_tree, input_item_node_t *p_parent, input_item_t *p_input );
+
+static void AddSubtree( 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 )
+{
+    media_tree_t *p_tree = userdata;
+    input_item_t *p_input = p_event->p_obj;
+
+    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 );
+    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 );
+    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 );
+    media_tree_Unlock( p_tree );
+}
+
+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 );
+}
+
+/* same as input_item_node_Delete(), but also deregister input events for every node */
+static void DestroyNode( 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( 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 media_tree_Unlock( 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( 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( media_tree_t *p_tree, const input_item_node_t *p_nod
     }
 }
 
-void media_tree_connected_default( media_tree_t *p_tree, void *userdata )
+void media_tree_subtree_added_default( 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 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->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->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 ) );
@@ -238,7 +348,7 @@ input_item_node_t *media_tree_Add( 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 media_tree_Remove( 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.rc2



More information about the vlc-devel mailing list