[vlc-commits] [Git][videolan/vlc][master] 21 commits: preparser: rework option and type flags

Steve Lhomme (@robUx4) gitlab at videolan.org
Sat Nov 9 15:58:46 UTC 2024



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
b0843bee by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: rework option and type flags

Separate Push options from creation types. use defines.

- - - - -
f9c3fe23 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: rename executor to parser

- - - - -
f6408e3a by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: re-order code

- - - - -
ba00b0f0 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: rework allocation error handling

- - - - -
0d3f8ff9 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: ensure parser.on_ended callback is valid

And that cbs is valid.

- - - - -
3358a579 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: pass runnable in TaskNew args

And remove the forward declaration.

- - - - -
202e3db0 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: rename RunnableRun

- - - - -
3d4d8503 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: move local variable from struct

- - - - -
e3f9129a by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: don't fetch if parsing was interrupted

- - - - -
702c98b5 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: call callback directly when interrupted

- - - - -
d1970794 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: use VLC_PREPARSER_REQ_ID_INVALID on error

- - - - -
e98fbb7f by Thomas Guillem at 2024-11-09T15:24:26+00:00
media_tree: fix missing return from tests

- - - - -
da62fe9b by Thomas Guillem at 2024-11-09T15:24:26+00:00
test: thumbnailer: remove sleep and wrong comments

A callback is now called when cancelled.

- - - - -
6aa76771 by Thomas Guillem at 2024-11-09T15:24:26+00:00
thumbnailer: rename task and functions

Temporary renaming to ease the future merge of preparser.c and
thumbnailer.c

- - - - -
39cf32ce by Thomas Guillem at 2024-11-09T15:24:26+00:00
thumbnailer: use the same sync mechanism than the preparser

- - - - -
d2a0c1de by Thomas Guillem at 2024-11-09T15:24:26+00:00
thumbnailer: report status from callback

Imitate the preparser callback.

- - - - -
3c1cc504 by Thomas Guillem at 2024-11-09T15:24:26+00:00
thumbnailer: move to preparser

Both code will be fusionned in the next commit.

No functional changes.

- - - - -
a4a0514e by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: merge with the thumbnailer API

You should now use a preparser to generate thumbnails.

One single preparser is able to:
 - Parse
 - Fetch meta
 - Generate thumbnails

Using 3 different queues. It is also possible to create a preparser for
only one type of processing.

- - - - -
5942c80b by Thomas Guillem at 2024-11-09T15:24:26+00:00
test: move input/thumbnail.c

- - - - -
dcea76e4 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: add a struct to configure the preparser

- - - - -
f9b455e7 by Thomas Guillem at 2024-11-09T15:24:26+00:00
preparser: add max_thumbnailer_threads in config struct

- - - - -


26 changed files:

- include/meson.build
- include/vlc_preparser.h
- − include/vlc_thumbnailer.h
- lib/core.c
- lib/libvlc_internal.h
- lib/media.c
- modules/gui/macosx/main/VLCMain.m
- modules/gui/qt/maininterface/mainctx.cpp
- modules/gui/qt/medialibrary/mlvideo.cpp
- modules/gui/qt/player/player_controller.cpp
- modules/misc/medialibrary/Thumbnailer.cpp
- modules/misc/medialibrary/medialibrary.h
- src/Makefile.am
- − src/input/thumbnailer.c
- src/libvlccore.sym
- src/media_source/media_tree.c
- src/meson.build
- src/playlist/playlist.c
- src/playlist/preparse.c
- src/preparser/fetcher.c
- src/preparser/fetcher.h
- src/preparser/preparser.c
- test/Makefile.am
- test/libvlc/media.c
- test/src/meson.build
- test/src/input/thumbnail.c → test/src/preparser/thumbnail.c


Changes:

=====================================
include/meson.build
=====================================
@@ -101,7 +101,6 @@ install_headers(
     'vlc_subpicture.h',
     'vlc_text_style.h',
     'vlc_threads.h',
-    'vlc_thumbnailer.h',
     'vlc_tick.h',
     'vlc_timestamp_helper.h',
     'vlc_tls.h',


=====================================
include/vlc_preparser.h
=====================================
@@ -46,33 +46,119 @@ typedef size_t vlc_preparser_req_id;
 
 #define VLC_PREPARSER_REQ_ID_INVALID 0
 
-typedef enum input_item_meta_request_option_t
+#define VLC_PREPARSER_TYPE_PARSE            0x01
+#define VLC_PREPARSER_TYPE_FETCHMETA_LOCAL  0x02
+#define VLC_PREPARSER_TYPE_FETCHMETA_NET    0x04
+#define VLC_PREPARSER_TYPE_THUMBNAIL        0x08
+#define VLC_PREPARSER_TYPE_FETCHMETA_ALL \
+    (VLC_PREPARSER_TYPE_FETCHMETA_LOCAL|VLC_PREPARSER_TYPE_FETCHMETA_NET)
+
+#define VLC_PREPARSER_OPTION_INTERACT 0x1000
+#define VLC_PREPARSER_OPTION_SUBITEMS 0x2000
+
+/** Preparser thumbnailer callbacks */
+struct vlc_thumbnailer_cbs
+{
+    /**
+     * Event received on thumbnailing completion or error
+     *
+     * This callback will always be called, provided
+     * vlc_preparser_GenerateThumbnail() returned a valid request, and provided
+     * the request is not cancelled before its completion.
+     *
+     * @note This callback is mandatory if calling
+     * vlc_preparser_GenerateThumbnail()
+     *
+     * In case of failure, timeout or cancellation, p_thumbnail will be NULL.
+     * The picture, if any, is owned by the thumbnailer, and must be acquired
+     * by using \link picture_Hold \endlink to use it pass the callback's
+     * scope.
+     *
+     * @param item item used for the thumbnailer
+     *
+     * @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
+     * timeout
+     *
+     * @param data opaque pointer passed by
+     * vlc_preparser_GenerateThumbnail()
+     *
+     */
+    void (*on_ended)(input_item_t *item, int status, picture_t* thumbnail,
+                     void *data);
+};
+
+/**
+ * Preparser seek argument
+ */
+struct vlc_preparser_seek_arg
 {
-    META_REQUEST_OPTION_NONE          = 0x00,
-    META_REQUEST_OPTION_PARSE         = 0x01,
-    META_REQUEST_OPTION_FETCH_LOCAL   = 0x02,
-    META_REQUEST_OPTION_FETCH_NETWORK = 0x04,
-    META_REQUEST_OPTION_FETCH_ANY     =
-        META_REQUEST_OPTION_FETCH_LOCAL|META_REQUEST_OPTION_FETCH_NETWORK,
-    META_REQUEST_OPTION_DO_INTERACT   = 0x08,
-    META_REQUEST_OPTION_PARSE_SUBITEMS = 0x10,
-} input_item_meta_request_option_t;
+    enum
+    {
+        /** Don't seek */
+        VLC_PREPARSER_SEEK_NONE,
+        /** Seek by time */
+        VLC_PREPARSER_SEEK_TIME,
+        /** Seek by position */
+        VLC_PREPARSER_SEEK_POS,
+    } type;
+    union
+    {
+        /** Seek time if type == VLC_PREPARSER_SEEK_TIME */
+        vlc_tick_t time;
+        /** Seek position if type == VLC_PREPARSER_SEEK_POS */
+        double pos;
+    };
+    enum
+    {
+        /** Precise, but potentially slow */
+        VLC_PREPARSER_SEEK_PRECISE,
+        /** Fast, but potentially imprecise */
+        VLC_PREPARSER_SEEK_FAST,
+    } speed;
+};
+
+/**
+ * Preparser creation configuration
+ */
+struct vlc_preparser_cfg
+{
+    /**
+     * A combination of VLC_PREPARSER_TYPE_* flags, it is used to
+     * setup the executors for each domain. Its possible to select more than
+     * one type
+     */
+    int types;
+
+    /**
+     * The maximum number of threads used by the parser, 0 for default
+     * (1 thread)
+     */
+    unsigned max_parser_threads;
+
+    /**
+     * The maximum number of threads used by the thumbnailer, 0 for default
+     * (1 thread)
+     */
+    unsigned max_thumbnailer_threads;
+
+    /**
+     * Timeout of the preparser and/or thumbnailer, 0 for no limits.
+     */
+    vlc_tick_t timeout;
+};
 
 /**
  * This function creates the preparser object and thread.
  *
  * @param obj the parent object
- * @param max_threads the maximum number of threads used to parse, must be >= 1
- * @param timeout timeout of the preparser, 0 for no limits.
- * @param request_type a combination of META_REQUEST_OPTION_PARSE,
- * META_REQUEST_OPTION_FETCH_LOCAL and META_REQUEST_OPTION_FETCH_NETWORK, it is
- * used to setup the executors for each domain.
+ * @param cfg a pointer to a valid confiuration struct
  * @return a valid preparser object or NULL in case of error
  */
 VLC_API vlc_preparser_t *vlc_preparser_New( vlc_object_t *obj,
-                                            unsigned max_threads,
-                                            vlc_tick_t timeout,
-                                            input_item_meta_request_option_t request_type );
+                                            const struct vlc_preparser_cfg *cfg );
 
 /**
  * This function enqueues the provided item to be preparsed or fetched.
@@ -82,7 +168,9 @@ VLC_API vlc_preparser_t *vlc_preparser_New( vlc_object_t *obj,
  *
  * @param preparser the preparser object
  * @param item a valid item to preparse
- * @param option preparse flag, cf @ref input_item_meta_request_option_t
+ * @param type_option a combination of VLC_PREPARSER_TYPE_* and
+ * VLC_PREPARSER_OPTION_* flags. The type must be in the set specified in
+ * 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
@@ -92,10 +180,32 @@ VLC_API vlc_preparser_t *vlc_preparser_New( vlc_object_t *obj,
  * error, the on_preparse_ended will *not* be invoked
  */
 VLC_API vlc_preparser_req_id
-vlc_preparser_Push( vlc_preparser_t *preparser, input_item_t *item,
-                    input_item_meta_request_option_t option,
+vlc_preparser_Push( vlc_preparser_t *preparser, input_item_t *item, int type_option,
                     const input_item_parser_cbs_t *cbs, void *cbs_userdata );
 
+/**
+ * This function enqueues the provided item for generating a thumbnail
+ *
+ * @param preparser the preparser object
+ * @param item a valid item to generate the thumbnail for
+ * @param seek_arg pointer to a seek struct, that tell at which time the
+ * thumbnail should be taken, NULL to disable seek
+ * @param timeout A timeout value, or VLC_TICK_INVALID to disable timeout
+ * @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
+ * 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_preparser_GenerateThumbnail( vlc_preparser_t *preparser, input_item_t *item,
+                                 const struct vlc_preparser_seek_arg *seek_arg,
+                                 const struct vlc_thumbnailer_cbs *cbs,
+                                 void *cbs_userdata );
+
 /**
  * This function cancel all preparsing requests for a given id
  *


=====================================
include/vlc_thumbnailer.h deleted
=====================================
@@ -1,145 +0,0 @@
-/*****************************************************************************
- * vlc_thumbnailer.h: Thumbnailing API
- *****************************************************************************
- * Copyright (C) 2018 VLC authors and VideoLAN
- *
- * Authors: Hugo Beauzée-Luyssen <hugo at beauzee.fr>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#ifndef VLC_THUMBNAILER_H
-#define VLC_THUMBNAILER_H
-
-#include <vlc_common.h>
-#include <vlc_tick.h>
-
-typedef struct vlc_thumbnailer_t vlc_thumbnailer_t;
-typedef size_t vlc_thumbnailer_req_id;
-
-#define VLC_THUMBNAILER_REQ_ID_INVALID 0
-
-/**
- * thumbnailer callbacks
- */
-struct vlc_thumbnailer_cbs
-{
-    /**
-     * Event received on thumbnailing completion or error
-     *
-     * This callback will always be called, provided vlc_thumbnailer_Request
-     * returned a valid request, and provided the request is not cancelled
-     * before its completion.
-     *
-     * @note This callback is mandatory.
-     *
-     * In case of failure, timeout or cancellation, p_thumbnail will be NULL.
-     * The picture, if any, is owned by the thumbnailer, and must be acquired
-     * by using \link picture_Hold \endlink to use it pass the callback's
-     * scope.
-     *
-     * \param thumbnail The generated thumbnail, or NULL in case of failure or
-     * timeout
-     * \param data Is the opaque pointer passed as vlc_thumbnailer_Request last
-     * parameter
-     */
-    void (*on_ended)(picture_t* thumbnail, void *data);
-};
-
-/**
- * \brief vlc_thumbnailer_Create Creates a thumbnailer object
- * \param parent A VLC object
- * @param timeout timeout of the thumbnailer, 0 for no limits.
- * \return A thumbnailer object, or NULL in case of failure
- */
-VLC_API vlc_thumbnailer_t*
-vlc_thumbnailer_Create(vlc_object_t* parent, vlc_tick_t timeout) VLC_USED;
-
-/**
- * Thumbnailer seek argument
- */
-struct vlc_thumbnailer_seek_arg
-{
-    enum
-    {
-        /** Don't seek */
-        VLC_THUMBNAILER_SEEK_NONE,
-        /** Seek by time */
-        VLC_THUMBNAILER_SEEK_TIME,
-        /** Seek by position */
-        VLC_THUMBNAILER_SEEK_POS,
-    } type;
-    union
-    {
-        /** Seek time if type == VLC_THUMBNAILER_SEEK_TIME */
-        vlc_tick_t time;
-        /** Seek position if type == VLC_THUMBNAILER_SEEK_POS */
-        double pos;
-    };
-    enum
-    {
-        /** Precise, but potentially slow */
-        VLC_THUMBNAILER_SEEK_PRECISE,
-        /** Fast, but potentially imprecise */
-        VLC_THUMBNAILER_SEEK_FAST,
-    } speed;
-};
-
-/**
- * \brief vlc_thumbnailer_Request Requests a thumbnailer
- * \param thumbnailer A thumbnailer object
- * \param input_item The input item to generate the thumbnail for
- * \param seek_arg pointer to a seek struct, that tell at which time the
- * thumbnail should be taken, NULL to disable seek
- * \param timeout A timeout value, or VLC_TICK_INVALID to disable timeout
- * \param cbs callback to listen to events (can't be NULL)
- * \param cbs_userdata opaque pointer used by the callbacks
- * \return VLC_THUMBNAILER_REQ_ID_INVALID in case of error, or a valid id if the
- * item was scheduled for thumbnailing. If this returns an
- * error, the 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_thumbnailer_req_id
-vlc_thumbnailer_Request( vlc_thumbnailer_t *thumbnailer,
-                         input_item_t *input_item,
-                         const struct vlc_thumbnailer_seek_arg *seek_arg,
-                         const struct vlc_thumbnailer_cbs *cbs,
-                         void *cbs_userdata );
-
-/**
- * \brief vlc_thumbnailer_Camcel Cancel a thumbnail request
- * \param thumbnailer A thumbnailer object
- * \param id unique id returned by vlc_thumbnailer_Request*(),
- * VLC_THUMBNAILER_REQ_ID_INVALID to cancels all tasks
- * \return number of tasks cancelled
- */
-VLC_API size_t
-vlc_thumbnailer_Cancel( vlc_thumbnailer_t* thumbnailer, vlc_thumbnailer_req_id id );
-
-/**
- * \brief vlc_thumbnailer_Delete Deletes a thumbnailer and cancel all pending requests
- * \param thumbnailer A thumbnailer object
- */
-VLC_API void vlc_thumbnailer_Delete( vlc_thumbnailer_t* thumbnailer );
-
-/**
- * Do not use, libVLC only fonction, will be removed soon
- */
-VLC_API void vlc_thumbnailer_SetTimeout( vlc_thumbnailer_t *thumbnailer,
-                                         vlc_tick_t timeout ) VLC_DEPRECATED;
-
-#endif // VLC_THUMBNAILER_H


=====================================
lib/core.c
=====================================
@@ -29,7 +29,6 @@
 #include <vlc/vlc.h>
 
 #include <vlc_preparser.h>
-#include <vlc_thumbnailer.h>
 #include <vlc_interface.h>
 
 #include <stdarg.h>
@@ -110,7 +109,7 @@ void libvlc_release( libvlc_instance_t *p_instance )
         if (p_instance->parser != NULL)
             vlc_preparser_Delete(p_instance->parser);
         if (p_instance->thumbnailer != NULL)
-            vlc_thumbnailer_Delete(p_instance->thumbnailer);
+            vlc_preparser_Delete(p_instance->thumbnailer);
 
         libvlc_InternalCleanup( p_instance->p_libvlc_int );
         libvlc_InternalDestroy( p_instance->p_libvlc_int );
@@ -266,26 +265,34 @@ vlc_preparser_t *libvlc_get_preparser(libvlc_instance_t *instance)
         if (default_timeout < 0)
             default_timeout = 0;
 
+        const struct vlc_preparser_cfg cfg = {
+            .types = VLC_PREPARSER_TYPE_PARSE | VLC_PREPARSER_TYPE_FETCHMETA_ALL,
+            .max_parser_threads = max_threads,
+            .timeout = default_timeout,
+        };
+
         parser = instance->parser =
-            vlc_preparser_New(VLC_OBJECT(instance->p_libvlc_int), max_threads,
-                              default_timeout,
-                              META_REQUEST_OPTION_PARSE |
-                              META_REQUEST_OPTION_FETCH_ANY);
+            vlc_preparser_New(VLC_OBJECT(instance->p_libvlc_int), &cfg);
     }
     vlc_mutex_unlock(&instance->lazy_init_lock);
 
     return parser;
 }
 
-vlc_thumbnailer_t *libvlc_get_thumbnailer(libvlc_instance_t *instance)
+vlc_preparser_t *libvlc_get_thumbnailer(libvlc_instance_t *instance)
 {
     vlc_mutex_lock(&instance->lazy_init_lock);
-    vlc_thumbnailer_t *thumb = instance->thumbnailer;
+    vlc_preparser_t *thumb = instance->thumbnailer;
 
     if (thumb == NULL)
     {
+        const struct vlc_preparser_cfg cfg = {
+            .types = VLC_PREPARSER_TYPE_THUMBNAIL,
+            .timeout = 0,
+        };
+
         thumb = instance->thumbnailer =
-            vlc_thumbnailer_Create(VLC_OBJECT(instance->p_libvlc_int), 0);
+            vlc_preparser_New(VLC_OBJECT(instance->p_libvlc_int), &cfg);
     }
     vlc_mutex_unlock(&instance->lazy_init_lock);
 


=====================================
lib/libvlc_internal.h
=====================================
@@ -36,7 +36,7 @@
 #include <vlc_threads.h>
 
 typedef struct vlc_preparser_t vlc_preparser_t;
-typedef struct vlc_thumbnailer_t vlc_thumbnailer_t;
+typedef struct vlc_preparser_t vlc_preparser_t;
 
 /* Note well: this header is included from LibVLC core.
  * Therefore, static inline functions MUST NOT call LibVLC functions here
@@ -105,7 +105,7 @@ struct libvlc_instance_t
 
     vlc_mutex_t lazy_init_lock;
     vlc_preparser_t *parser;
-    vlc_thumbnailer_t *thumbnailer;
+    vlc_preparser_t *thumbnailer;
 
     struct
     {
@@ -153,6 +153,6 @@ static inline vlc_tick_t vlc_tick_from_libvlc_time(libvlc_time_t time)
 }
 
 vlc_preparser_t *libvlc_get_preparser(libvlc_instance_t *instance);
-vlc_thumbnailer_t *libvlc_get_thumbnailer(libvlc_instance_t *instance);
+vlc_preparser_t *libvlc_get_thumbnailer(libvlc_instance_t *instance);
 
 #endif


=====================================
lib/media.c
=====================================
@@ -37,7 +37,6 @@
 #include <vlc_common.h>
 #include <vlc_meta.h>
 #include <vlc_url.h>
-#include <vlc_thumbnailer.h>
 #include <vlc_atomic.h>
 
 #include "../src/libvlc.h"
@@ -741,7 +740,7 @@ int libvlc_media_parse_request(libvlc_instance_t *inst, libvlc_media_t *media,
         return -1;
 
     input_item_t *item = media->p_input_item;
-    input_item_meta_request_option_t parse_scope = 0;
+    int parse_scope = 0;
     unsigned int ref = atomic_load_explicit(&media->worker_count,
                                             memory_order_relaxed);
     do
@@ -784,17 +783,17 @@ int libvlc_media_parse_request(libvlc_instance_t *inst, libvlc_media_t *media,
     }
 
     if (do_parse)
-        parse_scope |= META_REQUEST_OPTION_PARSE;
+        parse_scope |= VLC_PREPARSER_TYPE_PARSE;
 
     do_fetch = false;
     if (parse_flag & libvlc_media_fetch_local)
     {
-        parse_scope |= META_REQUEST_OPTION_FETCH_LOCAL;
+        parse_scope |= VLC_PREPARSER_TYPE_FETCHMETA_LOCAL;
         do_fetch = true;
     }
     if (parse_flag & libvlc_media_fetch_network)
     {
-        parse_scope |= META_REQUEST_OPTION_FETCH_NETWORK;
+        parse_scope |= VLC_PREPARSER_TYPE_FETCHMETA_NET;
         do_fetch = true;
     }
 
@@ -807,8 +806,8 @@ int libvlc_media_parse_request(libvlc_instance_t *inst, libvlc_media_t *media,
     }
 
     if (parse_flag & libvlc_media_do_interact)
-        parse_scope |= META_REQUEST_OPTION_DO_INTERACT;
-    parse_scope |= META_REQUEST_OPTION_PARSE_SUBITEMS;
+        parse_scope |= VLC_PREPARSER_OPTION_INTERACT;
+    parse_scope |= VLC_PREPARSER_OPTION_SUBITEMS;
 
     if (timeout == -1)
         timeout = var_InheritInteger(inst->p_libvlc_int, "preparse-timeout");
@@ -924,11 +923,15 @@ struct libvlc_media_thumbnail_request_t
     unsigned int height;
     bool crop;
     libvlc_picture_type_t type;
-    vlc_thumbnailer_req_id id;
+    vlc_preparser_req_id id;
 };
 
-static void media_on_thumbnail_ready( picture_t* thumbnail, void* data )
+static void media_on_thumbnail_ready( input_item_t *item, int status,
+                                      picture_t* thumbnail, void* data )
 {
+    (void) item;
+    (void) status;
+
     libvlc_media_thumbnail_request_t *req = data;
     libvlc_media_t *p_media = req->md;
     libvlc_event_t event;
@@ -948,18 +951,18 @@ static void media_on_thumbnail_ready( picture_t* thumbnail, void* data )
 static libvlc_media_thumbnail_request_t*
 libvlc_media_thumbnail_request( libvlc_instance_t *inst,
                                 libvlc_media_t *md,
-                                const struct vlc_thumbnailer_seek_arg *seek_arg,
+                                const struct vlc_preparser_seek_arg *seek_arg,
                                 unsigned int width, unsigned int height,
                                 bool crop, libvlc_picture_type_t picture_type,
                                 libvlc_time_t timeout )
 {
     assert( md );
 
-    vlc_thumbnailer_t *thumb = libvlc_get_thumbnailer(inst);
+    vlc_preparser_t *thumb = libvlc_get_thumbnailer(inst);
     if (unlikely(thumb == NULL))
         return NULL;
 
-    vlc_thumbnailer_SetTimeout( thumb, vlc_tick_from_libvlc_time( timeout ) );
+    vlc_preparser_SetTimeout( thumb, vlc_tick_from_libvlc_time( timeout ) );
 
     libvlc_media_thumbnail_request_t *req = malloc( sizeof( *req ) );
     if ( unlikely( req == NULL ) )
@@ -975,8 +978,8 @@ libvlc_media_thumbnail_request( libvlc_instance_t *inst,
     static const struct vlc_thumbnailer_cbs cbs = {
         .on_ended = media_on_thumbnail_ready,
     };
-    req->id = vlc_thumbnailer_Request( thumb, md->p_input_item, seek_arg,
-                                       &cbs, req );
+    req->id = vlc_preparser_GenerateThumbnail( thumb, md->p_input_item, seek_arg,
+                                               &cbs, req );
     if ( req->id == VLC_PREPARSER_REQ_ID_INVALID )
     {
         free( req );
@@ -995,11 +998,11 @@ libvlc_media_thumbnail_request_by_time( libvlc_instance_t *inst,
                                         bool crop, libvlc_picture_type_t picture_type,
                                         libvlc_time_t timeout )
 {
-    const struct vlc_thumbnailer_seek_arg seek_arg = {
-        .type = VLC_THUMBNAILER_SEEK_TIME,
+    const struct vlc_preparser_seek_arg seek_arg = {
+        .type = VLC_PREPARSER_SEEK_TIME,
         .time = vlc_tick_from_libvlc_time( time ),
         .speed = speed == libvlc_media_thumbnail_seek_fast ?
-            VLC_THUMBNAILER_SEEK_FAST : VLC_THUMBNAILER_SEEK_PRECISE,
+            VLC_PREPARSER_SEEK_FAST : VLC_PREPARSER_SEEK_PRECISE,
     };
     return libvlc_media_thumbnail_request( inst, md, &seek_arg, width, height,
                                            crop, picture_type, timeout );
@@ -1014,11 +1017,11 @@ libvlc_media_thumbnail_request_by_pos( libvlc_instance_t *inst,
                                        bool crop, libvlc_picture_type_t picture_type,
                                        libvlc_time_t timeout )
 {
-    const struct vlc_thumbnailer_seek_arg seek_arg = {
-        .type = VLC_THUMBNAILER_SEEK_POS,
+    const struct vlc_preparser_seek_arg seek_arg = {
+        .type = VLC_PREPARSER_SEEK_POS,
         .pos = pos,
         .speed = speed == libvlc_media_thumbnail_seek_fast ?
-            VLC_THUMBNAILER_SEEK_FAST : VLC_THUMBNAILER_SEEK_PRECISE,
+            VLC_PREPARSER_SEEK_FAST : VLC_PREPARSER_SEEK_PRECISE,
     };
     return libvlc_media_thumbnail_request( inst, md, &seek_arg, width, height,
                                            crop, picture_type, timeout );
@@ -1027,10 +1030,10 @@ libvlc_media_thumbnail_request_by_pos( libvlc_instance_t *inst,
 // Destroy a thumbnail request
 void libvlc_media_thumbnail_request_destroy( libvlc_media_thumbnail_request_t *req )
 {
-    vlc_thumbnailer_t *thumb = libvlc_get_thumbnailer(req->instance);
+    vlc_preparser_t *thumb = libvlc_get_thumbnailer(req->instance);
     assert(thumb != NULL);
 
-    vlc_thumbnailer_Cancel( thumb, req->id );
+    vlc_preparser_Cancel( thumb, req->id );
     libvlc_media_release( req->md );
     libvlc_release(req->instance);
     free( req );


=====================================
modules/gui/macosx/main/VLCMain.m
=====================================
@@ -155,8 +155,12 @@ int OpenIntf (vlc_object_t *p_this)
             intf_thread_t *p_intf = (intf_thread_t*) p_this;
             p_interface_thread = p_intf;
 
-            p_network_preparser = vlc_preparser_New(p_this, 1, 0,
-                                                    META_REQUEST_OPTION_PARSE);
+            const struct vlc_preparser_cfg cfg = {
+                .types = VLC_PREPARSER_TYPE_PARSE,
+                .max_parser_threads = 1,
+                .timeout = 0,
+            };
+            p_network_preparser = vlc_preparser_New(p_this, &cfg);
             if (p_network_preparser == nil)
             {
                 retcode = VLC_ENOMEM;


=====================================
modules/gui/qt/maininterface/mainctx.cpp
=====================================
@@ -251,8 +251,14 @@ MainCtx::MainCtx(qt_intf_t *_p_intf)
         QMetaObject::invokeMethod(m_medialib, &MediaLib::reload, Qt::QueuedConnection);
     }
 
-    m_network_preparser = vlc_preparser_New(VLC_OBJECT(libvlc), 1, 0,
-                                            META_REQUEST_OPTION_PARSE);
+    const struct vlc_preparser_cfg cfg = []{
+        struct vlc_preparser_cfg cfg{};
+        cfg.types = VLC_PREPARSER_TYPE_PARSE;
+        cfg.max_parser_threads = 1;
+        cfg.timeout = 0;
+        return cfg;
+    }();
+    m_network_preparser = vlc_preparser_New(VLC_OBJECT(libvlc), &cfg);
 
 #ifdef UPDATE_CHECK
     /* Checking for VLC updates */


=====================================
modules/gui/qt/medialibrary/mlvideo.cpp
=====================================
@@ -20,7 +20,6 @@
 
 #include <cassert>
 
-#include <vlc_thumbnailer.h>
 #include "mlhelper.hpp"
 #include "util/vlctick.hpp"
 


=====================================
modules/gui/qt/player/player_controller.cpp
=====================================
@@ -1955,17 +1955,21 @@ void PlayerController::requestArtUpdate( input_item_t *p_item )
         if (default_timeout < 0)
             default_timeout = 0;
 
-        d->m_preparser = vlc_preparser_New(VLC_OBJECT(d->p_intf), 1,
-                                           default_timeout,
-                                           META_REQUEST_OPTION_FETCH_ANY);
+        const struct vlc_preparser_cfg cfg = [default_timeout]{
+            struct vlc_preparser_cfg cfg{};
+            cfg.types = VLC_PREPARSER_TYPE_FETCHMETA_ALL;
+            cfg.max_parser_threads = 1;
+            cfg.timeout = default_timeout;
+            return cfg;
+        }();
+        d->m_preparser = vlc_preparser_New(VLC_OBJECT(d->p_intf), &cfg);
         if (unlikely(d->m_preparser == nullptr))
             return;
     }
 
-    input_item_meta_request_option_t fetch_options =
-        var_InheritBool( d->p_intf, "metadata-network-access" ) ?
-            META_REQUEST_OPTION_FETCH_ANY :
-            META_REQUEST_OPTION_FETCH_LOCAL;
+    int fetch_options = var_InheritBool( d->p_intf, "metadata-network-access" ) ?
+            VLC_PREPARSER_TYPE_FETCHMETA_ALL :
+            VLC_PREPARSER_TYPE_FETCHMETA_LOCAL;
 
     vlc_preparser_Push( d->m_preparser, p_item, fetch_options,
                         &art_fetcher_cbs, d  );


=====================================
modules/misc/medialibrary/Thumbnailer.cpp
=====================================
@@ -24,26 +24,31 @@
 
 #include "medialibrary.h"
 
-#include <vlc_thumbnailer.h>
 #include <vlc_fs.h>
 #include <vlc_block.h>
 #include <vlc_url.h>
 #include <vlc_cxx_helpers.hpp>
+#include <vlc_preparser.h>
 
 #include <stdexcept>
 
 Thumbnailer::Thumbnailer( vlc_medialibrary_module_t* ml )
     : m_ml( ml )
     , m_currentContext( nullptr )
-    , m_thumbnailer( nullptr, &vlc_thumbnailer_Delete )
+    , m_thumbnailer( nullptr, &vlc_preparser_Delete )
 {
-    m_thumbnailer.reset( vlc_thumbnailer_Create( VLC_OBJECT( ml ),
-                                                  VLC_TICK_FROM_SEC( 3 ) ) );
+    const struct vlc_preparser_cfg cfg = []{
+        struct vlc_preparser_cfg cfg{};
+        cfg.types = VLC_PREPARSER_TYPE_THUMBNAIL;
+        cfg.timeout = VLC_TICK_FROM_SEC( 3 );
+        return cfg;
+    }();
+    m_thumbnailer.reset( vlc_preparser_New( VLC_OBJECT( ml ), &cfg ) );
     if ( unlikely( m_thumbnailer == nullptr ) )
-        throw std::runtime_error( "Failed to instantiate a vlc_thumbnailer_t" );
+        throw std::runtime_error( "Failed to instantiate a vlc_preparser_t" );
 }
 
-void Thumbnailer::onThumbnailComplete( picture_t* thumbnail, void *data )
+void Thumbnailer::onThumbnailComplete( input_item_t *, int, picture_t* thumbnail, void *data )
 {
     ThumbnailerCtx* ctx = static_cast<ThumbnailerCtx*>( data );
 
@@ -71,20 +76,20 @@ bool Thumbnailer::generate( const medialibrary::IMedia&, const std::string& mrl,
     {
         vlc::threads::mutex_locker lock( m_mutex );
         m_currentContext = &ctx;
-        struct vlc_thumbnailer_seek_arg seek_arg = {
-            .type = vlc_thumbnailer_seek_arg::VLC_THUMBNAILER_SEEK_POS,
+        struct vlc_preparser_seek_arg seek_arg = {
+            .type = vlc_preparser_seek_arg::VLC_PREPARSER_SEEK_POS,
             .pos = position,
-            .speed = vlc_thumbnailer_seek_arg::VLC_THUMBNAILER_SEEK_FAST,
+            .speed = vlc_preparser_seek_arg::VLC_PREPARSER_SEEK_FAST,
         };
 
         static const struct vlc_thumbnailer_cbs cbs = {
             .on_ended = onThumbnailComplete,
         };
-        vlc_thumbnailer_req_id requestId =
-            vlc_thumbnailer_Request( m_thumbnailer.get(), item.get(), &seek_arg,
-                                     &cbs, &ctx );
+        vlc_preparser_req_id requestId =
+            vlc_preparser_GenerateThumbnail( m_thumbnailer.get(), item.get(),
+                                             &seek_arg, &cbs, &ctx );
 
-        if (requestId == VLC_THUMBNAILER_REQ_ID_INVALID)
+        if (requestId == VLC_PREPARSER_REQ_ID_INVALID)
         {
             m_currentContext = nullptr;
             return false;


=====================================
modules/misc/medialibrary/medialibrary.h
=====================================
@@ -40,7 +40,7 @@
 
 struct vlc_event_t;
 struct vlc_object_t;
-struct vlc_thumbnailer_t;
+struct vlc_preparser_t;
 
 class Logger;
 
@@ -137,14 +137,14 @@ public:
     void stop() override;
 
 private:
-    static void onThumbnailComplete( picture_t* thumbnail, void* data );
+    static void onThumbnailComplete( input_item_t *, int, picture_t* thumbnail, void *data );
 
 private:
     vlc_medialibrary_module_t* m_ml;
     vlc::threads::mutex m_mutex;
     vlc::threads::condition_variable m_cond;
     ThumbnailerCtx* m_currentContext;
-    std::unique_ptr<vlc_thumbnailer_t, void(*)(vlc_thumbnailer_t*)> m_thumbnailer;
+    std::unique_ptr<vlc_preparser_t, void(*)(vlc_preparser_t*)> m_thumbnailer;
 };
 
 class MediaLibrary : public medialibrary::IMediaLibraryCb


=====================================
src/Makefile.am
=====================================
@@ -107,7 +107,6 @@ pluginsinclude_HEADERS.h = \
 	../include/vlc_subpicture.h \
 	../include/vlc_text_style.h \
 	../include/vlc_threads.h \
-	../include/vlc_thumbnailer.h \
 	../include/vlc_tick.h \
 	../include/vlc_timestamp_helper.h \
 	../include/vlc_tls.h \
@@ -327,7 +326,6 @@ libvlccore_la_SOURCES = \
 	input/stream_filter.c \
 	input/stream_memory.c \
 	input/subtitles.c \
-	input/thumbnailer.c \
 	input/var.c \
 	audio_output/aout_internal.h \
 	audio_output/common.c \


=====================================
src/input/thumbnailer.c deleted
=====================================
@@ -1,329 +0,0 @@
-/*****************************************************************************
- * thumbnailer.c: Thumbnailing API
- *****************************************************************************
- * Copyright (C) 2018 VLC authors and VideoLAN
- *
- * Authors: Hugo Beauzée-Luyssen <hugo at beauzee.fr>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <vlc_thumbnailer.h>
-#include <vlc_executor.h>
-#include "input_internal.h"
-
-struct vlc_thumbnailer_t
-{
-    vlc_object_t* parent;
-    vlc_executor_t *executor;
-    vlc_mutex_t lock;
-    vlc_cond_t cond_ended;
-
-    vlc_thumbnailer_req_id current_id;
-    vlc_tick_t timeout;
-
-    struct vlc_list submitted_tasks; /**< list of struct task */
-};
-
-typedef struct task
-{
-    vlc_thumbnailer_t *thumbnailer;
-
-    struct vlc_thumbnailer_seek_arg seek_arg;
-    input_item_t *item;
-    const struct vlc_thumbnailer_cbs *cbs;
-    void* userdata;
-
-    enum
-    {
-        RUNNING,
-        INTERRUPTED,
-        ENDED,
-    } status;
-    picture_t *pic;
-
-    vlc_thumbnailer_req_id id;
-
-    struct vlc_runnable runnable; /**< to be passed to the executor */
-    struct vlc_list node; /**< node of vlc_thumbnailer_t.submitted_tasks */
-} task_t;
-
-static void RunnableRun(void *);
-
-static task_t *
-TaskNew(vlc_thumbnailer_t *thumbnailer, input_item_t *item,
-        const struct vlc_thumbnailer_seek_arg *seek_arg,
-        const struct vlc_thumbnailer_cbs *cbs, void *userdata )
-{
-    task_t *task = malloc(sizeof(*task));
-    if (!task)
-        return NULL;
-
-    task->thumbnailer = thumbnailer;
-    task->item = item;
-    if (seek_arg == NULL)
-        task->seek_arg = (struct vlc_thumbnailer_seek_arg) {
-            .type = VLC_THUMBNAILER_SEEK_NONE,
-        };
-    else
-        task->seek_arg = *seek_arg;
-
-    task->cbs = cbs;
-    task->userdata = userdata;
-
-    task->status = RUNNING;
-    task->pic = NULL;
-
-    task->runnable.run = RunnableRun;
-    task->runnable.userdata = task;
-
-    input_item_Hold(item);
-
-    return task;
-}
-
-static void
-TaskDestroy(task_t *task)
-{
-    input_item_Release(task->item);
-    free(task);
-}
-
-static void NotifyThumbnail(task_t *task, picture_t *pic)
-{
-    task->cbs->on_ended(pic, task->userdata);
-}
-
-static void
-on_thumbnailer_input_event( input_thread_t *input,
-                            const struct vlc_input_event *event, void *userdata )
-{
-    VLC_UNUSED(input);
-    if ( event->type != INPUT_EVENT_THUMBNAIL_READY &&
-         ( event->type != INPUT_EVENT_STATE || ( event->state.value != ERROR_S &&
-                                                 event->state.value != END_S ) ) )
-         return;
-
-    task_t *task = userdata;
-    vlc_thumbnailer_t *thumbnailer = task->thumbnailer;
-
-    vlc_mutex_lock(&thumbnailer->lock);
-    if (task->status != RUNNING)
-    {
-        /* We may receive a THUMBNAIL_READY event followed by an
-         * INPUT_EVENT_STATE (end of stream), we must only consider the first
-         * one. */
-        vlc_mutex_unlock(&thumbnailer->lock);
-        return;
-    }
-
-    task->status = ENDED;
-
-    if (event->type == INPUT_EVENT_THUMBNAIL_READY)
-        task->pic = picture_Hold(event->thumbnail);
-
-    vlc_cond_signal(&thumbnailer->cond_ended);
-    vlc_mutex_unlock(&thumbnailer->lock);
-}
-
-static void
-RunnableRun(void *userdata)
-{
-    vlc_thread_set_name("vlc-run-thumb");
-
-    task_t *task = userdata;
-    vlc_thumbnailer_t *thumbnailer = task->thumbnailer;
-
-    vlc_tick_t now = vlc_tick_now();
-
-    static const struct vlc_input_thread_callbacks cbs = {
-        .on_event = on_thumbnailer_input_event,
-    };
-
-    const struct vlc_input_thread_cfg cfg = {
-        .type = INPUT_TYPE_THUMBNAILING,
-        .cbs = &cbs,
-        .cbs_data = task,
-    };
-
-    input_thread_t* input =
-            input_Create( thumbnailer->parent, task->item, &cfg );
-    if (!input)
-        goto error;
-
-    assert(task->seek_arg.speed == VLC_THUMBNAILER_SEEK_PRECISE
-        || task->seek_arg.speed == VLC_THUMBNAILER_SEEK_FAST);
-    bool fast_seek = task->seek_arg.speed == VLC_THUMBNAILER_SEEK_FAST;
-
-    switch (task->seek_arg.type)
-    {
-        case VLC_THUMBNAILER_SEEK_NONE:
-            break;
-        case VLC_THUMBNAILER_SEEK_TIME:
-            input_SetTime(input, task->seek_arg.time, fast_seek);
-            break;
-        case VLC_THUMBNAILER_SEEK_POS:
-            input_SetPosition(input, task->seek_arg.pos, fast_seek);
-            break;
-        default:
-            vlc_assert_unreachable();
-    }
-
-    int ret = input_Start(input);
-    if (ret != VLC_SUCCESS)
-    {
-        input_Close(input);
-        goto error;
-    }
-
-    vlc_mutex_lock(&thumbnailer->lock);
-    if (thumbnailer->timeout == VLC_TICK_INVALID)
-    {
-        while (task->status == RUNNING)
-            vlc_cond_wait(&thumbnailer->cond_ended, &thumbnailer->lock);
-    }
-    else
-    {
-        vlc_tick_t deadline = now + thumbnailer->timeout;
-        int timeout = 0;
-        while (task->status == RUNNING && timeout == 0)
-            timeout =
-                vlc_cond_timedwait(&thumbnailer->cond_ended, &thumbnailer->lock, deadline);
-    }
-    picture_t* pic = task->pic;
-    task->pic = NULL;
-
-    bool interrupted = task->status == INTERRUPTED;
-
-    vlc_list_remove(&task->node);
-    vlc_mutex_unlock(&thumbnailer->lock);
-
-    NotifyThumbnail(task, interrupted ? NULL : pic);
-
-    if (pic)
-        picture_Release(pic);
-
-    input_Stop(input);
-    input_Close(input);
-
-error:
-    TaskDestroy(task);
-}
-
-vlc_thumbnailer_req_id
-vlc_thumbnailer_Request( vlc_thumbnailer_t *thumbnailer,
-                         input_item_t *item,
-                         const struct vlc_thumbnailer_seek_arg *seek_arg,
-                         const struct vlc_thumbnailer_cbs *cbs, void *userdata )
-{
-    assert( cbs != NULL && cbs->on_ended != NULL );
-
-    task_t *task = TaskNew(thumbnailer, item, seek_arg, cbs, userdata);
-    if (!task)
-        return 0;
-
-    vlc_mutex_lock(&thumbnailer->lock);
-    vlc_thumbnailer_req_id id = task->id = thumbnailer->current_id++;
-    static_assert(VLC_THUMBNAILER_REQ_ID_INVALID == 0, "Invalid id should be 0");
-    if (unlikely(thumbnailer->current_id == 0)) /* unsigned wrapping */
-        ++thumbnailer->current_id;
-    vlc_list_append(&task->node, &thumbnailer->submitted_tasks);
-    vlc_mutex_unlock(&thumbnailer->lock);
-
-    vlc_executor_Submit(thumbnailer->executor, &task->runnable);
-
-    return id;
-}
-
-size_t vlc_thumbnailer_Cancel( vlc_thumbnailer_t* thumbnailer, vlc_thumbnailer_req_id id )
-{
-    vlc_mutex_lock(&thumbnailer->lock);
-
-    task_t *task;
-    size_t count = 0;
-    vlc_list_foreach(task, &thumbnailer->submitted_tasks, node)
-    {
-        if (id == VLC_THUMBNAILER_REQ_ID_INVALID || task->id == id)
-        {
-            count++;
-            bool canceled =
-                vlc_executor_Cancel(thumbnailer->executor, &task->runnable);
-            if (canceled)
-            {
-                vlc_list_remove(&task->node);
-                vlc_mutex_unlock(&thumbnailer->lock);
-                NotifyThumbnail(task, NULL);
-                TaskDestroy(task);
-
-                /* Small optimisation in the likely case where the user cancel
-                 * only one task */
-                if (id != VLC_THUMBNAILER_REQ_ID_INVALID)
-                    return count;
-                vlc_mutex_lock(&thumbnailer->lock);
-            }
-            else
-            {
-                /* The task will be finished and destroyed after run() */
-                task->status = INTERRUPTED;
-                vlc_cond_signal(&thumbnailer->cond_ended);
-            }
-        }
-    }
-
-    vlc_mutex_unlock(&thumbnailer->lock);
-
-    return count;
-}
-
-vlc_thumbnailer_t *vlc_thumbnailer_Create( vlc_object_t* parent, vlc_tick_t timeout )
-{
-    assert(timeout >= 0);
-
-    vlc_thumbnailer_t *thumbnailer = malloc( sizeof( *thumbnailer ) );
-    if ( unlikely( thumbnailer == NULL ) )
-        return NULL;
-
-    thumbnailer->executor = vlc_executor_New(1);
-    if (!thumbnailer->executor)
-    {
-        free(thumbnailer);
-        return NULL;
-    }
-
-    thumbnailer->parent = parent;
-    thumbnailer->current_id = 1;
-    thumbnailer->timeout = timeout;
-    vlc_mutex_init(&thumbnailer->lock);
-    vlc_cond_init(&thumbnailer->cond_ended);
-    vlc_list_init(&thumbnailer->submitted_tasks);
-
-    return thumbnailer;
-}
-
-void vlc_thumbnailer_SetTimeout( vlc_thumbnailer_t *thumbnailer,
-                                 vlc_tick_t timeout )
-{
-    thumbnailer->timeout = timeout;
-}
-
-void vlc_thumbnailer_Delete( vlc_thumbnailer_t *thumbnailer )
-{
-    vlc_executor_Delete(thumbnailer->executor);
-    free( thumbnailer );
-}


=====================================
src/libvlccore.sym
=====================================
@@ -830,11 +830,6 @@ vlc_es_id_GetCat
 vlc_es_id_GetStrId
 vlc_es_id_IsStrIdStable
 vlc_encoder_Destroy
-vlc_thumbnailer_Create
-vlc_thumbnailer_Request
-vlc_thumbnailer_Cancel
-vlc_thumbnailer_Delete
-vlc_thumbnailer_SetTimeout
 vlc_player_AddAssociatedMedia
 vlc_player_AddListener
 vlc_player_AddMetadataListener
@@ -1042,6 +1037,7 @@ vlc_input_attachment_New
 vlc_input_attachment_Hold
 vlc_preparser_New
 vlc_preparser_Push
+vlc_preparser_GenerateThumbnail
 vlc_preparser_Cancel
 vlc_preparser_Delete
 vlc_preparser_Deactivate


=====================================
src/media_source/media_tree.c
=====================================
@@ -347,10 +347,11 @@ 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;
 #else
-    return vlc_preparser_Push(parser, media, META_REQUEST_OPTION_PARSE |
-                              META_REQUEST_OPTION_DO_INTERACT |
-                              META_REQUEST_OPTION_PARSE_SUBITEMS,
+    return vlc_preparser_Push(parser, media, VLC_PREPARSER_TYPE_PARSE |
+                              VLC_PREPARSER_OPTION_INTERACT |
+                              VLC_PREPARSER_OPTION_SUBITEMS,
                               &preparser_callbacks, tree);
 #endif
 }


=====================================
src/meson.build
=====================================
@@ -178,7 +178,6 @@ libvlccore_sources_base = files(
     'input/stream_filter.c',
     'input/stream_memory.c',
     'input/subtitles.c',
-    'input/thumbnailer.c',
     'input/var.c',
     'audio_output/aout_internal.h',
     'audio_output/common.c',


=====================================
src/playlist/playlist.c
=====================================
@@ -40,10 +40,12 @@ vlc_playlist_New(vlc_object_t *parent, enum vlc_playlist_preparsing rec,
 
     if (rec != VLC_PLAYLIST_PREPARSING_DISABLED)
     {
-        playlist->parser = vlc_preparser_New(parent, preparse_max_threads,
-                                             preparse_timeout,
-                                             META_REQUEST_OPTION_PARSE |
-                                             META_REQUEST_OPTION_FETCH_LOCAL);
+        const struct vlc_preparser_cfg cfg = {
+            .types = VLC_PREPARSER_TYPE_PARSE | VLC_PREPARSER_TYPE_FETCHMETA_LOCAL,
+            .max_parser_threads = preparse_max_threads,
+            .timeout = preparse_timeout,
+        };
+        playlist->parser = vlc_preparser_New(parent, &cfg);
         if (playlist->parser == NULL)
         {
             free(playlist);


=====================================
src/playlist/preparse.c
=====================================
@@ -149,10 +149,9 @@ vlc_playlist_AutoPreparse(vlc_playlist_t *playlist, input_item_t *input,
                 return;
         }
 
-        input_item_meta_request_option_t options =
-            META_REQUEST_OPTION_PARSE | META_REQUEST_OPTION_FETCH_LOCAL;
+        int options = VLC_PREPARSER_TYPE_PARSE | VLC_PREPARSER_TYPE_FETCHMETA_LOCAL;
         if (parse_subitems)
-            options |= META_REQUEST_OPTION_PARSE_SUBITEMS;
+            options |= VLC_PREPARSER_OPTION_SUBITEMS;
 
         vlc_preparser_Push(playlist->parser, input, options,
                            &preparser_callbacks, playlist);


=====================================
src/preparser/fetcher.c
=====================================
@@ -71,7 +71,7 @@ static void RunSearchNetwork(void *);
 
 static struct task *
 TaskNew(input_fetcher_t *fetcher, vlc_executor_t *executor, input_item_t *item,
-        input_item_meta_request_option_t options,
+        int options,
         const input_fetcher_callbacks_t *cbs, void *userdata)
 {
     struct task *task = malloc(sizeof(*task));
@@ -127,7 +127,7 @@ FetcherRemoveTask(input_fetcher_t *fetcher, struct task *task)
 
 static int
 Submit(input_fetcher_t *fetcher, vlc_executor_t *executor, input_item_t *item,
-       input_item_meta_request_option_t options,
+       int options,
        const input_fetcher_callbacks_t *cbs, void *userdata)
 {
     struct task *task =
@@ -380,7 +380,7 @@ static void RunSearchLocal(void *userdata)
     if( SearchByScope( task, FETCHER_SCOPE_LOCAL ) == VLC_SUCCESS )
         goto end; /* done */
 
-    if( task->options & META_REQUEST_OPTION_FETCH_NETWORK )
+    if( task->options & VLC_PREPARSER_TYPE_FETCHMETA_NET )
     {
         int ret = Submit(fetcher, fetcher->executor_network, task->item,
                          task->options, task->cbs, task->userdata);
@@ -422,9 +422,9 @@ static void RunSearchNetwork(void *userdata)
 }
 
 input_fetcher_t* input_fetcher_New( vlc_object_t* owner,
-                                    input_item_meta_request_option_t request_type )
+                                    int request_type )
 {
-    assert(request_type & META_REQUEST_OPTION_FETCH_ANY);
+    assert(request_type & VLC_PREPARSER_TYPE_FETCHMETA_ALL);
     input_fetcher_t* fetcher = malloc( sizeof( *fetcher ) );
 
     if( unlikely( !fetcher ) )
@@ -434,7 +434,7 @@ input_fetcher_t* input_fetcher_New( vlc_object_t* owner,
     if (max_threads < 1)
         max_threads = 1;
 
-    if (request_type & META_REQUEST_OPTION_FETCH_LOCAL)
+    if (request_type & VLC_PREPARSER_TYPE_FETCHMETA_LOCAL)
     {
         fetcher->executor_local = vlc_executor_New(max_threads);
         if (!fetcher->executor_local)
@@ -446,7 +446,7 @@ input_fetcher_t* input_fetcher_New( vlc_object_t* owner,
     else
         fetcher->executor_local = NULL;
 
-    if (request_type & META_REQUEST_OPTION_FETCH_NETWORK)
+    if (request_type & VLC_PREPARSER_TYPE_FETCHMETA_NET)
     {
         fetcher->executor_network = vlc_executor_New(max_threads);
         if (!fetcher->executor_network)
@@ -483,16 +483,16 @@ input_fetcher_t* input_fetcher_New( vlc_object_t* owner,
 }
 
 int input_fetcher_Push(input_fetcher_t* fetcher, input_item_t* item,
-    input_item_meta_request_option_t options,
-    const input_fetcher_callbacks_t *cbs, void *cbs_userdata)
+                       int options,
+                       const input_fetcher_callbacks_t *cbs, void *cbs_userdata)
 {
-    assert(options & META_REQUEST_OPTION_FETCH_ANY);
-    if (options & META_REQUEST_OPTION_FETCH_LOCAL)
+    assert(options & VLC_PREPARSER_TYPE_FETCHMETA_ALL);
+    if (options & VLC_PREPARSER_TYPE_FETCHMETA_LOCAL)
         assert(fetcher->executor_local != NULL);
-    if (options & META_REQUEST_OPTION_FETCH_NETWORK)
+    if (options & VLC_PREPARSER_TYPE_FETCHMETA_NET)
         assert(fetcher->executor_network != NULL);
 
-    vlc_executor_t *executor = options & META_REQUEST_OPTION_FETCH_LOCAL
+    vlc_executor_t *executor = options & VLC_PREPARSER_TYPE_FETCHMETA_LOCAL
                              ? fetcher->executor_local
                              : fetcher->executor_network;
 


=====================================
src/preparser/fetcher.h
=====================================
@@ -42,12 +42,11 @@ typedef struct input_fetcher_callbacks_t {
 /**
  * This function creates the fetcher object and thread.
  *
- * @param request_type a combination of META_REQUEST_OPTION_FETCH_LOCAL and
- * META_REQUEST_OPTION_FETCH_NETWORK, it is used to setup the executors for
+ * @param request_type a combination of VLC_PREPARSER_TYPE_FETCHMETA_LOCAL and
+ * VLC_PREPARSER_TYPE_FETCHMETA_NET, it is used to setup the executors for
  * each domain.
  */
-input_fetcher_t *input_fetcher_New( vlc_object_t *,
-                                    input_item_meta_request_option_t request_type );
+input_fetcher_t *input_fetcher_New( vlc_object_t *, int request_type );
 
 /**
  * This function enqueues the provided item to be art fetched.
@@ -55,8 +54,7 @@ input_fetcher_t *input_fetcher_New( vlc_object_t *,
  * The input item is retained until the art fetching is done or until the
  * fetcher object is destroyed.
  */
-int input_fetcher_Push( input_fetcher_t *, input_item_t *,
-                        input_item_meta_request_option_t,
+int input_fetcher_Push( input_fetcher_t *, input_item_t *, int,
                         const input_fetcher_callbacks_t *, void * );
 
 /**


=====================================
src/preparser/preparser.c
=====================================
@@ -31,11 +31,18 @@
 #include "input/input_internal.h"
 #include "fetcher.h"
 
+union vlc_preparser_cbs
+{
+    const input_item_parser_cbs_t *parser;
+    const struct vlc_thumbnailer_cbs *thumbnailer;
+};
+
 struct vlc_preparser_t
 {
     vlc_object_t* owner;
     input_fetcher_t* fetcher;
-    vlc_executor_t *executor;
+    vlc_executor_t *parser;
+    vlc_executor_t *thumbnailer;
     vlc_tick_t timeout;
     atomic_bool deactivated;
 
@@ -48,12 +55,13 @@ struct task
 {
     vlc_preparser_t *preparser;
     input_item_t *item;
-    input_item_meta_request_option_t options;
-    const input_item_parser_cbs_t *cbs;
+    int options;
+    struct vlc_preparser_seek_arg seek_arg;
+    union vlc_preparser_cbs cbs;
     void *userdata;
     vlc_preparser_req_id id;
 
-    input_item_parser_id_t *parser;
+    picture_t *pic;
 
     vlc_sem_t preparse_ended;
     int preparse_status;
@@ -64,12 +72,10 @@ struct task
     struct vlc_list node; /**< node of vlc_preparser_t.submitted_tasks */
 };
 
-static void RunnableRun(void *);
-
 static struct task *
-TaskNew(vlc_preparser_t *preparser, input_item_t *item,
-        input_item_meta_request_option_t options,
-        const input_item_parser_cbs_t *cbs, void *userdata)
+TaskNew(vlc_preparser_t *preparser, void (*run)(void *), input_item_t *item,
+        int options, const struct vlc_preparser_seek_arg *seek_arg,
+        union vlc_preparser_cbs cbs, void *userdata)
 {
     struct task *task = malloc(sizeof(*task));
     if (!task)
@@ -80,15 +86,22 @@ TaskNew(vlc_preparser_t *preparser, input_item_t *item,
     task->options = options;
     task->cbs = cbs;
     task->userdata = userdata;
+    task->pic = NULL;
+
+    if (seek_arg == NULL)
+        task->seek_arg = (struct vlc_preparser_seek_arg) {
+            .type = VLC_PREPARSER_SEEK_NONE,
+        };
+    else
+        task->seek_arg = *seek_arg;
 
     input_item_Hold(item);
 
-    task->parser = NULL;
     vlc_sem_init(&task->preparse_ended, 0);
     task->preparse_status = VLC_EGENERIC;
     atomic_init(&task->interrupted, false);
 
-    task->runnable.run = RunnableRun;
+    task->runnable.run = run;
     task->runnable.userdata = task;
 
     return task;
@@ -130,18 +143,15 @@ PreparserRemoveTask(vlc_preparser_t *preparser, struct task *task)
 }
 
 static void
-NotifyPreparseEnded(struct task *task, bool cancelled)
+NotifyPreparseEnded(struct task *task)
 {
-    if (cancelled || atomic_load(&task->interrupted))
+    if (atomic_load(&task->interrupted))
         task->preparse_status = -EINTR;
     else if (task->preparse_status == VLC_SUCCESS)
         input_item_SetPreparsed(task->item);
 
-    if (task->cbs == NULL)
-        return;
-
-    if (task->cbs->on_ended)
-        task->cbs->on_ended(task->item, task->preparse_status, task->userdata);
+    task->cbs.parser->on_ended(task->item, task->preparse_status,
+                               task->userdata);
 }
 
 static void
@@ -164,8 +174,8 @@ OnParserSubtreeAdded(input_item_t *item, input_item_node_t *subtree,
     if (atomic_load(&task->interrupted))
         return;
 
-    if (task->cbs && task->cbs->on_subtree_added)
-        task->cbs->on_subtree_added(task->item, subtree, task->userdata);
+    if (task->cbs.parser->on_subtree_added)
+        task->cbs.parser->on_subtree_added(task->item, subtree, task->userdata);
 }
 
 static void
@@ -179,8 +189,9 @@ OnParserAttachmentsAdded(input_item_t *item,
     if (atomic_load(&task->interrupted))
         return;
 
-    if (task->cbs && task->cbs->on_attachments_added)
-        task->cbs->on_attachments_added(task->item, array, count, task->userdata);
+    if (task->cbs.parser->on_attachments_added)
+        task->cbs.parser->on_attachments_added(task->item, array, count, 
+                                               task->userdata);
 }
 
 static void
@@ -191,7 +202,7 @@ OnArtFetchEnded(input_item_t *item, bool fetched, void *userdata)
 
     struct task *task = userdata;
 
-    NotifyPreparseEnded(task, false);
+    NotifyPreparseEnded(task);
     TaskDelete(task);
 }
 
@@ -212,11 +223,12 @@ Parse(struct task *task, vlc_tick_t deadline)
     const struct input_item_parser_cfg cfg = {
         .cbs = &cbs,
         .cbs_data = task,
-        .subitems = task->options & META_REQUEST_OPTION_PARSE_SUBITEMS,
-        .interact = task->options & META_REQUEST_OPTION_DO_INTERACT,
+        .subitems = task->options & VLC_PREPARSER_OPTION_SUBITEMS,
+        .interact = task->options & VLC_PREPARSER_OPTION_INTERACT,
     };
-    task->parser = input_item_Parse(obj, task->item, &cfg);
-    if (!task->parser)
+    input_item_parser_id_t *parser =
+        input_item_Parse(obj, task->item, &cfg);
+    if (parser == NULL)
     {
         task->preparse_status = VLC_EGENERIC;
         return;
@@ -228,29 +240,29 @@ Parse(struct task *task, vlc_tick_t deadline)
     else
         if (vlc_sem_timedwait(&task->preparse_ended, deadline))
         {
-            input_item_parser_id_Release(task->parser);
+            input_item_parser_id_Release(parser);
             task->preparse_status = VLC_ETIMEOUT;
             return;
         }
 
     /* This call also interrupts the parsing if it is still running */
-    input_item_parser_id_Release(task->parser);
+    input_item_parser_id_Release(parser);
 }
 
 static int
 Fetch(struct task *task)
 {
     input_fetcher_t *fetcher = task->preparser->fetcher;
-    if (!fetcher || !(task->options & META_REQUEST_OPTION_FETCH_ANY))
+    if (!fetcher || !(task->options & VLC_PREPARSER_TYPE_FETCHMETA_ALL))
         return VLC_ENOENT;
 
     return input_fetcher_Push(fetcher, task->item,
-                              task->options & META_REQUEST_OPTION_FETCH_ANY,
+                              task->options & VLC_PREPARSER_TYPE_FETCHMETA_ALL,
                               &input_fetcher_callbacks, task);
 }
 
 static void
-RunnableRun(void *userdata)
+ParserRun(void *userdata)
 {
     vlc_thread_set_name("vlc-run-prepars");
 
@@ -260,7 +272,7 @@ RunnableRun(void *userdata)
     vlc_tick_t deadline = preparser->timeout ? vlc_tick_now() + preparser->timeout
                                              : VLC_TICK_INVALID;
 
-    if (task->options & META_REQUEST_OPTION_PARSE)
+    if (task->options & VLC_PREPARSER_TYPE_PARSE)
     {
         if (atomic_load(&task->interrupted))
         {
@@ -273,7 +285,7 @@ RunnableRun(void *userdata)
 
     PreparserRemoveTask(preparser, task);
 
-    if (task->preparse_status == VLC_ETIMEOUT)
+    if (task->preparse_status == VLC_ETIMEOUT || atomic_load(&task->interrupted))
         goto end;
 
     int ret = Fetch(task);
@@ -282,7 +294,111 @@ RunnableRun(void *userdata)
         return; /* Remove the task and notify from the fetcher callback */
 
 end:
-    NotifyPreparseEnded(task, false);
+    NotifyPreparseEnded(task);
+    TaskDelete(task);
+}
+
+static void
+on_thumbnailer_input_event( input_thread_t *input,
+                            const struct vlc_input_event *event, void *userdata )
+{
+    VLC_UNUSED(input);
+    if ( event->type != INPUT_EVENT_THUMBNAIL_READY &&
+         ( event->type != INPUT_EVENT_STATE || ( event->state.value != ERROR_S &&
+                                                 event->state.value != END_S ) ) )
+         return;
+
+    struct task *task = userdata;
+
+    if (event->type == INPUT_EVENT_THUMBNAIL_READY)
+    {
+        task->pic = picture_Hold(event->thumbnail);
+        task->preparse_status = VLC_SUCCESS;
+    }
+    vlc_sem_post(&task->preparse_ended);
+}
+
+static void
+ThumbnailerRun(void *userdata)
+{
+    vlc_thread_set_name("vlc-run-thumb");
+
+    struct task *task = userdata;
+    vlc_preparser_t *preparser = task->preparser;
+
+    static const struct vlc_input_thread_callbacks cbs = {
+        .on_event = on_thumbnailer_input_event,
+    };
+
+    const struct vlc_input_thread_cfg cfg = {
+        .type = INPUT_TYPE_THUMBNAILING,
+        .cbs = &cbs,
+        .cbs_data = task,
+    };
+
+    vlc_tick_t deadline = preparser->timeout != VLC_TICK_INVALID ?
+                          vlc_tick_now() + preparser->timeout :
+                          VLC_TICK_INVALID;
+
+    input_thread_t* input =
+            input_Create( preparser->owner, task->item, &cfg );
+    if (!input)
+        goto error;
+
+    assert(task->seek_arg.speed == VLC_PREPARSER_SEEK_PRECISE
+        || task->seek_arg.speed == VLC_PREPARSER_SEEK_FAST);
+    bool fast_seek = task->seek_arg.speed == VLC_PREPARSER_SEEK_FAST;
+
+    switch (task->seek_arg.type)
+    {
+        case VLC_PREPARSER_SEEK_NONE:
+            break;
+        case VLC_PREPARSER_SEEK_TIME:
+            input_SetTime(input, task->seek_arg.time, fast_seek);
+            break;
+        case VLC_PREPARSER_SEEK_POS:
+            input_SetPosition(input, task->seek_arg.pos, fast_seek);
+            break;
+        default:
+            vlc_assert_unreachable();
+    }
+
+    int ret = input_Start(input);
+    if (ret != VLC_SUCCESS)
+    {
+        input_Close(input);
+        goto error;
+    }
+
+    if (deadline == VLC_TICK_INVALID)
+        vlc_sem_wait(&task->preparse_ended);
+    else
+    {
+        if (vlc_sem_timedwait(&task->preparse_ended, deadline))
+            task->preparse_status = VLC_ETIMEOUT;
+    }
+
+    if (atomic_load(&task->interrupted))
+        task->preparse_status = -EINTR;
+
+    picture_t* pic = task->pic;
+    task->pic = NULL;
+
+    vlc_mutex_lock(&preparser->lock);
+    vlc_list_remove(&task->node);
+    vlc_mutex_unlock(&preparser->lock);
+
+    task->cbs.thumbnailer->on_ended(task->item, task->preparse_status,
+                                    task->preparse_status == VLC_SUCCESS ?
+                                    pic : NULL, task->userdata);
+
+    if (pic)
+        picture_Release(pic);
+
+    input_Stop(input);
+    input_Close(input);
+
+error:
     TaskDelete(task);
 }
 
@@ -294,47 +410,57 @@ Interrupt(struct task *task)
     vlc_sem_post(&task->preparse_ended);
 }
 
-vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent, unsigned max_threads,
-                                    vlc_tick_t timeout,
-                                    input_item_meta_request_option_t request_type )
+vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent,
+                                    const struct vlc_preparser_cfg *cfg )
 {
-    assert(max_threads >= 1);
-    assert(timeout >= 0);
-    assert(request_type & (META_REQUEST_OPTION_FETCH_ANY|META_REQUEST_OPTION_PARSE));
+    assert(cfg != NULL);
+
+    assert(cfg->timeout >= 0);
+
+    int request_type = cfg->types;
+    assert(request_type & (VLC_PREPARSER_TYPE_FETCHMETA_ALL|
+                           VLC_PREPARSER_TYPE_PARSE|
+                           VLC_PREPARSER_TYPE_THUMBNAIL));
+
+    unsigned parser_threads = cfg->max_parser_threads == 0 ? 1 :
+                              cfg->max_parser_threads;
+    unsigned thumbnailer_threads = cfg->max_thumbnailer_threads == 0 ? 1 :
+                                   cfg->max_thumbnailer_threads;
 
     vlc_preparser_t* preparser = malloc( sizeof *preparser );
     if (!preparser)
         return NULL;
 
-    if (request_type & META_REQUEST_OPTION_PARSE)
+    preparser->timeout = cfg->timeout;
+    preparser->owner = parent;
+
+    if (request_type & VLC_PREPARSER_TYPE_PARSE)
     {
-        preparser->executor = vlc_executor_New(max_threads);
-        if (!preparser->executor)
-        {
-            free(preparser);
-            return NULL;
-        }
+        preparser->parser = vlc_executor_New(parser_threads);
+        if (!preparser->parser)
+            goto error_parser;
     }
     else
-        preparser->executor = NULL;
-
-    preparser->timeout = timeout;
+        preparser->parser = NULL;
 
-    preparser->owner = parent;
-    if (request_type & META_REQUEST_OPTION_FETCH_ANY)
+    if (request_type & VLC_PREPARSER_TYPE_FETCHMETA_ALL)
     {
         preparser->fetcher = input_fetcher_New(parent, request_type);
         if (unlikely(preparser->fetcher == NULL))
-        {
-            if (preparser->executor != NULL)
-                vlc_executor_Delete(preparser->executor);
-            free(preparser);
-            return NULL;
-        }
+            goto error_fetcher;
     }
     else
         preparser->fetcher = NULL;
 
+    if (request_type & VLC_PREPARSER_TYPE_THUMBNAIL)
+    {
+        preparser->thumbnailer = vlc_executor_New(thumbnailer_threads);
+        if (!preparser->thumbnailer)
+            goto error_thumbnail;
+    }
+    else
+        preparser->thumbnailer = NULL;
+
     atomic_init( &preparser->deactivated, false );
 
     vlc_mutex_init(&preparser->lock);
@@ -342,34 +468,52 @@ vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent, unsigned max_threads,
     preparser->current_id = 1;
 
     return preparser;
+
+error_thumbnail:
+    if (preparser->fetcher != NULL)
+        input_fetcher_Delete(preparser->fetcher);
+error_fetcher:
+    if (preparser->parser != NULL)
+        vlc_executor_Delete(preparser->parser);
+error_parser:
+    free(preparser);
+    return NULL;
 }
 
 vlc_preparser_req_id vlc_preparser_Push( vlc_preparser_t *preparser, input_item_t *item,
-                                  input_item_meta_request_option_t i_options,
-                                  const input_item_parser_cbs_t *cbs,
-                                  void *cbs_userdata )
+                                         int type_options,
+                                         const input_item_parser_cbs_t *cbs,
+                                         void *cbs_userdata )
 {
     if( atomic_load( &preparser->deactivated ) )
-        return 0;
+        return VLC_PREPARSER_REQ_ID_INVALID;
+
+    assert((type_options & VLC_PREPARSER_TYPE_THUMBNAIL) == 0);
 
-    assert(i_options & META_REQUEST_OPTION_PARSE
-        || i_options & META_REQUEST_OPTION_FETCH_ANY);
+    assert(type_options & VLC_PREPARSER_TYPE_PARSE
+        || type_options & VLC_PREPARSER_TYPE_FETCHMETA_ALL);
 
-    assert(!(i_options & META_REQUEST_OPTION_PARSE)
-        || preparser->executor != NULL);
-    assert(!(i_options & META_REQUEST_OPTION_FETCH_ANY)
+    assert(!(type_options & VLC_PREPARSER_TYPE_PARSE)
+        || preparser->parser != NULL);
+    assert(!(type_options & VLC_PREPARSER_TYPE_FETCHMETA_ALL)
         || preparser->fetcher != NULL);
 
-    struct task *task =
-        TaskNew(preparser, item, i_options, cbs, cbs_userdata);
+    assert(cbs != NULL && cbs->on_ended != NULL);
+
+    union vlc_preparser_cbs task_cbs = {
+        .parser = cbs,
+    };
+
+    struct task *task = TaskNew(preparser, ParserRun, item, type_options, NULL,
+                                task_cbs, cbs_userdata);
     if( !task )
-        return 0;
+        return VLC_PREPARSER_REQ_ID_INVALID;
 
-    if (preparser->executor != NULL)
+    if (preparser->parser != NULL)
     {
         vlc_preparser_req_id id = PreparserAddTask(preparser, task);
 
-        vlc_executor_Submit(preparser->executor, &task->runnable);
+        vlc_executor_Submit(preparser->parser, &task->runnable);
 
         return id;
     }
@@ -384,6 +528,35 @@ vlc_preparser_req_id vlc_preparser_Push( vlc_preparser_t *preparser, input_item_
     return ret == VLC_SUCCESS ? id : 0;
 }
 
+vlc_preparser_req_id
+vlc_preparser_GenerateThumbnail( vlc_preparser_t *preparser, input_item_t *item,
+                                 const struct vlc_preparser_seek_arg *seek_arg,
+                                 const struct vlc_thumbnailer_cbs *cbs,
+                                 void *cbs_userdata )
+{
+    if( atomic_load( &preparser->deactivated ) )
+        return VLC_PREPARSER_REQ_ID_INVALID;
+
+    assert(preparser->thumbnailer != NULL);
+    assert(cbs != NULL && cbs->on_ended != NULL);
+
+    union vlc_preparser_cbs task_cbs = {
+        .thumbnailer = cbs,
+    };
+
+    struct task *task =
+        TaskNew(preparser, ThumbnailerRun, item, VLC_PREPARSER_TYPE_THUMBNAIL,
+                seek_arg, task_cbs, cbs_userdata);
+    if (task == NULL)
+        return VLC_PREPARSER_REQ_ID_INVALID;
+
+    vlc_preparser_req_id id = PreparserAddTask(preparser, task);
+
+    vlc_executor_Submit(preparser->thumbnailer, &task->runnable);
+
+    return id;
+}
+
 size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req_id id )
 {
     vlc_mutex_lock(&preparser->lock);
@@ -396,13 +569,20 @@ size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req_id id
         {
             count++;
             /* TODO: the fetcher should be cancellable too */
-            bool canceled = preparser->executor != NULL
-              && vlc_executor_Cancel(preparser->executor, &task->runnable);
+            bool canceled = preparser->parser != NULL
+              && vlc_executor_Cancel(preparser->parser, &task->runnable);
             if (canceled)
             {
                 vlc_list_remove(&task->node);
                 vlc_mutex_unlock(&preparser->lock);
-                NotifyPreparseEnded(task, true);
+                task->preparse_status = -EINTR;
+                if (task->options == VLC_PREPARSER_TYPE_THUMBNAIL)
+                    task->cbs.thumbnailer->on_ended(task->item,
+                                                    task->preparse_status, NULL,
+                                                    task->userdata);
+                else
+                    task->cbs.parser->on_ended(task->item, task->preparse_status,
+                                               task->userdata);
                 TaskDelete(task);
 
                 /* Small optimisation in the likely case where the user cancel
@@ -439,11 +619,14 @@ void vlc_preparser_Delete( vlc_preparser_t *preparser )
     /* In case vlc_preparser_Deactivate() has not been called */
     vlc_preparser_Cancel(preparser, 0);
 
-    if (preparser->executor != NULL)
-        vlc_executor_Delete(preparser->executor);
+    if (preparser->parser != NULL)
+        vlc_executor_Delete(preparser->parser);
 
     if( preparser->fetcher )
         input_fetcher_Delete( preparser->fetcher );
 
+    if (preparser->thumbnailer != NULL)
+        vlc_executor_Delete(preparser->thumbnailer);
+
     free( preparser );
 }


=====================================
test/Makefile.am
=====================================
@@ -29,7 +29,7 @@ check_PROGRAMS = \
 	test_src_misc_variables \
 	test_src_input_stream \
 	test_src_input_stream_fifo \
-	test_src_input_thumbnail \
+	test_src_preparser_thumbnail \
 	test_src_input_decoder \
 	test_src_player \
 	test_src_player_monotonic_clock \
@@ -178,8 +178,8 @@ test_src_input_stream_net_CFLAGS = $(AM_CFLAGS) -DTEST_NET
 test_src_input_stream_net_LDADD = $(LIBVLCCORE) $(LIBVLC)
 test_src_input_stream_fifo_SOURCES = src/input/stream_fifo.c
 test_src_input_stream_fifo_LDADD = $(LIBVLCCORE) $(LIBVLC)
-test_src_input_thumbnail_SOURCES = src/input/thumbnail.c
-test_src_input_thumbnail_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_src_preparser_thumbnail_SOURCES = src/preparser/thumbnail.c
+test_src_preparser_thumbnail_LDADD = $(LIBVLCCORE) $(LIBVLC)
 test_src_player_SOURCES = src/player/player.c
 test_src_player_LDADD = $(LIBVLCCORE) $(LIBVLC) $(LIBM)
 test_src_player_monotonic_clock_SOURCES = src/player/player.c


=====================================
test/libvlc/media.c
=====================================
@@ -251,12 +251,15 @@ static void test_input_metadata_timeout(libvlc_instance_t *vlc, int timeout,
                                         : input_item_preparse_timeout,
     };
 
-    input_item_meta_request_option_t options =
-        META_REQUEST_OPTION_PARSE | META_REQUEST_OPTION_FETCH_LOCAL;
+    int options = VLC_PREPARSER_TYPE_PARSE | VLC_PREPARSER_TYPE_FETCHMETA_LOCAL;
 
+    const struct vlc_preparser_cfg cfg = {
+        .types = options,
+        .max_parser_threads = 1,
+        .timeout = VLC_TICK_FROM_MS(timeout),
+    };
     vlc_preparser_t *parser = vlc_preparser_New(VLC_OBJECT(vlc->p_libvlc_int),
-                                                1, VLC_TICK_FROM_MS(timeout),
-                                                options);
+                                                &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);


=====================================
test/src/meson.build
=====================================
@@ -71,8 +71,8 @@ vlc_tests += {
 }
 
 vlc_tests += {
-    'name' : 'test_src_input_thumbnail',
-    'sources' : files('input/thumbnail.c'),
+    'name' : 'test_src_preparser_thumbnail',
+    'sources' : files('preparser/thumbnail.c'),
     'suite' : ['src', 'test_src'],
     'link_with' : [libvlc, libvlccore],
     'module_depends' : ['demux_mock', 'rawvideo']


=====================================
test/src/input/thumbnail.c → test/src/preparser/thumbnail.c
=====================================
@@ -22,7 +22,7 @@
 #include "../lib/libvlc_internal.h"
 
 #include <vlc_common.h>
-#include <vlc_thumbnailer.h>
+#include <vlc_preparser.h>
 #include <vlc_input_item.h>
 #include <vlc_picture.h>
 
@@ -68,8 +68,10 @@ struct test_ctx
     bool b_done;
 };
 
-static void thumbnailer_callback( picture_t* thumbnail, void *data )
+static void thumbnailer_callback( input_item_t *item, int status,
+                                  picture_t* thumbnail, void *data )
 {
+    (void) item;
     struct test_ctx* p_ctx = data;
     vlc_mutex_lock( &p_ctx->lock );
 
@@ -78,6 +80,7 @@ static void thumbnailer_callback( picture_t* thumbnail, void *data )
         assert( test_params[p_ctx->test_idx].b_expected_success &&
                 "Expected failure but got a thumbnail" );
         assert( thumbnail->format.i_chroma == VLC_CODEC_ARGB );
+        assert( status == VLC_SUCCESS );
 
         /* TODO: Enable this once the new clock is merged */
 #if 0
@@ -98,8 +101,14 @@ static void thumbnailer_callback( picture_t* thumbnail, void *data )
 #endif
     }
     else
+    {
         assert( !test_params[p_ctx->test_idx].b_expected_success &&
                 "Expected a thumbnail but got a failure" );
+        if (test_params[p_ctx->test_idx].i_timeout == VLC_TICK_INVALID)
+            assert( status == VLC_EGENERIC );
+        else
+            assert( status == VLC_ETIMEOUT );
+    }
 
     p_ctx->b_done = true;
     vlc_cond_signal( &p_ctx->cond );
@@ -119,8 +128,13 @@ static void test_thumbnails( libvlc_instance_t* p_vlc )
         ctx.test_idx = i;
         ctx.b_done = false;
 
-        vlc_thumbnailer_t* p_thumbnailer = vlc_thumbnailer_Create(
-                    VLC_OBJECT( p_vlc->p_libvlc_int ), test_params[i].i_timeout );
+        const struct vlc_preparser_cfg cfg = {
+            .types = VLC_PREPARSER_TYPE_THUMBNAIL,
+            .timeout = test_params[i].i_timeout,
+        };
+
+        vlc_preparser_t* p_thumbnailer = vlc_preparser_New(
+                    VLC_OBJECT( p_vlc->p_libvlc_int ), &cfg );
         assert( p_thumbnailer != NULL );
 
 
@@ -136,28 +150,28 @@ static void test_thumbnails( libvlc_instance_t* p_vlc )
 
         vlc_mutex_lock( &ctx.lock );
 
-        vlc_thumbnailer_req_id id;
-        struct vlc_thumbnailer_seek_arg seek_arg;
+        vlc_preparser_req_id id;
+        struct vlc_preparser_seek_arg seek_arg;
         if ( test_params[i].b_use_pos )
         {
-            seek_arg.type = VLC_THUMBNAILER_SEEK_POS;
+            seek_arg.type = VLC_PREPARSER_SEEK_POS;
             seek_arg.pos = test_params[i].f_pos;
             seek_arg.speed = test_params[i].b_fast_seek ?
-                VLC_THUMBNAILER_SEEK_FAST : VLC_THUMBNAILER_SEEK_PRECISE;
+                VLC_PREPARSER_SEEK_FAST : VLC_PREPARSER_SEEK_PRECISE;
         }
         else
         {
-            seek_arg.type = VLC_THUMBNAILER_SEEK_TIME;
+            seek_arg.type = VLC_PREPARSER_SEEK_TIME;
             seek_arg.time = test_params[i].i_time;
             seek_arg.speed = test_params[i].b_fast_seek ?
-                VLC_THUMBNAILER_SEEK_FAST : VLC_THUMBNAILER_SEEK_PRECISE;
+                VLC_PREPARSER_SEEK_FAST : VLC_PREPARSER_SEEK_PRECISE;
         }
         static const struct vlc_thumbnailer_cbs cbs = {
             .on_ended = thumbnailer_callback,
         };
-        id = vlc_thumbnailer_Request( p_thumbnailer, p_item, &seek_arg,
-                                      &cbs, &ctx );
-        assert( id != VLC_THUMBNAILER_REQ_ID_INVALID );
+        id = vlc_preparser_GenerateThumbnail( p_thumbnailer, p_item, &seek_arg,
+                                              &cbs, &ctx );
+        assert( id != VLC_PREPARSER_REQ_ID_INVALID );
 
         while ( ctx.b_done == false )
             vlc_cond_wait( &ctx.cond, &ctx.lock );
@@ -167,21 +181,29 @@ static void test_thumbnails( libvlc_instance_t* p_vlc )
         input_item_Release( p_item );
         free( psz_mrl );
 
-        vlc_thumbnailer_Delete( p_thumbnailer );
+        vlc_preparser_Delete( p_thumbnailer );
     }
 }
 
-static void thumbnailer_callback_cancel( picture_t* p_thumbnail, void *data )
+static void thumbnailer_callback_cancel( input_item_t *item, int status,
+                                         picture_t* p_thumbnail, void *data )
 {
-    (void) data;
-    /* This callback should not be called since the request is cancelled */
+    (void) item;
     assert( p_thumbnail == NULL );
+    assert( status == -EINTR );
+
+    vlc_sem_t *sem = data;
+    vlc_sem_post(sem);
 }
 
 static void test_cancel_thumbnail( libvlc_instance_t* p_vlc )
 {
-    vlc_thumbnailer_t* p_thumbnailer = vlc_thumbnailer_Create(
-                VLC_OBJECT( p_vlc->p_libvlc_int ), VLC_TICK_INVALID );
+    const struct vlc_preparser_cfg cfg = {
+        .types = VLC_PREPARSER_TYPE_THUMBNAIL,
+        .timeout = VLC_TICK_INVALID,
+    };
+    vlc_preparser_t* p_thumbnailer = vlc_preparser_New(
+                VLC_OBJECT( p_vlc->p_libvlc_int ), &cfg );
     assert( p_thumbnailer != NULL );
 
     const char* psz_mrl = "mock://video_track_count=0;audio_track_count=1;"
@@ -195,18 +217,18 @@ static void test_cancel_thumbnail( libvlc_instance_t* p_vlc )
         .on_ended = thumbnailer_callback_cancel,
     };
 
-    vlc_thumbnailer_req_id id =
-        vlc_thumbnailer_Request( p_thumbnailer, p_item, NULL, &cbs, NULL );
+    vlc_sem_t sem;
+    vlc_sem_init(&sem, 0);
+    vlc_preparser_req_id id =
+        vlc_preparser_GenerateThumbnail( p_thumbnailer, p_item, NULL, &cbs, &sem );
 
-    vlc_thumbnailer_Cancel( p_thumbnailer, id );
+    vlc_preparser_Cancel( p_thumbnailer, id );
 
-    /* Check that thumbnailer_callback_cancel is not called, even after the
-     * normal termination of the parsing. */
-    (vlc_tick_sleep)(VLC_TICK_FROM_MS(250));
+    vlc_sem_wait(&sem);
 
     input_item_Release( p_item );
 
-    vlc_thumbnailer_Delete( p_thumbnailer );
+    vlc_preparser_Delete( p_thumbnailer );
 }
 
 int main( void )



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/162e77f9cd927fdcf93a76dc410755b04f5f2e01...f9b455e77c5c3c654d9378852264086aca9cb163

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/162e77f9cd927fdcf93a76dc410755b04f5f2e01...f9b455e77c5c3c654d9378852264086aca9cb163
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