[vlc-devel] [PATCH 4/4] medialibrary: Bump version & update API usages

Hugo Beauzée-Luyssen hugo at beauzee.fr
Tue Jun 25 16:04:55 CEST 2019


- Multiple thumbnail can now be used
- Discovery, thumbnailing & metadata extractions are now interruptible
- An entry_point_added event has been added

--
Appologies for the big commit, but splitting it in multiple chunk would
break incremental build
---
 contrib/src/medialibrary/rules.mak            |  2 +-
 include/vlc_media_library.h                   | 62 +++++++++++++----
 .../gui/qt/components/mediacenter/mlalbum.cpp |  2 +-
 .../qt/components/mediacenter/mlartist.cpp    |  2 +-
 .../gui/qt/components/mediacenter/mlvideo.cpp | 13 ++--
 .../misc/medialibrary/MetadataExtractor.cpp   | 30 ++++----
 modules/misc/medialibrary/Thumbnailer.cpp     | 67 +++++++++---------
 modules/misc/medialibrary/entities.cpp        | 68 ++++++++++++-------
 modules/misc/medialibrary/medialib.cpp        | 31 +++++++--
 modules/misc/medialibrary/medialibrary.h      | 39 +++++++++--
 src/misc/medialibrary.c                       | 12 +++-
 11 files changed, 221 insertions(+), 107 deletions(-)

diff --git a/contrib/src/medialibrary/rules.mak b/contrib/src/medialibrary/rules.mak
index 799f9b6db5..e9d5359f97 100644
--- a/contrib/src/medialibrary/rules.mak
+++ b/contrib/src/medialibrary/rules.mak
@@ -1,4 +1,4 @@
-MEDIALIBRARY_HASH := 60073666abbd5f604dddbfd600968bac7f94cd5e
+MEDIALIBRARY_HASH := d92baf8033c72f687d9853a483d27a70fd4e196e
 MEDIALIBRARY_VERSION := git-$(MEDIALIBRARY_HASH)
 MEDIALIBRARY_GITURL := https://code.videolan.org/videolan/medialibrary.git
 
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) */
 };
 
@@ -542,6 +558,16 @@ enum vlc_ml_event_type
      * vlc_ml_event_t::reload_completed::b_success
      */
     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
@@ -615,6 +641,11 @@ typedef struct vlc_ml_event_t
             bool b_success;
         } reload_completed;
         struct
+        {
+            const char* psz_entry_point;
+            bool b_success;
+        } entry_point_added;
+        struct
         {
             const char* psz_entry_point;
             bool b_success;
@@ -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..c96dbc9769 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,67 @@ 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;
     {
-        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 );
 }
-- 
2.20.1



More information about the vlc-devel mailing list