[vlc-devel] [PATCH 05/14] preparser: provide events in callbacks

Romain Vimont rom1v at videolabs.io
Thu Aug 16 16:02:02 CEST 2018


The input thread used by the preparser is not exposed to the caller.
Add a "callbacks" parameter to receive preparsing events.
---
 include/vlc_input_item.h  | 10 ++++-
 lib/media.c               |  2 +-
 src/libvlc.c              |  8 +++-
 src/libvlc.h              |  2 +
 src/playlist/item.c       |  3 +-
 src/preparser/preparser.c | 95 +++++++++++++++++++++++++++++++++++----
 src/preparser/preparser.h |  4 +-
 test/libvlc/media.c       |  3 +-
 8 files changed, 110 insertions(+), 17 deletions(-)

diff --git a/include/vlc_input_item.h b/include/vlc_input_item.h
index 38cc0e82c2..cd22b3277d 100644
--- a/include/vlc_input_item.h
+++ b/include/vlc_input_item.h
@@ -39,6 +39,7 @@
 
 typedef struct input_item_opaque input_item_opaque_t;
 typedef struct input_item_slave input_item_slave_t;
+typedef struct input_preparser_callbacks_t input_preparser_callbacks_t;
 
 struct info_t
 {
@@ -379,7 +380,7 @@ typedef enum input_item_meta_request_option_t
     META_REQUEST_OPTION_DO_INTERACT   = 0x04
 } input_item_meta_request_option_t;
 
-/* status of the vlc_InputItemPreparseEnded event */
+/* status of the on_preparse_ended() callback */
 enum input_item_preparse_status
 {
     ITEM_PREPARSE_SKIPPED,
@@ -388,8 +389,15 @@ enum input_item_preparse_status
     ITEM_PREPARSE_DONE
 };
 
+typedef struct input_preparser_callbacks_t {
+    void (*on_preparse_ended)(input_item_t *, enum input_item_preparse_status status, void *userdata);
+    void (*on_subtree_added)(input_item_t *, input_item_node_t *subtree, void *userdata);
+} input_preparser_callbacks_t;
+
 VLC_API int libvlc_MetadataRequest( libvlc_int_t *, input_item_t *,
                                     input_item_meta_request_option_t,
+                                    const input_preparser_callbacks_t *cbs,
+                                    void *cbs_userdata,
                                     int, void * );
 VLC_API int libvlc_ArtRequest(libvlc_int_t *, input_item_t *,
                               input_item_meta_request_option_t );
diff --git a/lib/media.c b/lib/media.c
index 5ffa91b47d..5ed5e2eaa1 100644
--- a/lib/media.c
+++ b/lib/media.c
@@ -811,7 +811,7 @@ static int media_parse(libvlc_media_t *media, bool b_async,
             parse_scope |= META_REQUEST_OPTION_SCOPE_NETWORK;
         if (parse_flag & libvlc_media_do_interact)
             parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
-        ret = libvlc_MetadataRequest(libvlc, item, parse_scope, timeout, media);
+        ret = libvlc_MetadataRequest(libvlc, item, parse_scope, NULL, NULL, timeout, media);
         if (ret != VLC_SUCCESS)
             return ret;
     }
diff --git a/src/libvlc.c b/src/libvlc.c
index 1f4fed6107..55604c1b79 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -472,6 +472,8 @@ static void GetFilenames( libvlc_int_t *p_vlc, unsigned n,
 
 int vlc_MetadataRequest(libvlc_int_t *libvlc, input_item_t *item,
                         input_item_meta_request_option_t i_options,
+                        const input_preparser_callbacks_t *cbs,
+                        void *cbs_userdata,
                         int timeout, void *id)
 {
     libvlc_priv_t *priv = libvlc_priv(libvlc);
@@ -485,7 +487,7 @@ int vlc_MetadataRequest(libvlc_int_t *libvlc, input_item_t *item,
         item->b_preparse_interact = true;
         vlc_mutex_unlock( &item->lock );
     }
-    input_preparser_Push( priv->parser, item, i_options, timeout, id );
+    input_preparser_Push( priv->parser, item, i_options, cbs, cbs_userdata, timeout, id );
     return VLC_SUCCESS;
 
 }
@@ -497,6 +499,8 @@ int vlc_MetadataRequest(libvlc_int_t *libvlc, input_item_t *item,
  */
 int libvlc_MetadataRequest(libvlc_int_t *libvlc, input_item_t *item,
                            input_item_meta_request_option_t i_options,
+                           const input_preparser_callbacks_t *cbs,
+                           void *cbs_userdata,
                            int timeout, void *id)
 {
     libvlc_priv_t *priv = libvlc_priv(libvlc);
@@ -509,7 +513,7 @@ int libvlc_MetadataRequest(libvlc_int_t *libvlc, input_item_t *item,
         item->i_preparse_depth = 1;
     vlc_mutex_unlock( &item->lock );
 
-    return vlc_MetadataRequest(libvlc, item, i_options, timeout, id);
+    return vlc_MetadataRequest(libvlc, item, i_options, cbs, cbs_userdata, timeout, id);
 }
 
 /**
diff --git a/src/libvlc.h b/src/libvlc.h
index 5040968d57..6c0381122b 100644
--- a/src/libvlc.h
+++ b/src/libvlc.h
@@ -204,6 +204,8 @@ void intf_DestroyAll( libvlc_int_t * );
 
 int vlc_MetadataRequest(libvlc_int_t *libvlc, input_item_t *item,
                         input_item_meta_request_option_t i_options,
+                        const input_preparser_callbacks_t *cbs,
+                        void *cbs_userdata,
                         int timeout, void *id);
 
 /*
diff --git a/src/playlist/item.c b/src/playlist/item.c
index d365ca1e18..9e3d0fac43 100644
--- a/src/playlist/item.c
+++ b/src/playlist/item.c
@@ -744,7 +744,8 @@ static void playlist_Preparse( playlist_t *p_playlist,
 
     if( sys->b_preparse && !input_item_IsPreparsed( input )
      && (EMPTY_STR(psz_artist) || EMPTY_STR(psz_album)) )
-        vlc_MetadataRequest( p_playlist->obj.libvlc, input, 0, -1, p_item );
+        vlc_MetadataRequest( p_playlist->obj.libvlc, input, 0,
+                             NULL, NULL, -1, p_item );
     free( psz_artist );
     free( psz_album );
 }
diff --git a/src/preparser/preparser.c b/src/preparser/preparser.c
index 42ab9d7694..e459f6e1c2 100644
--- a/src/preparser/preparser.c
+++ b/src/preparser/preparser.c
@@ -24,6 +24,7 @@
 #endif
 
 #include <vlc_common.h>
+#include <vlc_atomic.h>
 
 #include "misc/background_worker.h"
 #include "input/input_interface.h"
@@ -39,15 +40,55 @@ struct input_preparser_t
     atomic_bool deactivated;
 };
 
+typedef struct input_preparser_req_t
+{
+    input_item_t *item;
+    const input_preparser_callbacks_t *cbs;
+    void *userdata;
+    vlc_atomic_rc_t rc;
+} input_preparser_req_t;
+
 typedef struct input_preparser_task_t
 {
+    input_preparser_req_t *req;
     input_preparser_t* preparser;
     input_thread_t* input;
     atomic_int state;
     atomic_bool done;
-
 } input_preparser_task_t;
 
+static input_preparser_req_t *ReqCreate(input_item_t *item,
+                                        const input_preparser_callbacks_t *cbs,
+                                        void *userdata)
+{
+    input_preparser_req_t *req = malloc(sizeof(*req));
+    if (unlikely(!req))
+        return NULL;
+
+    req->item = item;
+    req->cbs = cbs;
+    req->userdata = userdata;
+    vlc_atomic_rc_init(&req->rc);
+
+    input_item_Hold(item);
+
+    return req;
+}
+
+static void ReqHold(input_preparser_req_t *req)
+{
+    vlc_atomic_rc_inc(&req->rc);
+}
+
+static void ReqRelease(input_preparser_req_t *req)
+{
+    if (vlc_atomic_rc_dec(&req->rc))
+    {
+        input_item_Release(req->item);
+        free(req);
+    }
+}
+
 static void InputEvent( input_thread_t *input, void *task_,
                         const struct vlc_input_event *event )
 {
@@ -64,13 +105,26 @@ static void InputEvent( input_thread_t *input, void *task_,
             atomic_store( &task->done, true );
             background_worker_RequestProbe( task->preparser->worker );
             break;
+        case INPUT_EVENT_PARSING:
+        {
+            input_preparser_req_t *req = task->req;
+            switch (event->parsing.action)
+            {
+                case VLC_INPUT_PARSING_SUBTREE_ADDED:
+                    if (req->cbs && req->cbs->on_subtree_added)
+                        req->cbs->on_subtree_added(req->item, event->parsing.root, req->userdata);
+                    break;
+            }
+            break;
+        }
         default: ;
     }
 }
 
-static int PreparserOpenInput( void* preparser_, void* item_, void** out )
+static int PreparserOpenInput( void* preparser_, void* req_, void** out )
 {
     input_preparser_t* preparser = preparser_;
+    input_preparser_req_t *req = req_;
     input_preparser_task_t* task = malloc( sizeof *task );
 
     if( unlikely( !task ) )
@@ -81,10 +135,12 @@ static int PreparserOpenInput( void* preparser_, void* item_, void** out )
 
     task->preparser = preparser_;
     task->input = input_CreatePreparser( preparser->owner, InputEvent,
-                                         task, item_ );
+                                         task, req->item );
     if( !task->input )
         goto error;
 
+    task->req = req;
+
     if( input_Start( task->input ) )
     {
         input_Close( task->input );
@@ -97,7 +153,10 @@ static int PreparserOpenInput( void* preparser_, void* item_, void** out )
 
 error:
     free( task );
-    input_item_SignalPreparseEnded( item_, ITEM_PREPARSE_FAILED );
+    /* TODO remove legacy input_item_SignalPreparseEnded() */
+    input_item_SignalPreparseEnded(req->item, ITEM_PREPARSE_FAILED);
+    if (req->cbs && req->cbs->on_preparse_ended)
+        req->cbs->on_preparse_ended(req->item, ITEM_PREPARSE_FAILED, req->userdata);
     return VLC_EGENERIC;
 }
 
@@ -111,6 +170,7 @@ static int PreparserProbeInput( void* preparser_, void* task_ )
 static void PreparserCloseInput( void* preparser_, void* task_ )
 {
     input_preparser_task_t* task = task_;
+    input_preparser_req_t *req = task->req;
 
     input_preparser_t* preparser = preparser_;
     input_thread_t* input = task->input;
@@ -141,11 +201,14 @@ static void PreparserCloseInput( void* preparser_, void* task_ )
     }
 
     input_item_SetPreparsed( item, true );
+    /* TODO remove legacy input_item_SignalPreparseEnded() */
     input_item_SignalPreparseEnded( item, status );
+    if (req->cbs && req->cbs->on_preparse_ended)
+        req->cbs->on_preparse_ended(req->item, status, req->userdata);
 }
 
-static void InputItemRelease( void* item ) { input_item_Release( item ); }
-static void InputItemHold( void* item ) { input_item_Hold( item ); }
+static void ReqHoldVoid(void *item) { ReqHold(item); }
+static void ReqReleaseVoid(void *item) { ReqRelease(item); }
 
 input_preparser_t* input_preparser_New( vlc_object_t *parent )
 {
@@ -157,8 +220,9 @@ input_preparser_t* input_preparser_New( vlc_object_t *parent )
         .pf_start = PreparserOpenInput,
         .pf_probe = PreparserProbeInput,
         .pf_stop = PreparserCloseInput,
-        .pf_release = InputItemRelease,
-        .pf_hold = InputItemHold };
+        .pf_release = ReqReleaseVoid,
+        .pf_hold = ReqHoldVoid
+    };
 
 
     if( likely( preparser ) )
@@ -182,6 +246,7 @@ input_preparser_t* input_preparser_New( vlc_object_t *parent )
 
 void input_preparser_Push( input_preparser_t *preparser,
     input_item_t *item, input_item_meta_request_option_t i_options,
+    const input_preparser_callbacks_t *cbs, void *cbs_userdata,
     int timeout, void *id )
 {
     if( atomic_load( &preparser->deactivated ) )
@@ -202,12 +267,24 @@ void input_preparser_Push( input_preparser_t *preparser,
                 break;
             /* fallthrough */
         default:
+            /* TODO remove legacy input_item_SignalPreparseEnded() */
             input_item_SignalPreparseEnded( item, ITEM_PREPARSE_SKIPPED );
+            if (cbs && cbs->on_preparse_ended)
+                cbs->on_preparse_ended(item, ITEM_PREPARSE_SKIPPED, cbs_userdata);
             return;
     }
 
-    if( background_worker_Push( preparser->worker, item, id, timeout ) )
+    struct input_preparser_req_t *req = ReqCreate(item, cbs, cbs_userdata);
+
+    if (background_worker_Push(preparser->worker, req, id, timeout))
+    {
+        /* TODO remove legacy input_item_SignalPreparseEnded() */
         input_item_SignalPreparseEnded( item, ITEM_PREPARSE_FAILED );
+        if (req->cbs && cbs->on_preparse_ended)
+            cbs->on_preparse_ended(item, ITEM_PREPARSE_FAILED, cbs_userdata);
+    }
+
+    ReqRelease(req);
 }
 
 void input_preparser_fetcher_Push( input_preparser_t *preparser,
diff --git a/src/preparser/preparser.h b/src/preparser/preparser.h
index 7cc9930eba..9fe4ae8e87 100644
--- a/src/preparser/preparser.h
+++ b/src/preparser/preparser.h
@@ -45,8 +45,6 @@ input_preparser_t *input_preparser_New( vlc_object_t * );
  *
  * The input item is retained until the preparsing is done or until the
  * preparser object is deleted.
- * Listen to vlc_InputItemPreparseEnded event to get notified when item is
- * preparsed.
  *
  * @param timeout maximum time allowed to preparse the item. If -1, the default
  * "preparse-timeout" option will be used as a timeout. If 0, it will wait
@@ -56,6 +54,8 @@ input_preparser_t *input_preparser_New( vlc_object_t * );
  */
 void input_preparser_Push( input_preparser_t *, input_item_t *,
                            input_item_meta_request_option_t,
+                           const input_preparser_callbacks_t *cbs,
+                           void *cbs_userdata,
                            int timeout, void *id );
 
 void input_preparser_fetcher_Push( input_preparser_t *, input_item_t *,
diff --git a/test/libvlc/media.c b/test/libvlc/media.c
index 4de30c7187..933ca41f70 100644
--- a/test/libvlc/media.c
+++ b/test/libvlc/media.c
@@ -158,7 +158,8 @@ static void test_input_metadata_timeout(libvlc_instance_t *vlc, int timeout,
                              input_item_preparse_timeout, &sem);
     assert(i_ret == 0);
     i_ret = libvlc_MetadataRequest(vlc->p_libvlc_int, p_item,
-                                   META_REQUEST_OPTION_SCOPE_LOCAL, timeout, vlc);
+                                   META_REQUEST_OPTION_SCOPE_LOCAL,
+                                   NULL, NULL, timeout, vlc);
     assert(i_ret == 0);
 
     if (wait_and_cancel > 0)
-- 
2.18.0



More information about the vlc-devel mailing list