[vlc-commits] [Git][videolan/vlc][master] 7 commits: playlist: remove redundant vlc_preparser_Cancel

Steve Lhomme (@robUx4) gitlab at videolan.org
Mon Oct 27 17:56:34 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
e0e13340 by Ayush Dey at 2025-10-27T17:42:26+00:00
playlist: remove redundant vlc_preparser_Cancel

Already called inside vlc_preparser_Delete

- - - - -
f85ea1e8 by Ayush Dey at 2025-10-27T17:42:26+00:00
preparser: rename vlc_preparser_cbs to vlc_preparser_cbs_internal

As a separate struct vlc_preparser_cbs will be added in the next commit
in vlc_preparser.h

- - - - -
341836d4 by Ayush Dey at 2025-10-27T17:42:26+00:00
preparser: rename struct task to struct vlc_preparser_req

- - - - -
1f31130e by Ayush Dey at 2025-10-27T17:42:26+00:00
preparser: use vlc_preparser_req pointer for request identification

Remove vlc_preparser_req_id

- - - - -
a203c96d by Ayush Dey at 2025-10-27T17:42:26+00:00
preparser: add vlc_preparser_req_GetItem API

The input_item_t* argument in callbacks will be replaced with
vlc_preparser_req* in the next commit.

- - - - -
98430128 by Ayush Dey at 2025-10-27T17:42:26+00:00
preparser: expose vlc_preparser_req in callbacks

Add struct vlc_preparser_cbs. The vlc_preparser_req* is now
exposed to identify the request associated with each callback.
It will also be used by the upcoming vlc_preparser_req_Release
API in the next commit.
input_item_t* argument is removed as it can be retrieved using
vlc_preparser_req_GetItem.

- - - - -
52c61546 by Ayush Dey at 2025-10-27T17:42:26+00:00
preparser: add vlc_preparser_req_Release API

Explicit API to release vlc_preparser_req* from user side.
Safe to call this from within the on_ended callback.

- - - - -


20 changed files:

- include/vlc_media_source.h
- include/vlc_preparser.h
- lib/media.c
- lib/media_internal.h
- modules/gui/qt/network/networkmediamodel.cpp
- modules/gui/qt/player/player_controller.cpp
- modules/misc/medialibrary/Thumbnailer.cpp
- modules/misc/medialibrary/medialibrary.h
- src/libvlccore.sym
- src/media_source/media_tree.c
- src/playlist/content.c
- src/playlist/item.c
- src/playlist/item.h
- src/playlist/playlist.c
- src/playlist/preparse.c
- src/playlist/preparse.h
- src/preparser/preparser.c
- test/libvlc/media.c
- test/src/preparser/thumbnail.c
- test/src/preparser/thumbnail_to_files.c


Changes:

=====================================
include/vlc_media_source.h
=====================================
@@ -236,10 +236,10 @@ vlc_media_tree_Find(vlc_media_tree_t *tree, const input_item_t *media,
  * \param tree   the media tree (not necessarily locked)
  * \param parser a valid preparser
  * \param media  the media to preparse
- * \returns VLC_PREPARSER_REQ_ID_INVALID in case of error, or a valid id if the
+ * \returns NULL in case of error, or a valid request handle if the
  * item was scheduled for preparsing. Cancel it vlc_preparser_Cancel().
  */
-VLC_API vlc_preparser_req_id
+VLC_API vlc_preparser_req *
 vlc_media_tree_Preparse(vlc_media_tree_t *tree, vlc_preparser_t *parser,
                         input_item_t *media);
 


=====================================
include/vlc_preparser.h
=====================================
@@ -42,9 +42,22 @@
  * It will also issue art fetching requests.
  */
 typedef struct vlc_preparser_t vlc_preparser_t;
-typedef size_t vlc_preparser_req_id;
 
-#define VLC_PREPARSER_REQ_ID_INVALID 0
+/**
+ * Preparser request opaque handle.
+ *
+ * Identifies a request submitted via vlc_preparser_Push(),
+ * vlc_preparser_GenerateThumbnail(), or vlc_preparser_GenerateThumbnailToFiles().
+ * It can be passed to vlc_preparser_Cancel() to cancel that request.
+ *
+ * @note
+ * - Validity starts when a submit function returns a non-NULL handle and ends
+ *   with vlc_preparser_req_Release().
+ *
+ * - The user must ensure that callbacks and their context remain valid
+ *   until request termination.
+ */
+typedef struct vlc_preparser_req vlc_preparser_req;
 
 #define VLC_PREPARSER_TYPE_PARSE            0x01
 #define VLC_PREPARSER_TYPE_FETCHMETA_LOCAL  0x02
@@ -57,6 +70,50 @@ typedef size_t vlc_preparser_req_id;
 #define VLC_PREPARSER_OPTION_INTERACT 0x1000
 #define VLC_PREPARSER_OPTION_SUBITEMS 0x2000
 
+struct vlc_preparser_cbs
+{
+    /**
+     * Event received when the parser ends
+     *
+     * @note This callback is mandatory.
+     *
+     * @param req request handle returned by vlc_preparser_Push()
+     * @param status VLC_SUCCESS in case of success, VLC_ETIMEOUT in case of
+     * timeout, -EINTR if cancelled, an error otherwise
+     * @param data opaque pointer passed by vlc_preparser_Push()
+     */
+    void (*on_ended)(vlc_preparser_req *req, int status, void *data);
+
+    /**
+     * Event received when a new subtree is added
+     *
+     * @note This callback is optional.
+     *
+     * @param req request handle returned by vlc_preparser_Push()
+     * @param subtree sub items of the current item (the listener gets the ownership)
+     * @param data opaque pointer passed by vlc_preparser_Push()
+     */
+    void (*on_subtree_added)(vlc_preparser_req *req, input_item_node_t *subtree,
+                             void *data);
+
+    /**
+     * Event received when new attachments are added
+     *
+     * @note This callback is optional. It can be called several times for one
+     * parse request. The array contains only new elements after a second call.
+     *
+     * @param req request handle returned by vlc_preparser_Push()
+     * @param array valid array containing new elements, should only be used
+     * within the callback. One and all elements can be held and stored on a
+     * new variable or new array.
+     * @param count number of elements in the array
+     * @param data opaque pointer passed by vlc_preparser_Push()
+     */
+    void (*on_attachments_added)(vlc_preparser_req *req,
+                                 input_attachment_t *const *array,
+                                 size_t count, void *data);
+};
+
 /**
  * Preparser thumbnailer callbacks
  *
@@ -79,7 +136,7 @@ struct vlc_thumbnailer_cbs
      * by using \link picture_Hold \endlink to use it pass the callback's
      * scope.
      *
-     * @param item item used for the thumbnailer
+     * @param req request handle returned by vlc_preparser_GenerateThumbnail()
      * @param status VLC_SUCCESS in case of success, VLC_ETIMEOUT in case of
      * timeout, -EINTR if cancelled, an error otherwise
      * @param thumbnail The generated thumbnail, or NULL in case of failure or
@@ -88,8 +145,7 @@ struct vlc_thumbnailer_cbs
      * vlc_preparser_GenerateThumbnail()
      *
      */
-    void (*on_ended)(input_item_t *item, int status, picture_t* thumbnail,
-                     void *data);
+    void (*on_ended)(vlc_preparser_req *req, int status, picture_t* thumbnail, void *data);
 };
 
 /**
@@ -110,7 +166,7 @@ struct vlc_thumbnailer_to_files_cbs
      * @note This callback is mandatory if calling
      * vlc_preparser_GenerateThumbnailToFiles()
      *
-     * @param item item used for the thumbnailer
+     * @param req request handle returned by vlc_preparser_GenerateThumbnailToFiles()
      * @param status VLC_SUCCESS in case of success, VLC_ETIMEOUT in case of
      * timeout, -EINTR if cancelled, an error otherwise. A success mean that an
      * image was generated but it is still possible that the export failed,
@@ -122,7 +178,7 @@ struct vlc_thumbnailer_to_files_cbs
      * @param data opaque pointer passed by
      * vlc_preparser_GenerateThumbnailToFiles()
      */
-    void (*on_ended)(input_item_t *item, int status,
+    void (*on_ended)(vlc_preparser_req *req, int status,
                      const bool *result_array, size_t result_count, void *data);
 };
 
@@ -268,15 +324,13 @@ VLC_API vlc_preparser_t *vlc_preparser_New( vlc_object_t *obj,
  * vlc_preparser_New() (it is possible to select less types).
  * @param cbs callback to listen to events (can't be NULL)
  * @param cbs_userdata opaque pointer used by the callbacks
- * @param id unique id provided by the caller. This is can be used to cancel
- * the request with vlc_preparser_Cancel()
- * @return VLC_PREPARSER_REQ_ID_INVALID in case of error, or a valid id if the
+ * @return NULL in case of error, or a valid request handle if the
  * item was scheduled for preparsing. If this returns an
  * error, the on_preparse_ended will *not* be invoked
  */
-VLC_API vlc_preparser_req_id
+VLC_API vlc_preparser_req *
 vlc_preparser_Push( vlc_preparser_t *preparser, input_item_t *item, int type_option,
-                    const input_item_parser_cbs_t *cbs, void *cbs_userdata );
+                    const struct vlc_preparser_cbs *cbs, void *cbs_userdata );
 
 /**
  * This function enqueues the provided item for generating a thumbnail
@@ -286,14 +340,14 @@ vlc_preparser_Push( vlc_preparser_t *preparser, input_item_t *item, int type_opt
  * @param arg pointer to the arg struct, NULL for default options
  * @param cbs callback to listen to events (can't be NULL)
  * @param cbs_userdata opaque pointer used by the callbacks
- * @return VLC_PREPARSER_REQ_ID_INVALID in case of error, or a valid id if the
+ * @return NULL in case of error, or a valid request handle if the
  * item was scheduled for thumbnailing. If this returns an
  * error, the thumbnailer.on_ended callback will *not* be invoked
  *
  * The provided input_item will be held by the thumbnailer and can safely be
  * released safely after calling this function.
  */
-VLC_API vlc_preparser_req_id
+VLC_API vlc_preparser_req *
 vlc_preparser_GenerateThumbnail( vlc_preparser_t *preparser, input_item_t *item,
                                  const struct vlc_thumbnailer_arg *arg,
                                  const struct vlc_thumbnailer_cbs *cbs,
@@ -332,14 +386,14 @@ vlc_preparser_CheckThumbnailerFormat(enum vlc_thumbnailer_format format);
  * @param output_count outputs array size, must be > 1
  * @param cbs callback to listen to events (can't be NULL)
  * @param cbs_userdata opaque pointer used by the callbacks
- * @return VLC_PREPARSER_REQ_ID_INVALID in case of error, or a valid id if the
+ * @return NULL in case of error, or a valid request handle if the
  * item was scheduled for thumbnailing. If this returns an
  * error, the thumbnailer.on_ended callback will *not* be invoked
  *
  * The provided input_item will be held by the thumbnailer and can safely be
  * released safely after calling this function.
  */
-VLC_API vlc_preparser_req_id
+VLC_API vlc_preparser_req *
 vlc_preparser_GenerateThumbnailToFiles( vlc_preparser_t *preparser, input_item_t *item,
                                         const struct vlc_thumbnailer_arg *arg,
                                         const struct vlc_thumbnailer_output *outputs,
@@ -348,15 +402,55 @@ vlc_preparser_GenerateThumbnailToFiles( vlc_preparser_t *preparser, input_item_t
                                         void *cbs_userdata );
 
 /**
- * This function cancel all preparsing requests for a given id
+ * This function cancels ongoing or queued preparsing/thumbnail generation
+ * for a given request handle.
  *
  * @param preparser the preparser object
- * @param id unique id returned by vlc_preparser_Push(),
- * VLC_PREPARSER_REQ_ID_INVALID to cancels all tasks
+ * @param req request handle returned by vlc_preparser_Push(),
+ * vlc_preparser_GenerateThumbnail(), or vlc_preparser_GenerateThumbnailToFiles().
+ * Pass NULL to cancel all pending and running tasks.
  * @return number of tasks cancelled
+ *
+ * @note
+ * - When a request is cancelled, the `on_ended` callback will be triggered
+ *   with -EINTR status.
+ *
+ * - If the request is already in a terminated state (finished, cancelled, or error),
+ *   the call is a no-op and no callback will be invoked.
  */
 VLC_API size_t vlc_preparser_Cancel( vlc_preparser_t *preparser,
-                                     vlc_preparser_req_id id );
+                                     vlc_preparser_req *req );
+
+/**
+ * Fetch the input item associated with the request.
+ *
+ * @param req request handle returned by vlc_preparser_Push(),
+ * vlc_preparser_GenerateThumbnail(), or vlc_preparser_GenerateThumbnailToFiles().
+ * @return input_item_t associated with the request
+ *
+ * @note The returned input item is held by the request, it must not be
+ * released by the caller.
+ */
+VLC_API input_item_t *vlc_preparser_req_GetItem(vlc_preparser_req *req);
+
+/**
+ * Release a preparser request handle.
+ *
+ * @param req the preparser request handle
+ *
+ * @note
+ * - The request handle is retained when returned by a submit function.
+ *
+ * - Mandatory to call to avoid memory leaks.
+ *
+ * - It is safe to call this API from within the on_ended callback.
+ *
+ * - The request handle should not be used after calling this function.
+ *
+ * - If called on an active request, it doesn't cancel the preparsing request,
+ *   use vlc_preparser_Cancel() for that.
+ */
+VLC_API void vlc_preparser_req_Release( vlc_preparser_req *req );
 
 /**
  * This function destroys the preparser object and thread.
@@ -375,4 +469,3 @@ VLC_API void vlc_preparser_SetTimeout( vlc_preparser_t *preparser,
 /** @} vlc_preparser */
 
 #endif
-


=====================================
lib/media.c
=====================================
@@ -218,11 +218,11 @@ error:
  * \internal
  * input_item_subitemtree_added (Private) (vlc event Callback)
  */
-static void input_item_subtree_added(input_item_t *item,
+static void input_item_subtree_added(vlc_preparser_req *req,
                                      input_item_node_t *node,
                                      void *user_data)
 {
-    VLC_UNUSED(item);
+    VLC_UNUSED(req);
     libvlc_media_t * p_md = user_data;
     libvlc_media_add_subtree(p_md, node);
     input_item_node_Delete(node);
@@ -241,11 +241,11 @@ void libvlc_media_add_subtree(libvlc_media_t *p_md, const input_item_node_t *nod
     libvlc_event_send( &p_md->event_manager, &event );
 }
 
-static void input_item_attachments_added( input_item_t *item,
+static void input_item_attachments_added( vlc_preparser_req *req,
                                           input_attachment_t *const *array,
                                           size_t count, void *user_data )
 {
-    VLC_UNUSED(item);
+    VLC_UNUSED(req);
     libvlc_media_t * p_md = user_data;
     libvlc_event_t event;
 
@@ -304,10 +304,9 @@ static void send_parsed_changed( libvlc_media_t *p_md,
  * \internal
  * input_item_preparse_ended (Private) (vlc event Callback)
  */
-static void input_item_preparse_ended(input_item_t *item,
+static void input_item_preparse_ended(vlc_preparser_req *req,
                                       int status, void *user_data)
 {
-    VLC_UNUSED(item);
     libvlc_media_t * p_md = user_data;
     libvlc_media_parsed_status_t new_status;
 
@@ -329,6 +328,8 @@ static void input_item_preparse_ended(input_item_t *item,
             vlc_assert_unreachable();
     }
     send_parsed_changed( p_md, new_status );
+    vlc_preparser_req_Release( req );
+    p_md->req = NULL;
 
     if (atomic_fetch_sub_explicit(&p_md->worker_count, 1,
                                   memory_order_release) == 1)
@@ -374,7 +375,7 @@ libvlc_media_t * libvlc_media_new_from_input_item(input_item_t *p_input_item )
 
     p_md->p_input_item->libvlc_owner = p_md;
     atomic_init(&p_md->parsed_status, libvlc_media_parsed_status_none);
-    p_md->id = VLC_PREPARSER_REQ_ID_INVALID;
+    p_md->req = NULL;
 
     libvlc_event_manager_init( &p_md->event_manager, p_md );
 
@@ -721,7 +722,7 @@ libvlc_media_get_filestat( libvlc_media_t *p_md, unsigned type, uint64_t *out )
     return 1;
 }
 
-static const input_item_parser_cbs_t preparser_callbacks = {
+static const struct vlc_preparser_cbs preparser_callbacks = {
     .on_ended = input_item_preparse_ended,
     .on_subtree_added = input_item_subtree_added,
     .on_attachments_added = input_item_attachments_added,
@@ -818,9 +819,9 @@ int libvlc_media_parse_request(libvlc_instance_t *inst, libvlc_media_t *media,
 
     vlc_preparser_SetTimeout(parser, VLC_TICK_FROM_MS(timeout));
 
-    media->id = vlc_preparser_Push(parser, item, parse_scope,
-                             &preparser_callbacks, media);
-    if (media->id == VLC_PREPARSER_REQ_ID_INVALID)
+    media->req = vlc_preparser_Push(parser, item, parse_scope,
+                                    &preparser_callbacks, media);
+    if (media->req == NULL)
     {
         atomic_fetch_sub_explicit(&media->worker_count, 1,
                                   memory_order_relaxed);
@@ -835,10 +836,10 @@ libvlc_media_parse_stop(libvlc_instance_t *inst, libvlc_media_t *media)
 {
     vlc_preparser_t *parser = libvlc_get_preparser(inst);
     assert(parser != NULL);
-    if (media->id != VLC_PREPARSER_REQ_ID_INVALID)
+    if (media->req != NULL)
     {
-        vlc_preparser_Cancel(parser, media->id);
-        media->id = VLC_PREPARSER_REQ_ID_INVALID;
+        vlc_preparser_Cancel(parser, media->req);
+        media->req = NULL;
     }
 }
 
@@ -927,13 +928,12 @@ struct libvlc_media_thumbnail_request_t
     unsigned int height;
     bool crop;
     libvlc_picture_type_t type;
-    vlc_preparser_req_id id;
+    vlc_preparser_req *preparser_req;
 };
 
-static void media_on_thumbnail_ready( input_item_t *item, int status,
+static void media_on_thumbnail_ready( vlc_preparser_req *request, int status,
                                       picture_t* thumbnail, void* data )
 {
-    (void) item;
     (void) status;
 
     libvlc_media_thumbnail_request_t *req = data;
@@ -949,6 +949,8 @@ static void media_on_thumbnail_ready( input_item_t *item, int status,
     libvlc_event_send( &p_media->event_manager, &event );
     if ( pic != NULL )
         libvlc_picture_release( pic );
+
+    vlc_preparser_req_Release( request );
 }
 
 // Start an asynchronous thumbnail generation
@@ -982,9 +984,9 @@ libvlc_media_thumbnail_request( libvlc_instance_t *inst,
     static const struct vlc_thumbnailer_cbs cbs = {
         .on_ended = media_on_thumbnail_ready,
     };
-    req->id = vlc_preparser_GenerateThumbnail( thumb, md->p_input_item, thumb_arg,
-                                               &cbs, req );
-    if ( req->id == VLC_PREPARSER_REQ_ID_INVALID )
+    req->preparser_req = vlc_preparser_GenerateThumbnail( thumb, md->p_input_item,
+                                                          thumb_arg, &cbs, req );
+    if ( req->preparser_req == NULL )
     {
         free( req );
         libvlc_media_release( md );
@@ -1043,7 +1045,7 @@ void libvlc_media_thumbnail_request_destroy( libvlc_media_thumbnail_request_t *r
     vlc_preparser_t *thumb = libvlc_get_thumbnailer(req->instance);
     assert(thumb != NULL);
 
-    vlc_preparser_Cancel( thumb, req->id );
+    vlc_preparser_Cancel( thumb, req->preparser_req );
     libvlc_media_release( req->md );
     libvlc_release(req->instance);
     free( req );


=====================================
lib/media_internal.h
=====================================
@@ -49,7 +49,7 @@ struct libvlc_media_t
     atomic_uint worker_count;
 
     _Atomic libvlc_media_parsed_status_t parsed_status;
-    vlc_preparser_req_id id;
+    vlc_preparser_req *req;
 };
 
 /* Media Descriptor */


=====================================
modules/gui/qt/network/networkmediamodel.cpp
=====================================
@@ -94,7 +94,7 @@ class NetworkMediaModelPrivate
 public:
     NetworkMediaModelPrivate(NetworkMediaModel* pub)
         : LocalListBaseModelPrivate<NetworkMediaItemPtr>(pub)
-        , m_preparseSem(1), m_parserId(VLC_PREPARSER_REQ_ID_INVALID)
+        , m_preparseSem(1), m_parserReq(NULL)
     {}
 
 public:
@@ -409,8 +409,8 @@ public:
             std::vector<SharedInputItem> itemList;
             {
                 MediaTreeLocker lock{tree};
-                if (m_parserId != VLC_PREPARSER_REQ_ID_INVALID)
-                    vlc_preparser_Cancel( parser, m_parserId );
+                if (m_parserReq != NULL)
+                    vlc_preparser_Cancel( parser, m_parserReq );
                 m_path = {QVariant::fromValue(PathNode(m_treeItem, m_name))};
                 if (vlc_media_tree_Find( tree.get(), m_treeItem.media.get(), &mediaNode, &parent))
                 {
@@ -438,7 +438,7 @@ public:
         }
 
         m_preparseSem.acquire();
-        m_parserId = vlc_media_tree_Preparse( tree.get(), parser, m_treeItem.media.get() );
+        m_parserReq = vlc_media_tree_Preparse( tree.get(), parser, m_treeItem.media.get() );
 
         m_listener = std::move( l );
 
@@ -481,7 +481,7 @@ public:
 
     struct ListenerCb;
 private:
-    vlc_preparser_req_id m_parserId;
+    vlc_preparser_req *m_parserReq;
 };
 
 // NetworkMediaModel::ListenerCb implementation
@@ -513,10 +513,10 @@ NetworkMediaModel::~NetworkMediaModel()
         auto parser = d->m_ctx->getNetworkPreparser();
         if (likely(parser != NULL))
         {
-            if (d->m_parserId != VLC_PREPARSER_REQ_ID_INVALID)
+            if (d->m_parserReq != NULL)
             {
-                vlc_preparser_Cancel( parser, d->m_parserId );
-                d->m_parserId = VLC_PREPARSER_REQ_ID_INVALID;
+                vlc_preparser_Cancel( parser, d->m_parserReq );
+                d->m_parserReq = NULL;
             }
             //wait for the callback call on cancel
             d->m_preparseSem.acquire();


=====================================
modules/gui/qt/player/player_controller.cpp
=====================================
@@ -1020,11 +1020,13 @@ static void on_player_timer_smpte_update(const struct vlc_player_timer_smpte_tim
 }
 
 
-static void on_preparse_ended_callback(input_item_t *p_item,
+static void on_preparse_ended_callback(vlc_preparser_req *req,
                                        int, void *userdata)
 {
+    input_item_t *p_item = vlc_preparser_req_GetItem(req);
     PlayerControllerPrivate *me = reinterpret_cast<PlayerControllerPrivate *>(userdata);
     me->onArtFetchEnded(p_item, input_item_IsArtFetched(p_item));
+    vlc_preparser_req_Release(req);
 }
 
 
@@ -1096,8 +1098,8 @@ static const struct vlc_player_timer_smpte_cbs player_timer_smpte_cbs = {
 
 // art fetcher callbacks
 
-static const input_item_parser_cbs_t art_fetcher_cbs  = []{
-    input_item_parser_cbs_t cbs{};
+static const struct vlc_preparser_cbs art_fetcher_cbs = []{
+    struct vlc_preparser_cbs cbs{};
     cbs.on_ended = on_preparse_ended_callback;
     return cbs;
 }();


=====================================
modules/misc/medialibrary/Thumbnailer.cpp
=====================================
@@ -49,7 +49,7 @@ Thumbnailer::Thumbnailer( vlc_medialibrary_module_t* ml )
         throw std::runtime_error( "Failed to instantiate a vlc_preparser_t" );
 }
 
-void Thumbnailer::onThumbnailToFilesComplete(input_item_t *, int ,
+void Thumbnailer::onThumbnailToFilesComplete(vlc_preparser_req *req, int ,
                                              const bool *result_array,
                                              size_t result_count, void *data)
 {
@@ -64,6 +64,7 @@ void Thumbnailer::onThumbnailToFilesComplete(input_item_t *, int ,
     }
     ctx->thumbnailer->m_currentContext = nullptr;
     ctx->thumbnailer->m_cond.broadcast();
+    vlc_preparser_req_Release( req );
 }
 
 bool Thumbnailer::generate( const medialibrary::IMedia&, const std::string& mrl,
@@ -110,14 +111,14 @@ bool Thumbnailer::generate( const medialibrary::IMedia&, const std::string& mrl,
             .on_ended = onThumbnailToFilesComplete,
         };
 
-        vlc_preparser_req_id requestId;
-        requestId = vlc_preparser_GenerateThumbnailToFiles(m_thumbnailer.get(),
-                                                           item.get(),
-                                                           &thumb_arg,
-                                                           &thumb_out, 1,
-                                                           &cbs, &ctx);
+        vlc_preparser_req *preparserReq;
+        preparserReq = vlc_preparser_GenerateThumbnailToFiles(m_thumbnailer.get(),
+                                                              item.get(),
+                                                              &thumb_arg,
+                                                              &thumb_out, 1,
+                                                              &cbs, &ctx);
 
-        if (requestId == VLC_PREPARSER_REQ_ID_INVALID)
+        if (preparserReq == NULL)
         {
             m_currentContext = nullptr;
             return false;
@@ -132,7 +133,7 @@ bool Thumbnailer::generate( const medialibrary::IMedia&, const std::string& mrl,
 
 void Thumbnailer::stop()
 {
-    vlc_preparser_Cancel(m_thumbnailer.get(), VLC_PREPARSER_REQ_ID_INVALID);
+    vlc_preparser_Cancel(m_thumbnailer.get(), NULL);
 
     vlc::threads::mutex_locker lock{ m_mutex };
     if ( m_currentContext != nullptr )


=====================================
modules/misc/medialibrary/medialibrary.h
=====================================
@@ -124,7 +124,7 @@ class Thumbnailer : public medialibrary::IThumbnailer
         Thumbnailer* thumbnailer;
         bool done;
         bool error;
-        vlc_preparser_req_id id;
+        vlc_preparser_req *req;
     };
 public:
     Thumbnailer(vlc_medialibrary_module_t* ml);
@@ -134,7 +134,7 @@ public:
     void stop() override;
 
 private:
-    static void onThumbnailToFilesComplete(input_item_t *item, int status,
+    static void onThumbnailToFilesComplete(vlc_preparser_req *req, int status,
                                            const bool *result_array,
                                            size_t result_count, void *data);
 


=====================================
src/libvlccore.sym
=====================================
@@ -1054,5 +1054,7 @@ vlc_preparser_GetBestThumbnailerFormat
 vlc_preparser_GenerateThumbnail
 vlc_preparser_GenerateThumbnailToFiles
 vlc_preparser_Cancel
+vlc_preparser_req_GetItem
+vlc_preparser_req_Release
 vlc_preparser_Delete
 vlc_preparser_SetTimeout


=====================================
src/media_source/media_tree.c
=====================================
@@ -130,9 +130,10 @@ vlc_media_tree_ClearChildren(input_item_node_t *root)
 }
 
 static void
-media_subtree_changed(input_item_t *media, input_item_node_t *node,
+media_subtree_changed(vlc_preparser_req *req, input_item_node_t *node,
                       void *userdata)
 {
+    input_item_t *media = vlc_preparser_req_GetItem(req);
     vlc_media_tree_t *tree = userdata;
 
     vlc_media_tree_Lock(tree);
@@ -159,8 +160,9 @@ media_subtree_changed(input_item_t *media, input_item_node_t *node,
 }
 
 static void
-media_subtree_preparse_ended(input_item_t *media, int status, void *user_data)
+media_subtree_preparse_ended(vlc_preparser_req *req, int status, void *user_data)
 {
+    input_item_t *media = vlc_preparser_req_GetItem(req);
     vlc_media_tree_t *tree = user_data;
 
     vlc_media_tree_Lock(tree);
@@ -175,6 +177,7 @@ media_subtree_preparse_ended(input_item_t *media, int status, void *user_data)
     }
     vlc_media_tree_Notify(tree, on_preparse_end, subtree_root, status);
     vlc_media_tree_Unlock(tree);
+    vlc_preparser_req_Release(req);
 }
 
 static inline void
@@ -322,12 +325,12 @@ vlc_media_tree_Remove(vlc_media_tree_t *tree, input_item_t *media)
     return true;
 }
 
-static const input_item_parser_cbs_t preparser_callbacks = {
+static const struct vlc_preparser_cbs preparser_callbacks = {
     .on_ended = media_subtree_preparse_ended,
     .on_subtree_added = media_subtree_changed,
 };
 
-vlc_preparser_req_id
+vlc_preparser_req *
 vlc_media_tree_Preparse(vlc_media_tree_t *tree, vlc_preparser_t *parser,
                         input_item_t *media)
 {
@@ -336,7 +339,7 @@ vlc_media_tree_Preparse(vlc_media_tree_t *tree, vlc_preparser_t *parser,
     VLC_UNUSED(parser);
     VLC_UNUSED(media);
     VLC_UNUSED(preparser_callbacks);
-    return VLC_PREPARSER_REQ_ID_INVALID;
+    return NULL;
 #else
     return vlc_preparser_Push(parser, media, VLC_PREPARSER_TYPE_PARSE |
                               VLC_PREPARSER_OPTION_INTERACT |


=====================================
src/playlist/content.c
=====================================
@@ -80,8 +80,8 @@ vlc_playlist_ItemsInserted(vlc_playlist_t *playlist, size_t index, size_t count,
     for (size_t i = index; i < index + count; ++i)
     {
         vlc_playlist_item_t *item = playlist->items.data[i];
-        item->preparser_id = vlc_playlist_AutoPreparse(playlist, item->media,
-                                                       subitems);
+        item->preparser_req = vlc_playlist_AutoPreparse(playlist, item->media,
+                                                        subitems);
     }
 }
 
@@ -238,7 +238,7 @@ vlc_playlist_Clear(vlc_playlist_t *playlist)
     VLC_UNUSED(ret); /* what could we do? */
 
     if (playlist->parser != NULL)
-        vlc_preparser_Cancel(playlist->parser, VLC_PREPARSER_REQ_ID_INVALID);
+        vlc_preparser_Cancel(playlist->parser, NULL);
 
     vlc_playlist_ClearItems(playlist);
     vlc_playlist_ItemsReset(playlist);
@@ -319,8 +319,8 @@ vlc_playlist_Remove(vlc_playlist_t *playlist, size_t index, size_t count)
     for (size_t i = 0; i < count; ++i) {
         vlc_playlist_item_t *item = playlist->items.data[index + i];
         if (playlist->parser != NULL
-                && item->preparser_id != VLC_PREPARSER_REQ_ID_INVALID)
-            vlc_preparser_Cancel(playlist->parser, item->preparser_id);
+                && item->preparser_req != NULL)
+            vlc_preparser_Cancel(playlist->parser, item->preparser_req);
 
         vlc_playlist_item_Release(item);
     }
@@ -356,8 +356,8 @@ vlc_playlist_Replace(vlc_playlist_t *playlist, size_t index,
 
     vlc_playlist_item_t *old = playlist->items.data[index];
     if (playlist->parser != NULL
-            && old->preparser_id != VLC_PREPARSER_REQ_ID_INVALID)
-        vlc_preparser_Cancel(playlist->parser, old->preparser_id);
+            && old->preparser_req != NULL)
+        vlc_preparser_Cancel(playlist->parser, old->preparser_req);
     vlc_playlist_item_Release(old);
     playlist->items.data[index] = item;
 


=====================================
src/playlist/item.c
=====================================
@@ -36,7 +36,7 @@ vlc_playlist_item_New(input_item_t *media, uint64_t id)
 
     vlc_atomic_rc_init(&item->rc);
     item->id = id;
-    item->preparser_id = VLC_PREPARSER_REQ_ID_INVALID;
+    item->preparser_req = NULL;
     item->media = media;
     input_item_Hold(media);
     return item;


=====================================
src/playlist/item.h
=====================================
@@ -31,7 +31,7 @@ struct vlc_playlist_item
 {
     input_item_t *media;
     uint64_t id;
-    vlc_preparser_req_id preparser_id;
+    vlc_preparser_req *preparser_req;
     vlc_atomic_rc_t rc;
 };
 


=====================================
src/playlist/playlist.c
=====================================
@@ -85,7 +85,6 @@ vlc_playlist_Delete(vlc_playlist_t *playlist)
     assert(vlc_list_is_empty(&playlist->listeners));
 
     if (playlist->parser != NULL) {
-        vlc_preparser_Cancel(playlist->parser, VLC_PREPARSER_REQ_ID_INVALID);
         vlc_preparser_Delete(playlist->parser);
     }
 


=====================================
src/playlist/preparse.c
=====================================
@@ -76,10 +76,10 @@ vlc_playlist_ExpandItemFromNode(vlc_playlist_t *playlist,
 }
 
 static void
-on_subtree_added(input_item_t *media, input_item_node_t *subtree,
+on_subtree_added(vlc_preparser_req *req, input_item_node_t *subtree,
                  void *userdata)
 {
-    VLC_UNUSED(media); /* retrieved by subtree->p_item */
+    VLC_UNUSED(req); /* retrieved by subtree->p_item */
     vlc_playlist_t *playlist = userdata;
 
     vlc_playlist_Lock(playlist);
@@ -89,9 +89,9 @@ on_subtree_added(input_item_t *media, input_item_node_t *subtree,
 }
 
 static void
-on_preparse_ended(input_item_t *media, int status, void *userdata)
+on_preparse_ended(vlc_preparser_req *req, int status, void *userdata)
 {
-    VLC_UNUSED(media); /* retrieved by subtree->p_item */
+    input_item_t *media = vlc_preparser_req_GetItem(req);
     vlc_playlist_t *playlist = userdata;
 
     if (status != VLC_SUCCESS)
@@ -103,14 +103,15 @@ on_preparse_ended(input_item_t *media, int status, void *userdata)
         vlc_playlist_Notify(playlist, on_items_updated, index,
                             &playlist->items.data[index], 1);
     vlc_playlist_Unlock(playlist);
+    vlc_preparser_req_Release(req);
 }
 
-static const input_item_parser_cbs_t preparser_callbacks = {
+static const struct vlc_preparser_cbs preparser_callbacks = {
     .on_ended = on_preparse_ended,
     .on_subtree_added = on_subtree_added,
 };
 
-vlc_preparser_req_id
+vlc_preparser_req *
 vlc_playlist_AutoPreparse(vlc_playlist_t *playlist, input_item_t *input,
                           bool parse_subitems)
 {
@@ -137,7 +138,7 @@ vlc_playlist_AutoPreparse(vlc_playlist_t *playlist, input_item_t *input,
         enum input_item_type_e input_type = input_item_GetType(input, &input_net);
 
         if (input_net)
-            return VLC_PREPARSER_REQ_ID_INVALID;
+            return NULL;
 
         switch (input_type)
         {
@@ -147,7 +148,7 @@ vlc_playlist_AutoPreparse(vlc_playlist_t *playlist, input_item_t *input,
             case ITEM_TYPE_PLAYLIST:
                 break;
             default:
-                return VLC_PREPARSER_REQ_ID_INVALID;
+                return NULL;
         }
 
         int options = VLC_PREPARSER_TYPE_PARSE | VLC_PREPARSER_TYPE_FETCHMETA_LOCAL;
@@ -157,5 +158,5 @@ vlc_playlist_AutoPreparse(vlc_playlist_t *playlist, input_item_t *input,
         return vlc_preparser_Push(playlist->parser, input, options,
                                   &preparser_callbacks, playlist);
     }
-    return VLC_PREPARSER_REQ_ID_INVALID;
+    return NULL;
 }


=====================================
src/playlist/preparse.h
=====================================
@@ -27,7 +27,7 @@
 typedef struct vlc_playlist vlc_playlist_t;
 typedef struct input_item_node_t input_item_node_t;
 
-vlc_preparser_req_id
+vlc_preparser_req *
 vlc_playlist_AutoPreparse(vlc_playlist_t *playlist, input_item_t *input,
                           bool parse_subitems);
 


=====================================
src/preparser/preparser.c
=====================================
@@ -36,9 +36,9 @@
 #include "input/input_internal.h"
 #include "fetcher.h"
 
-union vlc_preparser_cbs
+union vlc_preparser_cbs_internal
 {
-    const input_item_parser_cbs_t *parser;
+    const struct vlc_preparser_cbs *parser;
     const struct vlc_thumbnailer_cbs *thumbnailer;
     const struct vlc_thumbnailer_to_files_cbs *thumbnailer_to_files;
 };
@@ -53,7 +53,6 @@ struct vlc_preparser_t
     vlc_tick_t timeout;
 
     vlc_mutex_t lock;
-    vlc_preparser_req_id current_id;
     struct vlc_list submitted_tasks; /**< list of struct task */
 };
 
@@ -67,15 +66,14 @@ struct task_thumbnail_output
     unsigned int creat_mode;
 };
 
-struct task
+struct vlc_preparser_req
 {
     vlc_preparser_t *preparser;
     input_item_t *item;
     int options;
     struct vlc_thumbnailer_arg thumb_arg;
-    union vlc_preparser_cbs cbs;
+    union vlc_preparser_cbs_internal cbs;
     void *userdata;
-    vlc_preparser_req_id id;
 
     vlc_interrupt_t *i11e_ctx;
     picture_t *pic;
@@ -89,140 +87,131 @@ struct task
     struct vlc_runnable runnable; /**< to be passed to the executor */
 
     struct vlc_list node; /**< node of vlc_preparser_t.submitted_tasks */
+
+    vlc_atomic_rc_t rc;
 };
 
-static struct task *
-TaskNew(vlc_preparser_t *preparser, void (*run)(void *), input_item_t *item,
-        int options, const struct vlc_thumbnailer_arg *thumb_arg,
-        union vlc_preparser_cbs cbs, void *userdata)
+static struct vlc_preparser_req *
+PreparserRequestNew(vlc_preparser_t *preparser, void (*run)(void *), input_item_t *item,
+                    int options, const struct vlc_thumbnailer_arg *thumb_arg,
+                    union vlc_preparser_cbs_internal cbs, void *userdata)
 {
-    struct task *task = malloc(sizeof(*task));
-    if (!task)
+    struct vlc_preparser_req *req = malloc(sizeof(*req));
+    if (!req)
         return NULL;
 
-    task->preparser = preparser;
-    task->item = item;
-    task->options = options;
-    task->cbs = cbs;
-    task->userdata = userdata;
-    task->pic = NULL;
-    task->outputs = NULL;
-    task->output_count = 0;
+    req->preparser = preparser;
+    req->item = item;
+    req->options = options;
+    req->cbs = cbs;
+    req->userdata = userdata;
+    req->pic = NULL;
+    req->outputs = NULL;
+    req->output_count = 0;
+    vlc_atomic_rc_init(&req->rc);
 
     if (thumb_arg == NULL)
-        task->thumb_arg = (struct vlc_thumbnailer_arg) {
+        req->thumb_arg = (struct vlc_thumbnailer_arg) {
             .seek.type = VLC_THUMBNAILER_SEEK_NONE,
             .hw_dec = false,
         };
     else
-        task->thumb_arg = *thumb_arg;
+        req->thumb_arg = *thumb_arg;
 
     input_item_Hold(item);
 
-    vlc_sem_init(&task->preparse_ended, 0);
-    task->preparse_status = VLC_EGENERIC;
-    atomic_init(&task->interrupted, false);
+    vlc_sem_init(&req->preparse_ended, 0);
+    req->preparse_status = VLC_EGENERIC;
+    atomic_init(&req->interrupted, false);
 
-    task->runnable.run = run;
-    task->runnable.userdata = task;
+    req->runnable.run = run;
+    req->runnable.userdata = req;
     if (options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES)
-        task->i11e_ctx = vlc_interrupt_create();
+        req->i11e_ctx = vlc_interrupt_create();
     else
-        task->i11e_ctx = NULL;
+        req->i11e_ctx = NULL;
 
-    return task;
+    return req;
 }
 
 static void
-TaskDelete(struct task *task)
-{
-    input_item_Release(task->item);
-    for (size_t i = 0; i < task->output_count; ++i)
-        free(task->outputs[i].file_path);
-    free(task->outputs);
-    if (task->i11e_ctx != NULL)
-        vlc_interrupt_destroy(task->i11e_ctx);
-    free(task);
-}
-
-static vlc_preparser_req_id
-PreparserGetNextTaskIdLocked(vlc_preparser_t *preparser, struct task *task)
-{
-    vlc_preparser_req_id id = task->id = preparser->current_id++;
-    static_assert(VLC_PREPARSER_REQ_ID_INVALID == 0, "Invalid id should be 0");
-    if (unlikely(preparser->current_id == 0)) /* unsigned wrapping */
-        ++preparser->current_id;
-    return id;
+PreparserRequestDelete(struct vlc_preparser_req *req)
+{
+    input_item_Release(req->item);
+    for (size_t i = 0; i < req->output_count; ++i)
+        free(req->outputs[i].file_path);
+    free(req->outputs);
+    if (req->i11e_ctx != NULL)
+        vlc_interrupt_destroy(req->i11e_ctx);
+    free(req);
 }
 
-static vlc_preparser_req_id
-PreparserAddTask(vlc_preparser_t *preparser, struct task *task)
+static void
+PreparserAddTask(vlc_preparser_t *preparser, struct vlc_preparser_req *req)
 {
     vlc_mutex_lock(&preparser->lock);
-    vlc_preparser_req_id id = PreparserGetNextTaskIdLocked(preparser, task);
-    vlc_list_append(&task->node, &preparser->submitted_tasks);
+    vlc_list_append(&req->node, &preparser->submitted_tasks);
     vlc_mutex_unlock(&preparser->lock);
-    return id;
 }
 
 static void
-PreparserRemoveTask(vlc_preparser_t *preparser, struct task *task)
+PreparserRemoveTask(vlc_preparser_t *preparser, struct vlc_preparser_req *req)
 {
     vlc_mutex_lock(&preparser->lock);
-    vlc_list_remove(&task->node);
+    vlc_list_remove(&req->node);
     vlc_mutex_unlock(&preparser->lock);
 }
 
 static void
-NotifyPreparseEnded(struct task *task)
+NotifyPreparseEnded(struct vlc_preparser_req *req)
 {
-    if (atomic_load(&task->interrupted))
-        task->preparse_status = -EINTR;
-    else if (task->preparse_status == VLC_SUCCESS)
-        input_item_SetPreparsed(task->item);
+    if (atomic_load(&req->interrupted))
+        req->preparse_status = -EINTR;
+    else if (req->preparse_status == VLC_SUCCESS)
+        input_item_SetPreparsed(req->item);
 
-    task->cbs.parser->on_ended(task->item, task->preparse_status,
-                               task->userdata);
+    req->cbs.parser->on_ended(req, req->preparse_status,
+                              req->userdata);
 }
 
 static void
-OnParserEnded(input_item_t *item, int status, void *task_)
+OnParserEnded(input_item_t *item, int status, void *req_)
 {
     VLC_UNUSED(item);
-    struct task *task = task_;
+    struct vlc_preparser_req *req = req_;
 
-    task->preparse_status = status;
-    vlc_sem_post(&task->preparse_ended);
+    req->preparse_status = status;
+    vlc_sem_post(&req->preparse_ended);
 }
 
 static void
 OnParserSubtreeAdded(input_item_t *item, input_item_node_t *subtree,
-                     void *task_)
+                     void *req_)
 {
     VLC_UNUSED(item);
-    struct task *task = task_;
+    struct vlc_preparser_req *req = req_;
 
-    if (atomic_load(&task->interrupted))
+    if (atomic_load(&req->interrupted))
         return;
 
-    if (task->cbs.parser->on_subtree_added)
-        task->cbs.parser->on_subtree_added(task->item, subtree, task->userdata);
+    if (req->cbs.parser->on_subtree_added)
+        req->cbs.parser->on_subtree_added(req, subtree, req->userdata);
 }
 
 static void
 OnParserAttachmentsAdded(input_item_t *item,
                          input_attachment_t *const *array,
-                         size_t count, void *task_)
+                         size_t count, void *req_)
 {
     VLC_UNUSED(item);
-    struct task *task = task_;
+    struct vlc_preparser_req *req = req_;
 
-    if (atomic_load(&task->interrupted))
+    if (atomic_load(&req->interrupted))
         return;
 
-    if (task->cbs.parser->on_attachments_added)
-        task->cbs.parser->on_attachments_added(task->item, array, count, 
-                                               task->userdata);
+    if (req->cbs.parser->on_attachments_added)
+        req->cbs.parser->on_attachments_added(req, array, count,
+                                              req->userdata);
 }
 
 static void
@@ -231,10 +220,10 @@ OnArtFetchEnded(input_item_t *item, bool fetched, void *userdata)
     VLC_UNUSED(item);
     VLC_UNUSED(fetched);
 
-    struct task *task = userdata;
+    struct vlc_preparser_req *req = userdata;
 
-    NotifyPreparseEnded(task);
-    TaskDelete(task);
+    NotifyPreparseEnded(req);
+    vlc_preparser_req_Release(req);
 }
 
 static const input_fetcher_callbacks_t input_fetcher_callbacks = {
@@ -242,7 +231,7 @@ static const input_fetcher_callbacks_t input_fetcher_callbacks = {
 };
 
 static void
-Parse(struct task *task, vlc_tick_t deadline)
+Parse(struct vlc_preparser_req *req, vlc_tick_t deadline)
 {
     static const input_item_parser_cbs_t cbs = {
         .on_ended = OnParserEnded,
@@ -250,29 +239,29 @@ Parse(struct task *task, vlc_tick_t deadline)
         .on_attachments_added = OnParserAttachmentsAdded,
     };
 
-    vlc_object_t *obj = task->preparser->owner;
+    vlc_object_t *obj = req->preparser->owner;
     const struct input_item_parser_cfg cfg = {
         .cbs = &cbs,
-        .cbs_data = task,
-        .subitems = task->options & VLC_PREPARSER_OPTION_SUBITEMS,
-        .interact = task->options & VLC_PREPARSER_OPTION_INTERACT,
+        .cbs_data = req,
+        .subitems = req->options & VLC_PREPARSER_OPTION_SUBITEMS,
+        .interact = req->options & VLC_PREPARSER_OPTION_INTERACT,
     };
     input_item_parser_id_t *parser =
-        input_item_Parse(obj, task->item, &cfg);
+        input_item_Parse(obj, req->item, &cfg);
     if (parser == NULL)
     {
-        task->preparse_status = VLC_EGENERIC;
+        req->preparse_status = VLC_EGENERIC;
         return;
     }
 
     /* Wait until the end of parsing */
     if (deadline == VLC_TICK_INVALID)
-        vlc_sem_wait(&task->preparse_ended);
+        vlc_sem_wait(&req->preparse_ended);
     else
-        if (vlc_sem_timedwait(&task->preparse_ended, deadline))
+        if (vlc_sem_timedwait(&req->preparse_ended, deadline))
         {
             input_item_parser_id_Release(parser);
-            task->preparse_status = VLC_ETIMEOUT;
+            req->preparse_status = VLC_ETIMEOUT;
             return;
         }
 
@@ -281,15 +270,15 @@ Parse(struct task *task, vlc_tick_t deadline)
 }
 
 static int
-Fetch(struct task *task)
+Fetch(struct vlc_preparser_req *req)
 {
-    input_fetcher_t *fetcher = task->preparser->fetcher;
-    if (!fetcher || !(task->options & VLC_PREPARSER_TYPE_FETCHMETA_ALL))
+    input_fetcher_t *fetcher = req->preparser->fetcher;
+    if (!fetcher || !(req->options & VLC_PREPARSER_TYPE_FETCHMETA_ALL))
         return VLC_ENOENT;
 
-    return input_fetcher_Push(fetcher, task->item,
-                              task->options & VLC_PREPARSER_TYPE_FETCHMETA_ALL,
-                              &input_fetcher_callbacks, task);
+    return input_fetcher_Push(fetcher, req->item,
+                              req->options & VLC_PREPARSER_TYPE_FETCHMETA_ALL,
+                              &input_fetcher_callbacks, req);
 }
 
 static void
@@ -297,36 +286,36 @@ ParserRun(void *userdata)
 {
     vlc_thread_set_name("vlc-run-prepars");
 
-    struct task *task = userdata;
-    vlc_preparser_t *preparser = task->preparser;
+    struct vlc_preparser_req *req = userdata;
+    vlc_preparser_t *preparser = req->preparser;
 
     vlc_tick_t deadline = preparser->timeout ? vlc_tick_now() + preparser->timeout
                                              : VLC_TICK_INVALID;
 
-    if (task->options & VLC_PREPARSER_TYPE_PARSE)
+    if (req->options & VLC_PREPARSER_TYPE_PARSE)
     {
-        if (atomic_load(&task->interrupted))
+        if (atomic_load(&req->interrupted))
         {
-            PreparserRemoveTask(preparser, task);
+            PreparserRemoveTask(preparser, req);
             goto end;
         }
 
-        Parse(task, deadline);
+        Parse(req, deadline);
     }
 
-    PreparserRemoveTask(preparser, task);
+    PreparserRemoveTask(preparser, req);
 
-    if (task->preparse_status == VLC_ETIMEOUT || atomic_load(&task->interrupted))
+    if (req->preparse_status == VLC_ETIMEOUT || atomic_load(&req->interrupted))
         goto end;
 
-    int ret = Fetch(task);
+    int ret = Fetch(req);
 
     if (ret == VLC_SUCCESS)
         return; /* Remove the task and notify from the fetcher callback */
 
 end:
-    NotifyPreparseEnded(task);
-    TaskDelete(task);
+    NotifyPreparseEnded(req);
+    vlc_preparser_req_Release(req);
 }
 
 static bool
@@ -339,14 +328,14 @@ on_thumbnailer_input_event( input_thread_t *input,
                                                  event->state.value != END_S ) ) )
          return false;
 
-    struct task *task = userdata;
+    struct vlc_preparser_req *req = userdata;
 
     if (event->type == INPUT_EVENT_THUMBNAIL_READY)
     {
-        task->pic = picture_Hold(event->thumbnail);
-        task->preparse_status = VLC_SUCCESS;
+        req->pic = picture_Hold(event->thumbnail);
+        req->preparse_status = VLC_SUCCESS;
     }
-    vlc_sem_post(&task->preparse_ended);
+    vlc_sem_post(&req->preparse_ended);
     return true;
 }
 
@@ -390,19 +379,19 @@ ThumbnailerToFilesRun(void *userdata)
 {
     vlc_thread_set_name("vlc-run-thfil");
 
-    struct task *task = userdata;
-    vlc_preparser_t *preparser = task->preparser;
-    picture_t* pic = task->pic;
+    struct vlc_preparser_req *req = userdata;
+    vlc_preparser_t *preparser = req->preparser;
+    picture_t* pic = req->pic;
 
-    vlc_interrupt_set(task->i11e_ctx);
+    vlc_interrupt_set(req->i11e_ctx);
 
-    bool *result_array = vlc_alloc(task->output_count, sizeof(bool));
+    bool *result_array = vlc_alloc(req->output_count, sizeof(bool));
     if (result_array == NULL)
         goto error;
 
-    for (size_t i = 0; i < task->output_count; ++i)
+    for (size_t i = 0; i < req->output_count; ++i)
     {
-        struct task_thumbnail_output *output = &task->outputs[i];
+        struct task_thumbnail_output *output = &req->outputs[i];
 
         if (output->fourcc == VLC_CODEC_UNKNOWN)
         {
@@ -425,25 +414,25 @@ ThumbnailerToFilesRun(void *userdata)
         block_Release(block);
         if (ret == -EINTR)
         {
-            task->preparse_status = -EINTR;
+            req->preparse_status = -EINTR;
             goto error;
         }
 
         result_array[i] = ret == 0;
     }
 
-    task->preparse_status = VLC_SUCCESS;
+    req->preparse_status = VLC_SUCCESS;
 error:
-    PreparserRemoveTask(preparser, task);
-    if (task->preparse_status == VLC_SUCCESS)
-        task->cbs.thumbnailer_to_files->on_ended(task->item, task->preparse_status,
-                                                 result_array, task->output_count,
-                                                 task->userdata);
+    PreparserRemoveTask(preparser, req);
+    if (req->preparse_status == VLC_SUCCESS)
+        req->cbs.thumbnailer_to_files->on_ended(req, req->preparse_status,
+                                                result_array, req->output_count,
+                                                req->userdata);
     else
-        task->cbs.thumbnailer_to_files->on_ended(task->item, task->preparse_status,
-                                                 NULL, 0, task->userdata);
+        req->cbs.thumbnailer_to_files->on_ended(req, req->preparse_status,
+                                                NULL, 0, req->userdata);
     picture_Release(pic);
-    TaskDelete(task);
+    vlc_preparser_req_Release(req);
     free(result_array);
 }
 
@@ -452,8 +441,8 @@ ThumbnailerRun(void *userdata)
 {
     vlc_thread_set_name("vlc-run-thumb");
 
-    struct task *task = userdata;
-    vlc_preparser_t *preparser = task->preparser;
+    struct vlc_preparser_req *req = userdata;
+    vlc_preparser_t *preparser = req->preparser;
 
     static const struct vlc_input_thread_callbacks cbs = {
         .on_event = on_thumbnailer_input_event,
@@ -461,10 +450,10 @@ ThumbnailerRun(void *userdata)
 
     const struct vlc_input_thread_cfg cfg = {
         .type = INPUT_TYPE_THUMBNAILING,
-        .hw_dec = task->thumb_arg.hw_dec ? INPUT_CFG_HW_DEC_ENABLED
-                                         : INPUT_CFG_HW_DEC_DISABLED,
+        .hw_dec = req->thumb_arg.hw_dec ? INPUT_CFG_HW_DEC_ENABLED
+                                        : INPUT_CFG_HW_DEC_DISABLED,
         .cbs = &cbs,
-        .cbs_data = task,
+        .cbs_data = req,
     };
 
     vlc_tick_t deadline = preparser->timeout != VLC_TICK_INVALID ?
@@ -472,23 +461,23 @@ ThumbnailerRun(void *userdata)
                           VLC_TICK_INVALID;
 
     input_thread_t* input =
-            input_Create( preparser->owner, task->item, &cfg );
+            input_Create( preparser->owner, req->item, &cfg );
     if (!input)
         goto error;
 
-    assert(task->thumb_arg.seek.speed == VLC_THUMBNAILER_SEEK_PRECISE
-        || task->thumb_arg.seek.speed == VLC_THUMBNAILER_SEEK_FAST);
-    bool fast_seek = task->thumb_arg.seek.speed == VLC_THUMBNAILER_SEEK_FAST;
+    assert(req->thumb_arg.seek.speed == VLC_THUMBNAILER_SEEK_PRECISE
+        || req->thumb_arg.seek.speed == VLC_THUMBNAILER_SEEK_FAST);
+    bool fast_seek = req->thumb_arg.seek.speed == VLC_THUMBNAILER_SEEK_FAST;
 
-    switch (task->thumb_arg.seek.type)
+    switch (req->thumb_arg.seek.type)
     {
         case VLC_THUMBNAILER_SEEK_NONE:
             break;
         case VLC_THUMBNAILER_SEEK_TIME:
-            input_SetTime(input, task->thumb_arg.seek.time, fast_seek);
+            input_SetTime(input, req->thumb_arg.seek.time, fast_seek);
             break;
         case VLC_THUMBNAILER_SEEK_POS:
-            input_SetPosition(input, task->thumb_arg.seek.pos, fast_seek);
+            input_SetPosition(input, req->thumb_arg.seek.pos, fast_seek);
             break;
         default:
             vlc_assert_unreachable();
@@ -502,36 +491,36 @@ ThumbnailerRun(void *userdata)
     }
 
     if (deadline == VLC_TICK_INVALID)
-        vlc_sem_wait(&task->preparse_ended);
+        vlc_sem_wait(&req->preparse_ended);
     else
     {
-        if (vlc_sem_timedwait(&task->preparse_ended, deadline))
-            task->preparse_status = VLC_ETIMEOUT;
+        if (vlc_sem_timedwait(&req->preparse_ended, deadline))
+            req->preparse_status = VLC_ETIMEOUT;
     }
 
-    if (atomic_load(&task->interrupted))
-        task->preparse_status = -EINTR;
+    if (atomic_load(&req->interrupted))
+        req->preparse_status = -EINTR;
 
-    picture_t* pic = task->pic;
+    picture_t* pic = req->pic;
 
-    if (task->options & VLC_PREPARSER_TYPE_THUMBNAIL)
+    if (req->options & VLC_PREPARSER_TYPE_THUMBNAIL)
     {
-        assert((task->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES) == 0);
+        assert((req->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES) == 0);
 
-        PreparserRemoveTask(preparser, task);
-        task->cbs.thumbnailer->on_ended(task->item, task->preparse_status,
-                                        task->preparse_status == VLC_SUCCESS ?
-                                        pic : NULL, task->userdata);
+        PreparserRemoveTask(preparser, req);
+        req->cbs.thumbnailer->on_ended(req, req->preparse_status,
+                                       req->preparse_status == VLC_SUCCESS ?
+                                       pic : NULL, req->userdata);
     }
     else
     {
-        assert(task->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES);
+        assert(req->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES);
 
-        if (task->preparse_status != VLC_SUCCESS)
+        if (req->preparse_status != VLC_SUCCESS)
         {
-            PreparserRemoveTask(preparser, task);
-            task->cbs.thumbnailer_to_files->on_ended(task->item, task->preparse_status,
-                                                     NULL, 0, task->userdata);
+            PreparserRemoveTask(preparser, req);
+            req->cbs.thumbnailer_to_files->on_ended(req, req->preparse_status,
+                                                    NULL, 0, req->userdata);
         }
         else
         {
@@ -541,10 +530,10 @@ ThumbnailerRun(void *userdata)
 
             assert(pic != NULL);
 
-            task->runnable.run = ThumbnailerToFilesRun;
-            vlc_executor_Submit(preparser->thumbnailer_to_files, &task->runnable);
+            req->runnable.run = ThumbnailerToFilesRun;
+            vlc_executor_Submit(preparser->thumbnailer_to_files, &req->runnable);
             pic = NULL;
-            task = NULL;
+            req = NULL;
         }
     }
 
@@ -555,18 +544,25 @@ ThumbnailerRun(void *userdata)
     input_Close(input);
 
 error:
-    if (task != NULL)
-        TaskDelete(task);
+    if (req != NULL)
+        vlc_preparser_req_Release(req);
 }
 
 static void
-Interrupt(struct task *task)
+Interrupt(struct vlc_preparser_req *req)
 {
-    atomic_store(&task->interrupted, true);
-    if (task->i11e_ctx != NULL)
-        vlc_interrupt_kill(task->i11e_ctx);
+    atomic_store(&req->interrupted, true);
+    if (req->i11e_ctx != NULL)
+        vlc_interrupt_kill(req->i11e_ctx);
+
+    vlc_sem_post(&req->preparse_ended);
+}
 
-    vlc_sem_post(&task->preparse_ended);
+static struct vlc_preparser_req *
+PreparserRequestRetain(struct vlc_preparser_req *req)
+{
+    vlc_atomic_rc_inc(&req->rc);
+    return req;
 }
 
 vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent,
@@ -633,7 +629,6 @@ vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent,
 
     vlc_mutex_init(&preparser->lock);
     vlc_list_init(&preparser->submitted_tasks);
-    preparser->current_id = 1;
 
     return preparser;
 
@@ -651,10 +646,11 @@ error_parser:
     return NULL;
 }
 
-vlc_preparser_req_id vlc_preparser_Push( vlc_preparser_t *preparser, input_item_t *item,
-                                         int type_options,
-                                         const input_item_parser_cbs_t *cbs,
-                                         void *cbs_userdata )
+vlc_preparser_req *
+vlc_preparser_Push( vlc_preparser_t *preparser, input_item_t *item,
+                    int type_options,
+                    const struct vlc_preparser_cbs *cbs,
+                    void *cbs_userdata )
 {
     assert((type_options & VLC_PREPARSER_TYPE_THUMBNAIL) == 0);
     assert((type_options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES) == 0);
@@ -669,35 +665,29 @@ vlc_preparser_req_id vlc_preparser_Push( vlc_preparser_t *preparser, input_item_
 
     assert(cbs != NULL && cbs->on_ended != NULL);
 
-    union vlc_preparser_cbs task_cbs = {
+    union vlc_preparser_cbs_internal req_cbs = {
         .parser = cbs,
     };
 
-    struct task *task = TaskNew(preparser, ParserRun, item, type_options, NULL,
-                                task_cbs, cbs_userdata);
-    if( !task )
-        return VLC_PREPARSER_REQ_ID_INVALID;
+    struct vlc_preparser_req *req = PreparserRequestNew(preparser, ParserRun, item, type_options,
+                                                        NULL, req_cbs, cbs_userdata);
+    if( !req )
+        return NULL;
 
     if (preparser->parser != NULL)
     {
-        vlc_preparser_req_id id = PreparserAddTask(preparser, task);
+        PreparserAddTask(preparser, req);
 
-        vlc_executor_Submit(preparser->parser, &task->runnable);
+        vlc_executor_Submit(preparser->parser, &req->runnable);
 
-        return id;
+        return PreparserRequestRetain(req);
     }
 
-    /* input_fetcher is not cancellable (for now) but we need to generate a new
-     * id anyway. */
-    vlc_mutex_lock(&preparser->lock);
-    vlc_preparser_req_id id = PreparserGetNextTaskIdLocked(preparser, task);
-    vlc_mutex_unlock(&preparser->lock);
-
-    int ret = Fetch(task);
-    return ret == VLC_SUCCESS ? id : 0;
+    int ret = Fetch(req);
+    return ret == VLC_SUCCESS ? PreparserRequestRetain(req) : NULL;
 }
 
-vlc_preparser_req_id
+vlc_preparser_req *
 vlc_preparser_GenerateThumbnail( vlc_preparser_t *preparser, input_item_t *item,
                                  const struct vlc_thumbnailer_arg *thumb_arg,
                                  const struct vlc_thumbnailer_cbs *cbs,
@@ -706,21 +696,21 @@ vlc_preparser_GenerateThumbnail( vlc_preparser_t *preparser, input_item_t *item,
     assert(preparser->thumbnailer != NULL);
     assert(cbs != NULL && cbs->on_ended != NULL);
 
-    union vlc_preparser_cbs task_cbs = {
+    union vlc_preparser_cbs_internal req_cbs = {
         .thumbnailer = cbs,
     };
 
-    struct task *task =
-        TaskNew(preparser, ThumbnailerRun, item, VLC_PREPARSER_TYPE_THUMBNAIL,
-                thumb_arg, task_cbs, cbs_userdata);
-    if (task == NULL)
-        return VLC_PREPARSER_REQ_ID_INVALID;
+    struct vlc_preparser_req *req =
+        PreparserRequestNew(preparser, ThumbnailerRun, item, VLC_PREPARSER_TYPE_THUMBNAIL,
+                            thumb_arg, req_cbs, cbs_userdata);
+    if (req == NULL)
+        return NULL;
 
-    vlc_preparser_req_id id = PreparserAddTask(preparser, task);
+    PreparserAddTask(preparser, req);
 
-    vlc_executor_Submit(preparser->thumbnailer, &task->runnable);
+    vlc_executor_Submit(preparser->thumbnailer, &req->runnable);
 
-    return id;
+    return PreparserRequestRetain(req);
 }
 
 static int
@@ -785,7 +775,7 @@ vlc_preparser_CheckThumbnailerFormat(enum vlc_thumbnailer_format format)
     return CheckThumbnailerFormat(format, NULL, NULL, NULL);
 }
 
-vlc_preparser_req_id
+vlc_preparser_req *
 vlc_preparser_GenerateThumbnailToFiles( vlc_preparser_t *preparser, input_item_t *item,
                                         const struct vlc_thumbnailer_arg *thumb_arg,
                                         const struct vlc_thumbnailer_output *outputs,
@@ -797,28 +787,28 @@ vlc_preparser_GenerateThumbnailToFiles( vlc_preparser_t *preparser, input_item_t
     assert(cbs != NULL && cbs->on_ended != NULL);
     assert(outputs != NULL && output_count > 0);
 
-    union vlc_preparser_cbs task_cbs = {
+    union vlc_preparser_cbs_internal req_cbs = {
         .thumbnailer_to_files = cbs,
     };
 
-    struct task *task =
-        TaskNew(preparser, ThumbnailerRun, item,
-                VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES, thumb_arg,
-                task_cbs, cbs_userdata);
-    if (task == NULL)
-        return VLC_PREPARSER_REQ_ID_INVALID;
+    struct vlc_preparser_req *req =
+        PreparserRequestNew(preparser, ThumbnailerRun, item,
+                            VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES, thumb_arg,
+                            req_cbs, cbs_userdata);
+    if (req == NULL)
+        return NULL;
 
-    task->outputs = vlc_alloc(output_count, sizeof(*outputs));
-    if (unlikely(task->outputs == NULL))
+    req->outputs = vlc_alloc(output_count, sizeof(*outputs));
+    if (unlikely(req->outputs == NULL))
     {
-        TaskDelete(task);
-        return VLC_PREPARSER_REQ_ID_INVALID;
+        PreparserRequestDelete(req);
+        return NULL;
     }
 
     size_t valid_output_count = 0;
     for (size_t i = 0; i < output_count; ++i)
     {
-        struct task_thumbnail_output *dst = &task->outputs[i];
+        struct task_thumbnail_output *dst = &req->outputs[i];
         const struct vlc_thumbnailer_output *src = &outputs[i];
         assert(src->file_path != NULL);
 
@@ -837,57 +827,57 @@ vlc_preparser_GenerateThumbnailToFiles( vlc_preparser_t *preparser, input_item_t
 
         if (unlikely(dst->file_path == NULL))
         {
-            TaskDelete(task);
-            return VLC_PREPARSER_REQ_ID_INVALID;
+            PreparserRequestDelete(req);
+            return NULL;
         }
-        task->output_count++;
+        req->output_count++;
     }
 
     if (valid_output_count == 0)
     {
-        TaskDelete(task);
+        PreparserRequestDelete(req);
         msg_Err(preparser->owner, "thumbnailer: no valid \"image encoder\" found");
-        return VLC_PREPARSER_REQ_ID_INVALID;
+        return NULL;
     }
 
-    vlc_preparser_req_id id = PreparserAddTask(preparser, task);
+    PreparserAddTask(preparser, req);
 
-    vlc_executor_Submit(preparser->thumbnailer, &task->runnable);
+    vlc_executor_Submit(preparser->thumbnailer, &req->runnable);
 
-    return id;
+    return PreparserRequestRetain(req);
 }
 
-size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req_id id )
+size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req *req )
 {
     vlc_mutex_lock(&preparser->lock);
 
-    struct task *task;
+    struct vlc_preparser_req *req_itr;
     size_t count = 0;
-    vlc_list_foreach(task, &preparser->submitted_tasks, node)
+    vlc_list_foreach(req_itr, &preparser->submitted_tasks, node)
     {
-        if (id == VLC_PREPARSER_REQ_ID_INVALID || task->id == id)
+        if (req == NULL || req_itr == req)
         {
             count++;
 
             bool canceled;
-            if (task->options & VLC_PREPARSER_TYPE_PARSE)
+            if (req_itr->options & VLC_PREPARSER_TYPE_PARSE)
             {
                 assert(preparser->parser != NULL);
                 canceled = vlc_executor_Cancel(preparser->parser,
-                                               &task->runnable);
+                                               &req_itr->runnable);
             }
-            else if (task->options & (VLC_PREPARSER_TYPE_THUMBNAIL |
-                                      VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES))
+            else if (req_itr->options & (VLC_PREPARSER_TYPE_THUMBNAIL |
+                                         VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES))
             {
                 assert(preparser->thumbnailer != NULL);
                 canceled = vlc_executor_Cancel(preparser->thumbnailer,
-                                               &task->runnable);
+                                               &req_itr->runnable);
                 if (!canceled &&
-                    task->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES)
+                    req_itr->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES)
                 {
                     assert(preparser->thumbnailer_to_files != NULL);
                     canceled = vlc_executor_Cancel(preparser->thumbnailer_to_files,
-                                                   &task->runnable);
+                                                   &req_itr->runnable);
                 }
             }
             else /* TODO: the fetcher should be cancellable too */
@@ -895,42 +885,42 @@ size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req_id id
 
             if (canceled)
             {
-                vlc_list_remove(&task->node);
+                vlc_list_remove(&req_itr->node);
                 vlc_mutex_unlock(&preparser->lock);
-                task->preparse_status = -EINTR;
-                if (task->options & (VLC_PREPARSER_TYPE_PARSE |
-                                     VLC_PREPARSER_TYPE_FETCHMETA_ALL))
+                req_itr->preparse_status = -EINTR;
+                if (req_itr->options & (VLC_PREPARSER_TYPE_PARSE |
+                                        VLC_PREPARSER_TYPE_FETCHMETA_ALL))
                 {
-                    assert((task->options & VLC_PREPARSER_TYPE_THUMBNAIL) == 0);
-                    task->cbs.parser->on_ended(task->item, task->preparse_status,
-                                               task->userdata);
+                    assert((req_itr->options & VLC_PREPARSER_TYPE_THUMBNAIL) == 0);
+                    req_itr->cbs.parser->on_ended(req_itr, req_itr->preparse_status,
+                                                  req_itr->userdata);
                 }
-                else if (task->options & VLC_PREPARSER_TYPE_THUMBNAIL)
+                else if (req_itr->options & VLC_PREPARSER_TYPE_THUMBNAIL)
                 {
-                    assert((task->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES) == 0);
-                    task->cbs.thumbnailer->on_ended(task->item,
-                                                    task->preparse_status, NULL,
-                                                    task->userdata);
+                    assert((req_itr->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES) == 0);
+                    req_itr->cbs.thumbnailer->on_ended(req_itr,
+                                                       req_itr->preparse_status, NULL,
+                                                       req_itr->userdata);
                 }
                 else
                 {
-                    assert(task->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES);
-                    task->cbs.thumbnailer_to_files->on_ended(task->item,
-                                                             task->preparse_status,
-                                                             NULL, 0,
-                                                             task->userdata);
+                    assert(req_itr->options & VLC_PREPARSER_TYPE_THUMBNAIL_TO_FILES);
+                    req_itr->cbs.thumbnailer_to_files->on_ended(req_itr,
+                                                                req_itr->preparse_status,
+                                                                NULL, 0,
+                                                                req_itr->userdata);
                 }
-                TaskDelete(task);
+                vlc_preparser_req_Release(req_itr);
 
                 /* Small optimisation in the likely case where the user cancel
                  * only one task */
-                if (id != VLC_PREPARSER_REQ_ID_INVALID)
+                if (req != NULL)
                     return count;
                 vlc_mutex_lock(&preparser->lock);
             }
             else
                 /* The task will be finished and destroyed after run() */
-                Interrupt(task);
+                Interrupt(req_itr);
         }
     }
 
@@ -939,16 +929,31 @@ size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req_id id
     return count;
 }
 
+input_item_t *vlc_preparser_req_GetItem(vlc_preparser_req *req)
+{
+    assert(req != NULL);
+    return req->item;
+}
+
 void vlc_preparser_SetTimeout( vlc_preparser_t *preparser,
                                vlc_tick_t timeout )
 {
     preparser->timeout = timeout;
 }
 
+void vlc_preparser_req_Release( vlc_preparser_req *req )
+{
+    assert(req != NULL);
+    if (!vlc_atomic_rc_dec(&req->rc))
+        return;
+
+    PreparserRequestDelete(req);
+}
+
 void vlc_preparser_Delete( vlc_preparser_t *preparser )
 {
     /* In case vlc_preparser_Deactivate() has not been called */
-    vlc_preparser_Cancel(preparser, 0);
+    vlc_preparser_Cancel(preparser, NULL);
 
     if (preparser->parser != NULL)
         vlc_executor_Delete(preparser->parser);


=====================================
test/libvlc/media.c
=====================================
@@ -208,24 +208,24 @@ static void test_media_tracks(libvlc_instance_t *vlc)
     libvlc_media_release (media);
 }
 
-static void input_item_preparse_timeout( input_item_t *item,
+static void input_item_preparse_timeout( vlc_preparser_req *req,
                                          int status, void *user_data )
 {
-    VLC_UNUSED(item);
     vlc_sem_t *p_sem = user_data;
 
     assert( status == VLC_ETIMEOUT );
     vlc_sem_post(p_sem);
+    vlc_preparser_req_Release(req);
 }
 
-static void input_item_preparse_cancel( input_item_t *item,
+static void input_item_preparse_cancel( vlc_preparser_req *req,
                                         int status, void *user_data )
 {
-    VLC_UNUSED(item);
     vlc_sem_t *p_sem = user_data;
 
     assert( status == -EINTR );
     vlc_sem_post(p_sem);
+    vlc_preparser_req_Release(req);
 }
 
 static void test_input_metadata_timeout(libvlc_instance_t *vlc, int timeout,
@@ -246,7 +246,7 @@ static void test_input_metadata_timeout(libvlc_instance_t *vlc, int timeout,
 
     vlc_sem_t sem;
     vlc_sem_init (&sem, 0);
-    const input_item_parser_cbs_t cbs = {
+    const struct vlc_preparser_cbs cbs = {
         .on_ended = wait_and_cancel > 0 ? input_item_preparse_cancel
                                         : input_item_preparse_timeout,
     };
@@ -261,13 +261,13 @@ static void test_input_metadata_timeout(libvlc_instance_t *vlc, int timeout,
     vlc_preparser_t *parser = vlc_preparser_New(VLC_OBJECT(vlc->p_libvlc_int),
                                                 &cfg);
     assert(parser != NULL);
-    vlc_preparser_req_id id = vlc_preparser_Push(parser, p_item, options, &cbs, &sem);
-    assert(id != VLC_PREPARSER_REQ_ID_INVALID);
+    vlc_preparser_req *req = vlc_preparser_Push(parser, p_item, options, &cbs, &sem);
+    assert(req != NULL);
 
     if (wait_and_cancel > 0)
     {
         vlc_tick_sleep( VLC_TICK_FROM_MS(wait_and_cancel) );
-        size_t count = vlc_preparser_Cancel(parser, id);
+        size_t count = vlc_preparser_Cancel(parser, req);
         assert(count == 1);
     }
     vlc_sem_wait(&sem);


=====================================
test/src/preparser/thumbnail.c
=====================================
@@ -68,10 +68,9 @@ struct test_ctx
     bool b_done;
 };
 
-static void thumbnailer_callback( input_item_t *item, int status,
+static void thumbnailer_callback( vlc_preparser_req *req, int status,
                                   picture_t* thumbnail, void *data )
 {
-    (void) item;
     struct test_ctx* p_ctx = data;
     vlc_mutex_lock( &p_ctx->lock );
 
@@ -113,6 +112,7 @@ static void thumbnailer_callback( input_item_t *item, int status,
     p_ctx->b_done = true;
     vlc_cond_signal( &p_ctx->cond );
     vlc_mutex_unlock( &p_ctx->lock );
+    vlc_preparser_req_Release( req );
 }
 
 static void test_thumbnails( libvlc_instance_t* p_vlc )
@@ -150,7 +150,7 @@ static void test_thumbnails( libvlc_instance_t* p_vlc )
 
         vlc_mutex_lock( &ctx.lock );
 
-        vlc_preparser_req_id id;
+        vlc_preparser_req *req;
         struct vlc_thumbnailer_arg thumb_arg;
         if ( test_params[i].b_use_pos )
         {
@@ -170,9 +170,9 @@ static void test_thumbnails( libvlc_instance_t* p_vlc )
         static const struct vlc_thumbnailer_cbs cbs = {
             .on_ended = thumbnailer_callback,
         };
-        id = vlc_preparser_GenerateThumbnail( p_thumbnailer, p_item, &thumb_arg,
-                                              &cbs, &ctx );
-        assert( id != VLC_PREPARSER_REQ_ID_INVALID );
+        req = vlc_preparser_GenerateThumbnail( p_thumbnailer, p_item, &thumb_arg,
+                                               &cbs, &ctx );
+        assert( req != NULL );
 
         while ( ctx.b_done == false )
             vlc_cond_wait( &ctx.cond, &ctx.lock );
@@ -186,15 +186,15 @@ static void test_thumbnails( libvlc_instance_t* p_vlc )
     }
 }
 
-static void thumbnailer_callback_cancel( input_item_t *item, int status,
+static void thumbnailer_callback_cancel( vlc_preparser_req *req, int status,
                                          picture_t* p_thumbnail, void *data )
 {
-    (void) item;
     assert( p_thumbnail == NULL );
     assert( status == -EINTR );
 
     vlc_sem_t *sem = data;
     vlc_sem_post(sem);
+    vlc_preparser_req_Release(req);
 }
 
 static void test_cancel_thumbnail( libvlc_instance_t* p_vlc )
@@ -220,10 +220,10 @@ static void test_cancel_thumbnail( libvlc_instance_t* p_vlc )
 
     vlc_sem_t sem;
     vlc_sem_init(&sem, 0);
-    vlc_preparser_req_id id =
+    vlc_preparser_req *req =
         vlc_preparser_GenerateThumbnail( p_thumbnailer, p_item, NULL, &cbs, &sem );
 
-    vlc_preparser_Cancel( p_thumbnailer, id );
+    vlc_preparser_Cancel( p_thumbnailer, req );
 
     vlc_sem_wait(&sem);
 


=====================================
test/src/preparser/thumbnail_to_files.c
=====================================
@@ -82,8 +82,9 @@ struct context
     vlc_sem_t sem;
 };
 
-static void parser_on_ended(input_item_t *item, int status, void *userdata)
+static void parser_on_ended(vlc_preparser_req *req, int status, void *userdata)
 {
+    input_item_t *item = vlc_preparser_req_GetItem(req);
     struct context *context = userdata;
     assert(status == VLC_SUCCESS);
 
@@ -111,17 +112,17 @@ static void parser_on_ended(input_item_t *item, int status, void *userdata)
     assert(es_fmt->video.i_height == test_entry->out_height);
 
     vlc_sem_post(&context->sem);
+    vlc_preparser_req_Release(req);
 }
 
-static void on_ended(input_item_t *item, int status,
+static void on_ended(vlc_preparser_req *req, int status,
                      const bool *result_array, size_t result_count, void *data)
 {
     struct context *context = data;
-    (void) item;
     assert(status == VLC_SUCCESS);
     assert(context->test_count == result_count);
 
-    static const struct input_item_parser_cbs_t parser_cbs = {
+    static const struct vlc_preparser_cbs parser_cbs = {
         .on_ended = parser_on_ended,
     };
 
@@ -154,14 +155,15 @@ static void on_ended(input_item_t *item, int status,
                 free(option);
             }
 
-            vlc_preparser_req_id req_id =
+            vlc_preparser_req *req =
                 vlc_preparser_Push(context->preparser, thumb,
                                    VLC_PREPARSER_TYPE_PARSE,
                                    &parser_cbs, context);
-            assert(req_id != VLC_PREPARSER_REQ_ID_INVALID);
+            assert(req != NULL);
             input_item_Release(thumb);
         }
     }
+    vlc_preparser_req_Release(req);
 }
 
 static int get_formats(enum vlc_thumbnailer_format *out_format,
@@ -329,18 +331,18 @@ int main(int argc, const char *argv[])
     input_item_t *item = input_item_New(MOCK_URL, "mock");
     assert(item != NULL);
 
-    vlc_preparser_req_id req_id =
+    vlc_preparser_req *req =
         vlc_preparser_GenerateThumbnailToFiles(preparser, item, &arg,
                                                entries, test_count,
                                                &cbs, &context);
 
-    assert(req_id != VLC_PREPARSER_REQ_ID_INVALID);
+    assert(req != NULL);
 
     /* Wait for all tests */
     for (size_t i = 0; i < test_count; ++i)
         vlc_sem_wait(&context.sem);
 
-    size_t count = vlc_preparser_Cancel(preparser, req_id);
+    size_t count = vlc_preparser_Cancel(preparser, req);
     assert(count == 0); /* Should not be cancelled and already processed */
 
     for (size_t i = 0; i < test_count; ++i)



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/39ec5d6db26c7314fc6c1ec4b721238d73f03603...52c61546c2f84a39ad91ef5a4780344014da0455

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/39ec5d6db26c7314fc6c1ec4b721238d73f03603...52c61546c2f84a39ad91ef5a4780344014da0455
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list