diff --git a/include/meson.build b/include/meson.build index 11c7c07900..e9b434f4a6 100644 --- a/include/meson.build +++ b/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', diff --git a/include/vlc_preparser.h b/include/vlc_preparser.h index 68951b1a4e..51548fb728 100644 --- a/include/vlc_preparser.h +++ b/include/vlc_preparser.h @@ -49,12 +49,77 @@ typedef size_t vlc_preparser_req_id; #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 +{ + 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; +}; + /** * This function creates the preparser object and thread. * @@ -93,6 +158,29 @@ VLC_API vlc_preparser_req_id 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 * diff --git a/include/vlc_thumbnailer.h b/include/vlc_thumbnailer.h deleted file mode 100644 index 29f907054a..0000000000 --- a/include/vlc_thumbnailer.h +++ /dev/null @@ -1,148 +0,0 @@ -/***************************************************************************** - * vlc_thumbnailer.h: Thumbnailing API - ***************************************************************************** - * Copyright (C) 2018 VLC authors and VideoLAN - * - * Authors: Hugo Beauzée-Luyssen - * - * 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 -#include - -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 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 Is the opaque pointer passed as vlc_thumbnailer_Request last - * parameter - */ - void (*on_ended)(input_item_t *item, int status, 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 diff --git a/lib/core.c b/lib/core.c index 2a0777129a..768ea15d58 100644 --- a/lib/core.c +++ b/lib/core.c @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -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 ); @@ -277,15 +276,16 @@ vlc_preparser_t *libvlc_get_preparser(libvlc_instance_t *instance) 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) { thumb = instance->thumbnailer = - vlc_thumbnailer_Create(VLC_OBJECT(instance->p_libvlc_int), 0); + vlc_preparser_New(VLC_OBJECT(instance->p_libvlc_int), 1, 0, + VLC_PREPARSER_TYPE_THUMBNAIL); } vlc_mutex_unlock(&instance->lazy_init_lock); diff --git a/lib/libvlc_internal.h b/lib/libvlc_internal.h index 8308150db5..aebe61add5 100644 --- a/lib/libvlc_internal.h +++ b/lib/libvlc_internal.h @@ -36,7 +36,7 @@ #include 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 diff --git a/lib/media.c b/lib/media.c index 01e0efb63c..cf8914a620 100644 --- a/lib/media.c +++ b/lib/media.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include "../src/libvlc.h" @@ -924,7 +923,7 @@ 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( input_item_t *item, int status, @@ -952,18 +951,18 @@ static void media_on_thumbnail_ready( input_item_t *item, int status, 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 ) ) @@ -979,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 ); @@ -999,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 ); @@ -1018,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 ); @@ -1031,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 ); diff --git a/modules/gui/qt/medialibrary/mlvideo.cpp b/modules/gui/qt/medialibrary/mlvideo.cpp index d54c44d2f0..8b2b7fc3ce 100644 --- a/modules/gui/qt/medialibrary/mlvideo.cpp +++ b/modules/gui/qt/medialibrary/mlvideo.cpp @@ -20,7 +20,6 @@ #include -#include #include "mlhelper.hpp" #include "util/vlctick.hpp" diff --git a/modules/misc/medialibrary/Thumbnailer.cpp b/modules/misc/medialibrary/Thumbnailer.cpp index 86335b79b4..3eaa80bd0f 100644 --- a/modules/misc/medialibrary/Thumbnailer.cpp +++ b/modules/misc/medialibrary/Thumbnailer.cpp @@ -24,23 +24,24 @@ #include "medialibrary.h" -#include #include #include #include #include +#include #include 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 ) ) ); + m_thumbnailer.reset( vlc_preparser_New( VLC_OBJECT( ml ), 1, + VLC_TICK_FROM_SEC( 3 ), + VLC_PREPARSER_TYPE_THUMBNAIL ) ); 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( input_item_t *, int, picture_t* thumbnail, void *data ) @@ -71,20 +72,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; diff --git a/modules/misc/medialibrary/medialibrary.h b/modules/misc/medialibrary/medialibrary.h index aed6098e1f..a50690fd86 100644 --- a/modules/misc/medialibrary/medialibrary.h +++ b/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; @@ -144,7 +144,7 @@ private: vlc::threads::mutex m_mutex; vlc::threads::condition_variable m_cond; ThumbnailerCtx* m_currentContext; - std::unique_ptr m_thumbnailer; + std::unique_ptr m_thumbnailer; }; class MediaLibrary : public medialibrary::IMediaLibraryCb diff --git a/src/Makefile.am b/src/Makefile.am index f7831d8924..853d56680a 100644 --- a/src/Makefile.am +++ b/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 \ diff --git a/src/libvlccore.sym b/src/libvlccore.sym index cb8533dc9a..018399b898 100644 --- a/src/libvlccore.sym +++ b/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 diff --git a/src/preparser/preparser.c b/src/preparser/preparser.c index 6a08208ded..6a4e39a9b5 100644 --- a/src/preparser/preparser.c +++ b/src/preparser/preparser.c @@ -26,17 +26,23 @@ #include #include #include -#include #include "input/input_interface.h" #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 *parser; + vlc_executor_t *thumbnailer; vlc_tick_t timeout; atomic_bool deactivated; @@ -50,10 +56,13 @@ struct task vlc_preparser_t *preparser; input_item_t *item; int options; - const input_item_parser_cbs_t *cbs; + struct vlc_preparser_seek_arg seek_arg; + union vlc_preparser_cbs cbs; void *userdata; vlc_preparser_req_id id; + picture_t *pic; + vlc_sem_t preparse_ended; int preparse_status; atomic_bool interrupted; @@ -63,42 +72,10 @@ struct task struct vlc_list node; /**< node of vlc_preparser_t.submitted_tasks */ }; -struct vlc_thumbnailer_t -{ - vlc_object_t* parent; - vlc_executor_t *executor; - vlc_mutex_t lock; - - vlc_thumbnailer_req_id current_id; - vlc_tick_t timeout; - - struct vlc_list submitted_tasks; /**< list of struct th_task */ -}; - -typedef struct th_task -{ - vlc_thumbnailer_t *thumbnailer; - - struct vlc_thumbnailer_seek_arg seek_arg; - input_item_t *item; - const struct vlc_thumbnailer_cbs *cbs; - void* userdata; - - vlc_sem_t preparse_ended; - int preparse_status; - atomic_bool interrupted; - - 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 */ -} th_task_t; - static struct task * TaskNew(vlc_preparser_t *preparser, void (*run)(void *), input_item_t *item, - int options, const input_item_parser_cbs_t *cbs, void *userdata) + 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) @@ -109,6 +86,14 @@ TaskNew(vlc_preparser_t *preparser, void (*run)(void *), 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); @@ -165,7 +150,8 @@ NotifyPreparseEnded(struct task *task) else if (task->preparse_status == VLC_SUCCESS) input_item_SetPreparsed(task->item); - 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 @@ -188,8 +174,8 @@ OnParserSubtreeAdded(input_item_t *item, input_item_node_t *subtree, if (atomic_load(&task->interrupted)) return; - if (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 @@ -203,8 +189,9 @@ OnParserAttachmentsAdded(input_item_t *item, if (atomic_load(&task->interrupted)) return; - if (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 @@ -311,11 +298,6 @@ end: TaskDelete(task); } -static void NotifyThumbnail(th_task_t *task, picture_t *pic) -{ - task->cbs->on_ended(task->item, task->preparse_status, pic, task->userdata); -} - static void on_thumbnailer_input_event( input_thread_t *input, const struct vlc_input_event *event, void *userdata ) @@ -326,7 +308,7 @@ on_thumbnailer_input_event( input_thread_t *input, event->state.value != END_S ) ) ) return; - th_task_t *task = userdata; + struct task *task = userdata; if (event->type == INPUT_EVENT_THUMBNAIL_READY) { @@ -336,20 +318,13 @@ on_thumbnailer_input_event( input_thread_t *input, vlc_sem_post(&task->preparse_ended); } -static void -ThTaskDestroy(th_task_t *task) -{ - input_item_Release(task->item); - free(task); -} - static void ThumbnailerRun(void *userdata) { vlc_thread_set_name("vlc-run-thumb"); - th_task_t *task = userdata; - vlc_thumbnailer_t *thumbnailer = task->thumbnailer; + struct task *task = userdata; + vlc_preparser_t *preparser = task->preparser; static const struct vlc_input_thread_callbacks cbs = { .on_event = on_thumbnailer_input_event, @@ -361,27 +336,27 @@ ThumbnailerRun(void *userdata) .cbs_data = task, }; - vlc_tick_t deadline = thumbnailer->timeout != VLC_TICK_INVALID ? - vlc_tick_now() + thumbnailer->timeout : + vlc_tick_t deadline = preparser->timeout != VLC_TICK_INVALID ? + vlc_tick_now() + preparser->timeout : VLC_TICK_INVALID; input_thread_t* input = - input_Create( thumbnailer->parent, task->item, &cfg ); + input_Create( preparser->owner, 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; + 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_THUMBNAILER_SEEK_NONE: + case VLC_PREPARSER_SEEK_NONE: break; - case VLC_THUMBNAILER_SEEK_TIME: + case VLC_PREPARSER_SEEK_TIME: input_SetTime(input, task->seek_arg.time, fast_seek); break; - case VLC_THUMBNAILER_SEEK_POS: + case VLC_PREPARSER_SEEK_POS: input_SetPosition(input, task->seek_arg.pos, fast_seek); break; default: @@ -409,11 +384,13 @@ ThumbnailerRun(void *userdata) picture_t* pic = task->pic; task->pic = NULL; - vlc_mutex_lock(&thumbnailer->lock); + vlc_mutex_lock(&preparser->lock); vlc_list_remove(&task->node); - vlc_mutex_unlock(&thumbnailer->lock); + vlc_mutex_unlock(&preparser->lock); - NotifyThumbnail(task, task->preparse_status == VLC_SUCCESS ? pic : NULL); + task->cbs.thumbnailer->on_ended(task->item, task->preparse_status, + task->preparse_status == VLC_SUCCESS ? + pic : NULL, task->userdata); if (pic) picture_Release(pic); @@ -422,7 +399,7 @@ ThumbnailerRun(void *userdata) input_Close(input); error: - ThTaskDestroy(task); + TaskDelete(task); } static void @@ -438,7 +415,9 @@ vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent, unsigned max_threads, { assert(max_threads >= 1); assert(timeout >= 0); - assert(request_type & (VLC_PREPARSER_TYPE_FETCHMETA_ALL|VLC_PREPARSER_TYPE_PARSE)); + assert(request_type & (VLC_PREPARSER_TYPE_FETCHMETA_ALL| + VLC_PREPARSER_TYPE_PARSE| + VLC_PREPARSER_TYPE_THUMBNAIL)); vlc_preparser_t* preparser = malloc( sizeof *preparser ); if (!preparser) @@ -465,6 +444,15 @@ vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent, unsigned max_threads, else preparser->fetcher = NULL; + if (request_type & VLC_PREPARSER_TYPE_THUMBNAIL) + { + preparser->thumbnailer = vlc_executor_New(1); + if (!preparser->thumbnailer) + goto error_thumbnail; + } + else + preparser->thumbnailer = NULL; + atomic_init( &preparser->deactivated, false ); vlc_mutex_init(&preparser->lock); @@ -473,6 +461,9 @@ vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent, unsigned max_threads, return preparser; +error_thumbnail: + if (preparser->fetcher != NULL) + input_fetcher_Delete(preparser->fetcher); error_fetcher: if (preparser->parser != NULL) vlc_executor_Delete(preparser->parser); @@ -489,6 +480,8 @@ vlc_preparser_req_id vlc_preparser_Push( vlc_preparser_t *preparser, input_item_ if( atomic_load( &preparser->deactivated ) ) return VLC_PREPARSER_REQ_ID_INVALID; + assert((type_options & VLC_PREPARSER_TYPE_THUMBNAIL) == 0); + assert(type_options & VLC_PREPARSER_TYPE_PARSE || type_options & VLC_PREPARSER_TYPE_FETCHMETA_ALL); @@ -499,8 +492,12 @@ vlc_preparser_req_id vlc_preparser_Push( vlc_preparser_t *preparser, input_item_ assert(cbs != NULL && cbs->on_ended != NULL); - struct task *task = - TaskNew(preparser, ParserRun, item, type_options, cbs, cbs_userdata); + 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 VLC_PREPARSER_REQ_ID_INVALID; @@ -523,6 +520,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); @@ -542,8 +568,13 @@ size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req_id id vlc_list_remove(&task->node); vlc_mutex_unlock(&preparser->lock); task->preparse_status = -EINTR; - task->cbs->parser.on_ended(task->item, task->preparse_status, - task->userdata); + 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 @@ -586,144 +617,8 @@ void vlc_preparser_Delete( vlc_preparser_t *preparser ) if( preparser->fetcher ) input_fetcher_Delete( preparser->fetcher ); - free( preparser ); -} + if (preparser->thumbnailer != NULL) + vlc_executor_Delete(preparser->thumbnailer); -static void ThumbnailerRun(void *); - -static th_task_t * -ThTaskNew(vlc_thumbnailer_t *thumbnailer, input_item_t *item, - const struct vlc_thumbnailer_seek_arg *seek_arg, - const struct vlc_thumbnailer_cbs *cbs, void *userdata ) -{ - th_task_t *task = malloc(sizeof(*task)); - if (!task) - return NULL; - - vlc_sem_init(&task->preparse_ended, 0); - atomic_init(&task->interrupted, false); - task->preparse_status = VLC_EGENERIC; - - 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->pic = NULL; - - task->runnable.run = ThumbnailerRun; - task->runnable.userdata = task; - - input_item_Hold(item); - - return 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 ); - - th_task_t *task = ThTaskNew(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); - - th_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); - task->preparse_status = -EINTR; - NotifyThumbnail(task, NULL); - ThTaskDestroy(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() */ - atomic_store(&task->interrupted, true); - vlc_sem_post(&task->preparse_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_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 ); + free( preparser ); } diff --git a/test/src/input/thumbnail.c b/test/src/input/thumbnail.c index d46035c48d..0927e5b667 100644 --- a/test/src/input/thumbnail.c +++ b/test/src/input/thumbnail.c @@ -22,7 +22,7 @@ #include "../lib/libvlc_internal.h" #include -#include +#include #include #include @@ -128,8 +128,9 @@ 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 ); + vlc_preparser_t* p_thumbnailer = vlc_preparser_New( + VLC_OBJECT( p_vlc->p_libvlc_int ), 1, test_params[i].i_timeout, + VLC_PREPARSER_TYPE_THUMBNAIL ); assert( p_thumbnailer != NULL ); @@ -145,28 +146,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 ); @@ -176,7 +177,7 @@ 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 ); } } @@ -193,8 +194,9 @@ static void thumbnailer_callback_cancel( input_item_t *item, int status, 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 ); + vlc_preparser_t* p_thumbnailer = vlc_preparser_New( + VLC_OBJECT( p_vlc->p_libvlc_int ), 1, VLC_TICK_INVALID, + VLC_PREPARSER_TYPE_THUMBNAIL ); assert( p_thumbnailer != NULL ); const char* psz_mrl = "mock://video_track_count=0;audio_track_count=1;" @@ -210,16 +212,16 @@ static void test_cancel_thumbnail( libvlc_instance_t* p_vlc ) vlc_sem_t sem; vlc_sem_init(&sem, 0); - vlc_thumbnailer_req_id id = - vlc_thumbnailer_Request( p_thumbnailer, p_item, NULL, &cbs, &sem ); + 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 ); vlc_sem_wait(&sem); input_item_Release( p_item ); - vlc_thumbnailer_Delete( p_thumbnailer ); + vlc_preparser_Delete( p_thumbnailer ); } int main( void )