vlc | branch: master | Hugo Beauzée-Luyssen <[email protected]> | Mon Jun 17 15:54:02 2019 +0200| [5961eeaa01a1bbe278280dfda6e4c99963c4d725] | committer: Hugo Beauzée-Luyssen
medialibrary: Bump version & update API usages - Multiple thumbnail can now be used - Discovery, thumbnailing & metadata extractions are now interruptible - An entry_point_added event has been added > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=5961eeaa01a1bbe278280dfda6e4c99963c4d725 --- include/vlc_media_library.h | 62 ++++++++++++++++---- modules/gui/qt/components/mediacenter/mlalbum.cpp | 2 +- modules/gui/qt/components/mediacenter/mlartist.cpp | 2 +- modules/gui/qt/components/mediacenter/mlvideo.cpp | 13 +++-- modules/misc/medialibrary/MetadataExtractor.cpp | 30 ++++++---- modules/misc/medialibrary/Thumbnailer.cpp | 68 ++++++++++------------ modules/misc/medialibrary/entities.cpp | 68 ++++++++++++++-------- modules/misc/medialibrary/medialib.cpp | 31 ++++++++-- modules/misc/medialibrary/medialibrary.h | 39 ++++++++++--- src/misc/medialibrary.c | 12 +++- 10 files changed, 221 insertions(+), 106 deletions(-) diff --git a/include/vlc_media_library.h b/include/vlc_media_library.h index 6d2d39d0a0..e6205f31ca 100644 --- a/include/vlc_media_library.h +++ b/include/vlc_media_library.h @@ -68,6 +68,24 @@ typedef enum vlc_ml_track_type_t VLC_ML_TRACK_TYPE_AUDIO, } vlc_ml_track_type_t; +typedef enum vlc_ml_thumbnail_size_t +{ + VLC_ML_THUMBNAIL_SMALL, + VLC_ML_THUMBNAIL_BANNER, + + VLC_ML_THUMBNAIL_SIZE_COUNT +} vlc_ml_thumbnail_size_t; + +typedef struct vlc_ml_thumbnail_t +{ + char* psz_mrl; + /** + * True if a thumbnail is available, or if thumbnail generation was + * attempted but failed + */ + bool b_generated; +} vlc_ml_thumbnail_t; + typedef struct vlc_ml_movie_t { char* psz_summary; @@ -182,10 +200,8 @@ typedef struct vlc_ml_media_t time_t i_last_played_date; char* psz_title; - char* psz_artwork_mrl; - /* True if a thumbnail is available, or if thumbnail generation was - * attempted but failed */ - bool b_artwork_generated; + vlc_ml_thumbnail_t thumbnails[VLC_ML_THUMBNAIL_SIZE_COUNT]; + bool b_is_favorite; union @@ -209,7 +225,7 @@ typedef struct vlc_ml_artist_t int64_t i_id; char* psz_name; char* psz_shortbio; - char* psz_artwork_mrl; + vlc_ml_thumbnail_t thumbnails[VLC_ML_THUMBNAIL_SIZE_COUNT]; char* psz_mb_id; unsigned int i_nb_album; @@ -226,7 +242,7 @@ typedef struct vlc_ml_album_t { int64_t i_id; char* psz_title; char* psz_summary; - char* psz_artwork_mrl; + vlc_ml_thumbnail_t thumbnails[VLC_ML_THUMBNAIL_SIZE_COUNT]; char* psz_artist; int64_t i_artist_id; @@ -439,8 +455,8 @@ enum vlc_ml_control VLC_ML_MEDIA_INCREASE_PLAY_COUNT, /**< arg1: media id; can fail */ VLC_ML_MEDIA_GET_MEDIA_PLAYBACK_PREF, /**< arg1: media id; arg2: vlc_ml_playback_pref; arg3: char**; */ VLC_ML_MEDIA_SET_MEDIA_PLAYBACK_PREF, /**< arg1: media id; arg2: vlc_ml_playback_pref; arg3: const char*; */ - VLC_ML_MEDIA_SET_THUMBNAIL, /**< arg1: media id; arg2: const char*; */ - VLC_ML_MEDIA_GENERATE_THUMBNAIL, /**< arg1: media id; */ + VLC_ML_MEDIA_SET_THUMBNAIL, /**< arg1: media id; arg2: const char*; arg3: vlc_ml_thumbnail_size_t */ + VLC_ML_MEDIA_GENERATE_THUMBNAIL, /**< arg1: media id; arg2: vlc_ml_thumbnail_size_t; arg3: width; arg4: height; arg5: position */ VLC_ML_MEDIA_ADD_EXTERNAL_MRL, /**< arg1: media id; arg2: const char*; arg3: type(vlc_ml_file_type_t) */ }; @@ -543,6 +559,16 @@ enum vlc_ml_event_type */ VLC_ML_EVENT_RELOAD_COMPLETED, /** + * Sent when a new entry point gets added to the database. + * The entry point that was added is stored in + * vlc::ml_event_t::entry_point_added::psz_entry_point, and the success or failure + * state is stored in vlc_ml_event_t::entry_point_added::b_success + * If successful, this event won't be emited again for this entry point. + * In case of failure, this event will be fired again if the same entry point + * is queued for discovery again. + */ + VLC_ML_EVENT_ENTRY_POINT_ADDED, + /** * Sent when an entry point removal request has been processed. * The removed entry point is stored in * vlc_ml_event_t::entry_point_removed::psz_entry_point and the success or failure @@ -618,6 +644,11 @@ typedef struct vlc_ml_event_t { const char* psz_entry_point; bool b_success; + } entry_point_added; + struct + { + const char* psz_entry_point; + bool b_success; } entry_point_removed; struct { @@ -652,6 +683,7 @@ typedef struct vlc_ml_event_t struct { const vlc_ml_media_t* p_media; + vlc_ml_thumbnail_size_t i_size; bool b_success; } media_thumbnail_generated; }; @@ -848,14 +880,20 @@ static inline int vlc_ml_media_set_playback_pref( vlc_medialibrary_t* p_ml, int6 return vlc_ml_control( p_ml, VLC_ML_MEDIA_SET_MEDIA_PLAYBACK_PREF, i_media_id, i_pref, psz_value ); } -static inline int vlc_ml_media_set_thumbnail( vlc_medialibrary_t* p_ml, int64_t i_media_id, const char* psz_mrl ) +static inline int vlc_ml_media_set_thumbnail( vlc_medialibrary_t* p_ml, int64_t i_media_id, + const char* psz_mrl, vlc_ml_thumbnail_size_t sizeType ) { - return vlc_ml_control( p_ml, VLC_ML_MEDIA_SET_THUMBNAIL, i_media_id, psz_mrl ); + return vlc_ml_control( p_ml, VLC_ML_MEDIA_SET_THUMBNAIL, i_media_id, psz_mrl, sizeType ); } -static inline int vlc_ml_media_generate_thumbnail( vlc_medialibrary_t* p_ml, int64_t i_media_id ) +static inline int vlc_ml_media_generate_thumbnail( vlc_medialibrary_t* p_ml, int64_t i_media_id, + vlc_ml_thumbnail_size_t size_type, + uint32_t i_desired_width, + uint32_t i_desired_height, + float position ) { - return vlc_ml_control( p_ml, VLC_ML_MEDIA_GENERATE_THUMBNAIL, i_media_id ); + return vlc_ml_control( p_ml, VLC_ML_MEDIA_GENERATE_THUMBNAIL, i_media_id, + size_type, i_desired_width, i_desired_height, position ); } static inline int vlc_ml_media_add_external_mrl( vlc_medialibrary_t* p_ml, int64_t i_media_id, diff --git a/modules/gui/qt/components/mediacenter/mlalbum.cpp b/modules/gui/qt/components/mediacenter/mlalbum.cpp index 271133f8f8..88df4f034a 100644 --- a/modules/gui/qt/components/mediacenter/mlalbum.cpp +++ b/modules/gui/qt/components/mediacenter/mlalbum.cpp @@ -25,7 +25,7 @@ MLAlbum::MLAlbum(vlc_medialibrary_t* _ml, const vlc_ml_album_t *_data, QObject * , m_title ( QString::fromUtf8( _data->psz_title ) ) , m_releaseYear ( _data->i_year ) , m_shortSummary( QString::fromUtf8( _data->psz_summary ) ) - , m_cover ( QString::fromUtf8( _data->psz_artwork_mrl ) ) + , m_cover ( QString::fromUtf8( _data->thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl ) ) , m_mainArtist ( QString::fromUtf8( _data->psz_artist ) ) , m_nbTracks ( _data->i_nb_tracks ) { diff --git a/modules/gui/qt/components/mediacenter/mlartist.cpp b/modules/gui/qt/components/mediacenter/mlartist.cpp index bf4e2ee2a7..98a6b0b96b 100644 --- a/modules/gui/qt/components/mediacenter/mlartist.cpp +++ b/modules/gui/qt/components/mediacenter/mlartist.cpp @@ -24,7 +24,7 @@ MLArtist::MLArtist(const vlc_ml_artist_t* _data, QObject *_parent) , m_id ( _data->i_id, VLC_ML_PARENT_ARTIST ) , m_name ( QString::fromUtf8( _data->psz_name ) ) , m_shortBio( QString::fromUtf8( _data->psz_shortbio ) ) - , m_cover ( QString::fromUtf8( _data->psz_artwork_mrl ) ) + , m_cover ( QString::fromUtf8( _data->thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl ) ) , m_nbAlbums( _data->i_nb_album ) { assert( _data ); diff --git a/modules/gui/qt/components/mediacenter/mlvideo.cpp b/modules/gui/qt/components/mediacenter/mlvideo.cpp index 84190f6ad7..4305327be0 100644 --- a/modules/gui/qt/components/mediacenter/mlvideo.cpp +++ b/modules/gui/qt/components/mediacenter/mlvideo.cpp @@ -27,9 +27,9 @@ MLVideo::MLVideo(vlc_medialibrary_t* ml, const vlc_ml_media_t* data, QObject* pa , m_ml( ml ) , m_id( data->i_id, VLC_ML_PARENT_UNKNOWN ) , m_title( QString::fromUtf8( data->psz_title ) ) - , m_thumbnail( QString::fromUtf8( data->psz_artwork_mrl ) ) + , m_thumbnail( QString::fromUtf8( data->thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl ) ) , m_playCount( data->i_playcount ) - , m_thumbnailGenerated( data->b_artwork_generated ) + , m_thumbnailGenerated( data->thumbnails[VLC_ML_THUMBNAIL_SMALL].b_generated ) , m_ml_event_handle( nullptr, [this](vlc_ml_event_callback_t* cb ) { assert( m_ml != nullptr ); vlc_ml_event_unregister_callback( m_ml, cb ); @@ -88,14 +88,16 @@ void MLVideo::onMlEvent( void* data, const vlc_ml_event_t* event ) void MLVideo::onMlEvent( const vlc_ml_event_t* event ) { - if ( event->i_type != VLC_ML_EVENT_MEDIA_THUMBNAIL_GENERATED ) + if ( event->i_type != VLC_ML_EVENT_MEDIA_THUMBNAIL_GENERATED || + event->media_thumbnail_generated.i_size != VLC_ML_THUMBNAIL_SMALL ) return; m_thumbnailGenerated = true; if ( event->media_thumbnail_generated.p_media->i_id != m_id.id ) return; if ( event->media_thumbnail_generated.b_success == false ) return; - auto thumbnailMrl = event->media_thumbnail_generated.p_media->psz_artwork_mrl; + auto thumbnailMrl = event->media_thumbnail_generated + .p_media->thumbnails[event->media_thumbnail_generated.i_size].psz_mrl; m_thumbnail = QString::fromUtf8( thumbnailMrl ); vlc_ml_event_unregister_from_callback( m_ml, m_ml_event_handle.release() ); emit onThumbnailChanged( m_thumbnail ); @@ -116,7 +118,8 @@ QString MLVideo::getThumbnail() if ( m_thumbnailGenerated == false ) { m_ml_event_handle.reset( vlc_ml_event_register_callback( m_ml, onMlEvent, this ) ); - vlc_ml_media_generate_thumbnail( m_ml, m_id.id ); + vlc_ml_media_generate_thumbnail( m_ml, m_id.id, VLC_ML_THUMBNAIL_SMALL, + 512, 320, .15 ); } return m_thumbnail; diff --git a/modules/misc/medialibrary/MetadataExtractor.cpp b/modules/misc/medialibrary/MetadataExtractor.cpp index 7348ab3be3..0047b7b0fc 100644 --- a/modules/misc/medialibrary/MetadataExtractor.cpp +++ b/modules/misc/medialibrary/MetadataExtractor.cpp @@ -31,12 +31,12 @@ MetadataExtractor::MetadataExtractor( vlc_object_t* parent ) void MetadataExtractor::onParserEnded( ParseContext& ctx, int status ) { - vlc::threads::mutex_locker lock( ctx.m_mutex ); + vlc::threads::mutex_locker lock( ctx.mde->m_mutex ); // We need to probe the item now, but not from the input thread ctx.success = status == VLC_SUCCESS; ctx.needsProbing = true; - ctx.m_cond.signal(); + ctx.mde->m_cond.signal(); } void MetadataExtractor::populateItem( medialibrary::parser::IItem& item, input_item_t* inputItem ) @@ -150,7 +150,7 @@ medialibrary::parser::Status MetadataExtractor::run( medialibrary::parser::IItem &MetadataExtractor::onParserEnded, &MetadataExtractor::onParserSubtreeAdded, }; - + m_currentCtx = &ctx; ctx.inputItem->i_preparse_depth = 1; ctx.inputParser = { input_item_Parse( ctx.inputItem.get(), m_obj, &cbs, @@ -158,14 +158,17 @@ medialibrary::parser::Status MetadataExtractor::run( medialibrary::parser::IItem &input_item_parser_id_Release }; if ( ctx.inputParser == nullptr ) + { + m_currentCtx = nullptr; return medialibrary::parser::Status::Fatal; + } { - vlc::threads::mutex_locker lock( ctx.m_mutex ); + vlc::threads::mutex_locker lock( m_mutex ); auto deadline = vlc_tick_now() + VLC_TICK_FROM_SEC( 5 ); - while ( ctx.needsProbing == false ) + while ( ctx.needsProbing == false && ctx.inputParser != nullptr ) { - auto res = ctx.m_cond.timedwait( ctx.m_mutex, deadline ); + auto res = m_cond.timedwait( m_mutex, deadline ); if ( res != 0 ) { msg_Dbg( m_obj, "Timed out while extracting %s metadata", @@ -173,9 +176,10 @@ medialibrary::parser::Status MetadataExtractor::run( medialibrary::parser::IItem break; } } + m_currentCtx = nullptr; } - if ( !ctx.success ) + if ( !ctx.success || ctx.inputParser == nullptr ) return medialibrary::parser::Status::Fatal; populateItem( item, ctx.inputItem.get() ); @@ -188,11 +192,6 @@ const char* MetadataExtractor::name() const return "libvlccore extraction"; } -uint8_t MetadataExtractor::nbThreads() const -{ - return 1; -} - medialibrary::parser::Step MetadataExtractor::targetedStep() const { return medialibrary::parser::Step::MetadataExtraction; @@ -210,3 +209,10 @@ void MetadataExtractor::onFlushing() void MetadataExtractor::onRestarted() { } + +void MetadataExtractor::stop() +{ + vlc::threads::mutex_locker lock{ m_mutex }; + if ( m_currentCtx != nullptr ) + input_item_parser_id_Interrupt( m_currentCtx->inputParser.get() ); +} diff --git a/modules/misc/medialibrary/Thumbnailer.cpp b/modules/misc/medialibrary/Thumbnailer.cpp index 33d90732cd..8e839ba1f6 100644 --- a/modules/misc/medialibrary/Thumbnailer.cpp +++ b/modules/misc/medialibrary/Thumbnailer.cpp @@ -30,9 +30,8 @@ #include <vlc_url.h> #include <vlc_cxx_helpers.hpp> -Thumbnailer::Thumbnailer( vlc_medialibrary_module_t* ml, std::string thumbnailsDir ) +Thumbnailer::Thumbnailer( vlc_medialibrary_module_t* ml ) : m_ml( ml ) - , m_thumbnailDir( std::move( thumbnailsDir ) ) , m_thumbnailer( nullptr, &vlc_thumbnailer_Release ) { m_thumbnailer.reset( vlc_thumbnailer_Create( VLC_OBJECT( ml ) ) ); @@ -40,71 +39,68 @@ Thumbnailer::Thumbnailer( vlc_medialibrary_module_t* ml, std::string thumbnailsD throw std::runtime_error( "Failed to instantiate a vlc_thumbnailer_t" ); } -struct ThumbnailerCtx -{ - ~ThumbnailerCtx() - { - if ( item != nullptr ) - input_item_Release( item ); - if ( thumbnail != nullptr ) - picture_Release( thumbnail ); - } - vlc::threads::condition_variable cond; - vlc::threads::mutex mutex; - input_item_t* item; - bool done; - picture_t* thumbnail; -}; - -static void onThumbnailComplete( void* data, picture_t* thumbnail ) +void Thumbnailer::onThumbnailComplete( void* data, picture_t* thumbnail ) { ThumbnailerCtx* ctx = static_cast<ThumbnailerCtx*>( data ); { - vlc::threads::mutex_locker lock( ctx->mutex ); + vlc::threads::mutex_locker lock( ctx->thumbnailer->m_mutex ); ctx->done = true; ctx->thumbnail = thumbnail ? picture_Hold( thumbnail ) : nullptr; + ctx->thumbnailer->m_currentContext = nullptr; } - ctx->cond.signal(); + ctx->thumbnailer->m_cond.signal(); } -bool Thumbnailer::generate( medialibrary::MediaPtr media, const std::string& mrl ) +bool Thumbnailer::generate( const std::string& mrl, uint32_t desiredWidth, + uint32_t desiredHeight, float position, + const std::string& dest ) { ThumbnailerCtx ctx{}; - ctx.item = input_item_New( mrl.c_str(), media->title().c_str() ); - if ( unlikely( ctx.item == nullptr ) ) + auto item = vlc::wrap_cptr( input_item_New( mrl.c_str(), nullptr ), + &input_item_Release ); + if ( unlikely( item == nullptr ) ) return false; - input_item_AddOption( ctx.item, "no-hwdec", VLC_INPUT_OPTION_TRUSTED ); + input_item_AddOption( item.get(), "no-hwdec", VLC_INPUT_OPTION_TRUSTED ); ctx.done = false; + ctx.thumbnailer = this; { - vlc::threads::mutex_locker lock( ctx.mutex ); - vlc_thumbnailer_RequestByPos( m_thumbnailer.get(), .3f, - VLC_THUMBNAILER_SEEK_FAST, ctx.item, + vlc::threads::mutex_locker lock( m_mutex ); + m_currentContext = &ctx; + ctx.request = vlc_thumbnailer_RequestByPos( m_thumbnailer.get(), position, + VLC_THUMBNAILER_SEEK_FAST, item.get(), VLC_TICK_FROM_SEC( 3 ), &onThumbnailComplete, &ctx ); while ( ctx.done == false ) - ctx.cond.wait( ctx.mutex ); + m_cond.wait( m_mutex ); + m_currentContext = nullptr; } if ( ctx.thumbnail == nullptr ) return false; block_t* block; if ( picture_Export( VLC_OBJECT( m_ml ), &block, nullptr, ctx.thumbnail, - VLC_CODEC_JPEG, 512, 320, true ) != VLC_SUCCESS ) + VLC_CODEC_JPEG, desiredWidth, desiredHeight, true ) != VLC_SUCCESS ) return false; auto blockPtr = vlc::wrap_cptr( block, &block_Release ); - std::string outputPath = m_thumbnailDir + std::to_string( media->id() ) + ".jpg"; - auto f = vlc::wrap_cptr( vlc_fopen( outputPath.c_str(), "wb" ), &fclose ); + auto f = vlc::wrap_cptr( vlc_fopen( dest.c_str(), "wb" ), &fclose ); if ( f == nullptr ) return false; if ( fwrite( block->p_buffer, block->i_buffer, 1, f.get() ) != 1 ) return false; - auto thumbnailMrl = vlc::wrap_cptr( vlc_path2uri( outputPath.c_str(), nullptr ) ); - if ( thumbnailMrl == nullptr ) - return false; + return true; +} - return media->setThumbnail( thumbnailMrl.get() ); +void Thumbnailer::stop() +{ + vlc::threads::mutex_locker lock{ m_mutex }; + if ( m_currentContext != nullptr ) + { + vlc_thumbnailer_Cancel( m_thumbnailer.get(), m_currentContext->request ); + m_currentContext->done = true; + m_cond.signal(); + } } diff --git a/modules/misc/medialibrary/entities.cpp b/modules/misc/medialibrary/entities.cpp index ecbf9396cd..35975c8ab7 100644 --- a/modules/misc/medialibrary/entities.cpp +++ b/modules/misc/medialibrary/entities.cpp @@ -50,6 +50,40 @@ static auto const strdup_helper = []( std::string const& src, char*& dst ) return true; }; +static_assert( static_cast<uint32_t>( VLC_ML_THUMBNAIL_SMALL ) == + static_cast<uint32_t>( medialibrary::ThumbnailSizeType::Thumbnail ) && + static_cast<uint32_t>( VLC_ML_THUMBNAIL_BANNER ) == + static_cast<uint32_t>( medialibrary::ThumbnailSizeType::Banner ) && + static_cast<uint32_t>( VLC_ML_THUMBNAIL_SIZE_COUNT ) == + static_cast<uint32_t>( medialibrary::ThumbnailSizeType::Count ), + "Mismatched thumbnail sizes" ); + +template <typename T> +static bool convertThumbnails( const T input, vlc_ml_thumbnail_t *output ) +{ + for ( auto i = 0u; i < VLC_ML_THUMBNAIL_SIZE_COUNT; ++i ) + { + auto sizeType = static_cast<medialibrary::ThumbnailSizeType>( i ); + if ( input->isThumbnailGenerated( sizeType ) == false ) + { + output[i].psz_mrl = nullptr; + output[i].b_generated = false; + continue; + } + output[i].b_generated = true; + const auto thumbnailMrl = input->thumbnailMrl( sizeType ); + if ( thumbnailMrl.empty() == false ) + { + output[i].psz_mrl = strdup( thumbnailMrl.c_str() ); + if ( output[i].psz_mrl == nullptr ) + return false; + } + else + output[i].psz_mrl = nullptr; + } + return true; +} + bool Convert( const medialibrary::IAlbumTrack* input, vlc_ml_album_track_t& output ) { output.i_artist_id = input->artistId(); @@ -218,24 +252,8 @@ bool Convert( const medialibrary::IMedia* input, vlc_ml_media_t& output ) if ( convertTracks( input, output ) == false ) return false; - if ( input->isThumbnailGenerated() == true ) - { - output.b_artwork_generated = true; - const auto& thumbnail = input->thumbnail(); - if ( thumbnail.empty() == true ) - output.psz_artwork_mrl = nullptr; - else - { - output.psz_artwork_mrl = strdup( thumbnail.c_str() ); - if ( unlikely( output.psz_artwork_mrl == nullptr ) ) - return false; - } - } - else - { - output.psz_artwork_mrl = nullptr; - output.b_artwork_generated = false; - } + if ( convertThumbnails( input, output.thumbnails ) == false ) + return false; return true; } @@ -288,8 +306,10 @@ bool Convert( const medialibrary::IAlbum* input, vlc_ml_album_t& output ) output.i_year = input->releaseYear(); if( !strdup_helper( input->title(), output.psz_title ) || - !strdup_helper( input->shortSummary(), output.psz_summary ) || - !strdup_helper( input->thumbnailMrl(), output.psz_artwork_mrl ) ) + !strdup_helper( input->shortSummary(), output.psz_summary ) ) + return false; + + if ( convertThumbnails( input, output.thumbnails ) == false ) return false; auto artist = input->albumArtist(); @@ -337,10 +357,10 @@ bool Convert( const medialibrary::IArtist* input, vlc_ml_artist_t& output ) return false; if( !strdup_helper( input->shortBio(), output.psz_shortbio ) || - !strdup_helper( input->thumbnailMrl(), output.psz_artwork_mrl ) || !strdup_helper( input->musicBrainzId(), output.psz_mb_id ) ) return false; - return true; + + return convertThumbnails( input, output.thumbnails ); } bool Convert( const medialibrary::IGenre* input, vlc_ml_genre_t& output ) @@ -423,9 +443,9 @@ input_item_t* MediaToInputItem( const medialibrary::IMedia* media ) VLC_TICK_FROM_MS( media->duration() ), ITEM_TYPE_FILE, ITEM_NET_UNKNOWN ), &input_item_Release ); - if ( media->isThumbnailGenerated() == true ) + if ( media->isThumbnailGenerated( medialibrary::ThumbnailSizeType::Thumbnail ) == true ) { - auto thumbnail = media->thumbnail(); + auto thumbnail = media->thumbnailMrl( medialibrary::ThumbnailSizeType::Thumbnail ); if ( thumbnail.length() > 0 ) input_item_SetArtworkURL( inputItem.get(), thumbnail.c_str() ); } diff --git a/modules/misc/medialibrary/medialib.cpp b/modules/misc/medialibrary/medialib.cpp index c518bc9c4b..f19579d14f 100644 --- a/modules/misc/medialibrary/medialib.cpp +++ b/modules/misc/medialibrary/medialib.cpp @@ -63,6 +63,10 @@ private: { msg_Dbg( m_obj, "%s", msg.c_str() ); } + virtual void Verbose( const std::string& msg ) override + { + msg_Dbg( m_obj, "%s", msg.c_str() ); + } private: vlc_object_t* m_obj; @@ -227,6 +231,15 @@ void MediaLibrary::onReloadCompleted( const std::string& entryPoint, bool succes m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev ); } +void MediaLibrary::onEntryPointAdded( const std::string& entryPoint, bool success ) +{ + vlc_ml_event_t ev; + ev.i_type = VLC_ML_EVENT_ENTRY_POINT_ADDED; + ev.entry_point_added.psz_entry_point = entryPoint.c_str(); + ev.entry_point_added.b_success = success; + m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev ); +} + void MediaLibrary::onEntryPointRemoved( const std::string& entryPoint, bool success ) { vlc_ml_event_t ev; @@ -270,11 +283,14 @@ void MediaLibrary::onBackgroundTasksIdleChanged( bool idle ) m_vlc_ml->cbs->pf_send_event( m_vlc_ml, &ev ); } -void MediaLibrary::onMediaThumbnailReady( medialibrary::MediaPtr media, bool success ) +void MediaLibrary::onMediaThumbnailReady( medialibrary::MediaPtr media, + medialibrary::ThumbnailSizeType sizeType, + bool success ) { vlc_ml_event_t ev; ev.i_type = VLC_ML_EVENT_MEDIA_THUMBNAIL_GENERATED; ev.media_thumbnail_generated.b_success = success; + ev.media_thumbnail_generated.i_size = static_cast<vlc_ml_thumbnail_size_t>( sizeType ); auto mPtr = vlc::wrap_cptr<vlc_ml_media_t>( static_cast<vlc_ml_media_t*>( malloc( sizeof( vlc_ml_media_t ) ) ), vlc_ml_media_release ); @@ -327,8 +343,7 @@ bool MediaLibrary::Start() ml->addParserService( std::make_shared<MetadataExtractor>( VLC_OBJECT( m_vlc_ml ) ) ); try { - ml->addThumbnailer( std::make_shared<Thumbnailer>( - m_vlc_ml, std::move( thumbnailsDir ) ) ); + ml->addThumbnailer( std::make_shared<Thumbnailer>( m_vlc_ml ) ); } catch ( const std::runtime_error& ex ) { @@ -966,12 +981,18 @@ int MediaLibrary::controlMedia( int query, va_list args ) case VLC_ML_MEDIA_SET_THUMBNAIL: { auto mrl = va_arg( args, const char* ); - m->setThumbnail( mrl ); + auto sizeType = va_arg( args, int ); + m->setThumbnail( mrl, static_cast<medialibrary::ThumbnailSizeType>( sizeType ) ); return VLC_SUCCESS; } case VLC_ML_MEDIA_GENERATE_THUMBNAIL: { - auto res = m_ml->requestThumbnail( m ); + auto sizeType = va_arg( args, int ); + auto width = va_arg( args, uint32_t ); + auto height = va_arg( args, uint32_t ); + auto position = va_arg( args, double ); + auto res = m->requestThumbnail( static_cast<medialibrary::ThumbnailSizeType>( sizeType ), + width, height, position ); return res == true ? VLC_SUCCESS : VLC_EGENERIC; } case VLC_ML_MEDIA_ADD_EXTERNAL_MRL: diff --git a/modules/misc/medialibrary/medialibrary.h b/modules/misc/medialibrary/medialibrary.h index 42cda31c35..861a41c44a 100644 --- a/modules/misc/medialibrary/medialibrary.h +++ b/modules/misc/medialibrary/medialibrary.h @@ -40,6 +40,7 @@ struct vlc_event_t; struct vlc_object_t; struct vlc_thumbnailer_t; +struct vlc_thumbnailer_request_t; class Logger; @@ -58,8 +59,6 @@ private: { } - vlc::threads::condition_variable m_cond; - vlc::threads::mutex m_mutex; bool needsProbing; bool success; MetadataExtractor* mde; @@ -79,11 +78,11 @@ public: private: virtual medialibrary::parser::Status run( medialibrary::parser::IItem& item ) override; virtual const char*name() const override; - virtual uint8_t nbThreads() const override; virtual medialibrary::parser::Step targetedStep() const override; virtual bool initialize( medialibrary::IMediaLibrary* ml ) override; virtual void onFlushing() override; virtual void onRestarted() override; + virtual void stop() override; void onParserEnded( ParseContext& ctx, int status ); void addSubtree( ParseContext& ctx, input_item_node_t *root ); @@ -94,18 +93,41 @@ private: void *user_data ); private: + vlc::threads::condition_variable m_cond; + vlc::threads::mutex m_mutex; + ParseContext* m_currentCtx; vlc_object_t* m_obj; }; class Thumbnailer : public medialibrary::IThumbnailer { + struct ThumbnailerCtx + { + ~ThumbnailerCtx() + { + if ( thumbnail != nullptr ) + picture_Release( thumbnail ); + } + Thumbnailer* thumbnailer; + bool done; + picture_t* thumbnail; + vlc_thumbnailer_request_t* request; + }; public: - Thumbnailer( vlc_medialibrary_module_t* ml, std::string thumbnailsDir); - virtual bool generate( medialibrary::MediaPtr media, const std::string& mrl ) override; + Thumbnailer(vlc_medialibrary_module_t* ml); + virtual bool generate( const std::string& mrl, uint32_t desiredWidth, + uint32_t desiredHeight, float position, + const std::string& dest ) override; + virtual void stop() override; + +private: + static void onThumbnailComplete( void* data, picture_t* thumbnail ); private: vlc_medialibrary_module_t* m_ml; - std::string m_thumbnailDir; + 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; }; @@ -162,12 +184,15 @@ public: virtual void onDiscoveryCompleted(const std::string& entryPoint, bool success) override; virtual void onReloadStarted(const std::string& entryPoint) override; virtual void onReloadCompleted(const std::string& entryPoint, bool success) override; + virtual void onEntryPointAdded(const std::string& entryPoint, bool success) override; virtual void onEntryPointRemoved(const std::string& entryPoint, bool success) override; virtual void onEntryPointBanned(const std::string& entryPoint, bool success) override; virtual void onEntryPointUnbanned(const std::string& entryPoint, bool success) override; virtual void onParsingStatsUpdated(uint32_t percent) override; virtual void onBackgroundTasksIdleChanged(bool isIdle) override; - virtual void onMediaThumbnailReady(medialibrary::MediaPtr media, bool success) override; + virtual void onMediaThumbnailReady(medialibrary::MediaPtr media, + medialibrary::ThumbnailSizeType sizeType, + bool success) override; }; bool Convert( const medialibrary::IMedia* input, vlc_ml_media_t& output ); diff --git a/src/misc/medialibrary.c b/src/misc/medialibrary.c index 436a5b226f..f100f29b81 100644 --- a/src/misc/medialibrary.c +++ b/src/misc/medialibrary.c @@ -134,6 +134,12 @@ vlc_medialibrary_t* vlc_ml_instance_get( vlc_object_t* p_obj ) return p_priv->p_media_library; } +static void vlc_ml_thumbnails_release( vlc_ml_thumbnail_t *p_thumbnails ) +{ + for ( int i = 0; i < VLC_ML_THUMBNAIL_SIZE_COUNT; ++i ) + free( p_thumbnails[i].psz_mrl ); +} + static void vlc_ml_show_release_inner( vlc_ml_show_t* p_show ) { free( p_show->psz_artwork_mrl ); @@ -169,7 +175,7 @@ static void vlc_ml_media_release_inner( vlc_ml_media_t* p_media ) vlc_ml_file_list_release( p_media->p_files ); vlc_ml_media_release_tracks_inner( p_media->p_tracks ); free( p_media->psz_title ); - free( p_media->psz_artwork_mrl ); + vlc_ml_thumbnails_release( p_media->thumbnails ); switch( p_media->i_subtype ) { case VLC_ML_MEDIA_SUBTYPE_ALBUMTRACK: @@ -189,7 +195,7 @@ static void vlc_ml_media_release_inner( vlc_ml_media_t* p_media ) static void vlc_ml_artist_release_inner( vlc_ml_artist_t* p_artist ) { - free( p_artist->psz_artwork_mrl ); + vlc_ml_thumbnails_release( p_artist->thumbnails ); free( p_artist->psz_name ); free( p_artist->psz_shortbio ); free( p_artist->psz_mb_id ); @@ -205,8 +211,8 @@ void vlc_ml_artist_release( vlc_ml_artist_t* p_artist ) static void vlc_ml_album_release_inner( vlc_ml_album_t* p_album ) { + vlc_ml_thumbnails_release( p_album->thumbnails ); free( p_album->psz_artist ); - free( p_album->psz_artwork_mrl ); free( p_album->psz_summary ); free( p_album->psz_title ); } _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
