[vlc-commits] [Git][videolan/vlc][master] 8 commits: qt: move ml functions out of cover generator

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Tue May 31 11:42:34 UTC 2022



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
ca99e26a by Prince Gupta at 2022-05-31T11:27:09+00:00
qt: move ml functions out of cover generator

- - - - -
fa6882e0 by Prince Gupta at 2022-05-31T11:27:09+00:00
qt: factorize thumbnail url checking

- - - - -
562aba9f by Prince Gupta at 2022-05-31T11:27:09+00:00
qt: fix thumbnail generation for playlist media

- - - - -
7ac4e9e8 by Prince Gupta at 2022-05-31T11:27:09+00:00
qt: implement ThumbnailCollector

- - - - -
70e9e6bd by Prince Gupta at 2022-05-31T11:27:09+00:00
qt: remove ml member from covergenerator

- - - - -
2be11b50 by Prince Gupta at 2022-05-31T11:27:09+00:00
qt: constify covergenerator

- - - - -
26e15e2a by Prince Gupta at 2022-05-31T11:27:09+00:00
qt: generate child thumbnail during folder/group cover generation

fixes #26804

- - - - -
492561fa by Prince Gupta at 2022-05-31T11:27:09+00:00
qt: generate child thumbnail during playlist cover generation

- - - - -


13 changed files:

- modules/gui/qt/Makefile.am
- modules/gui/qt/medialibrary/mlbasemodel.hpp
- modules/gui/qt/medialibrary/mlgenremodel.cpp
- modules/gui/qt/medialibrary/mlhelper.cpp
- modules/gui/qt/medialibrary/mlhelper.hpp
- modules/gui/qt/medialibrary/mlplaylistlistmodel.cpp
- modules/gui/qt/medialibrary/mlplaylistmodel.cpp
- modules/gui/qt/medialibrary/mlvideofoldersmodel.cpp
- modules/gui/qt/medialibrary/mlvideogroupsmodel.cpp
- + modules/gui/qt/medialibrary/thumbnailcollector.cpp
- + modules/gui/qt/medialibrary/thumbnailcollector.hpp
- modules/gui/qt/util/covergenerator.cpp
- modules/gui/qt/util/covergenerator.hpp


Changes:

=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -210,6 +210,8 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/medialibrary/mlplaylistmedia.hpp \
 	gui/qt/medialibrary/mlplaylistmodel.cpp \
 	gui/qt/medialibrary/mlplaylistmodel.hpp \
+	gui/qt/medialibrary/thumbnailcollector.hpp \
+	gui/qt/medialibrary/thumbnailcollector.cpp \
 	gui/qt/menus/custom_menus.cpp \
 	gui/qt/menus/custom_menus.hpp \
 	gui/qt/menus/qml_menu_wrapper.cpp \
@@ -416,6 +418,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/medialibrary/mlplaylistmodel.moc.cpp \
 	gui/qt/medialibrary/mlvideofoldersmodel.moc.cpp \
 	gui/qt/medialibrary/mlvideogroupsmodel.moc.cpp \
+	gui/qt/medialibrary/thumbnailcollector.moc.cpp \
 	gui/qt/menus/custom_menus.moc.cpp \
 	gui/qt/menus/qml_menu_wrapper.moc.cpp \
 	gui/qt/menus/menus.moc.cpp \


=====================================
modules/gui/qt/medialibrary/mlbasemodel.hpp
=====================================
@@ -39,6 +39,7 @@
 class MLListCache;
 class MediaLib;
 class MLItemCover;
+class CoverGenerator;
 
 class MLBaseModel : public QAbstractListModel
 {
@@ -195,7 +196,9 @@ protected:
     std::shared_ptr<BaseLoader> m_itemLoader;
 
 private: // Friends
-    friend QString getVideoListCover(const MLBaseModel*, MLItemCover*, int, int, int);
+    friend QString createGroupMediaCover(const MLBaseModel* model, MLItemCover* parent
+                                         , int role
+                                         , const std::shared_ptr<CoverGenerator> generator);
 };
 
 #endif // MLBASEMODEL_HPP


=====================================
modules/gui/qt/medialibrary/mlgenremodel.cpp
=====================================
@@ -38,6 +38,29 @@ static const int MLGENREMODEL_COVER_BLUR = 4;
 
 //-------------------------------------------------------------------------------------------------
 
+namespace
+{
+
+QStringList getGenreMediaThumbnails(vlc_medialibrary_t* p_ml, const int count, const int64_t id)
+{
+    QStringList thumbnails;
+
+    vlc_ml_query_params_t params;
+
+    memset(&params, 0, sizeof(vlc_ml_query_params_t));
+
+    // NOTE: We retrieve twice the count to maximize our chances to get a valid thumbnail.
+    params.i_nbResults = count * 2;
+
+    ml_unique_ptr<vlc_ml_album_list_t> list(vlc_ml_list_genre_albums(p_ml, &params, id));
+
+    thumbnailCopy(ml_range_iterate<vlc_ml_album_t>(list), std::back_inserter(thumbnails), count);
+
+    return thumbnails;
+}
+
+}
+
 QHash<QByteArray, vlc_ml_sorting_criteria_t> MLGenreModel::M_names_to_criteria = {
     {"title", VLC_ML_SORTING_ALPHA}
 };
@@ -154,7 +177,7 @@ QString MLGenreModel::getCover(MLGenre * genre) const
     [genreId, coverDefault = m_coverDefault]
     (vlc_medialibrary_t* ml, Context& ctx)
     {
-        CoverGenerator generator{ml, genreId};
+        CoverGenerator generator {genreId};
 
         generator.setSize(QSize(MLGENREMODEL_COVER_WIDTH,
                                  MLGENREMODEL_COVER_HEIGHT));
@@ -172,7 +195,8 @@ QString MLGenreModel::getCover(MLGenre * genre) const
         if (generator.cachedFileAvailable())
             ctx.cover = generator.cachedFileURL();
         else
-            ctx.cover = generator.execute();
+            ctx.cover = generator.execute(getGenreMediaThumbnails(ml, MLGENREMODEL_COVER_COUNTX * MLGENREMODEL_COVER_COUNTY, genreId.id));
+
         vlc_ml_media_set_genre_thumbnail(ml, genreId.id, qtu(ctx.cover), VLC_ML_THUMBNAIL_SMALL);
     },
     //UI thread


=====================================
modules/gui/qt/medialibrary/mlhelper.cpp
=====================================
@@ -21,6 +21,42 @@
 // MediaLibrary includes
 #include "mlbasemodel.hpp"
 #include "mlitemcover.hpp"
+#include "thumbnailcollector.hpp"
+
+namespace
+{
+
+struct ThumbnailList
+{
+    QSet<int64_t> toGenerate;
+    QStringList existing;
+};
+
+ThumbnailList extractChildMediaThumbnailsOrIDs(vlc_medialibrary_t *p_ml, const int count, const MLItemId &itemID)
+{
+    ThumbnailList result;
+
+    vlc_ml_query_params_t params {};
+    params.i_nbResults = count;
+
+    ml_unique_ptr<vlc_ml_media_list_t> list(vlc_ml_list_media_of(p_ml, &params, itemID.type, itemID.id));
+
+    for (const auto &media : ml_range_iterate<vlc_ml_media_t>(list))
+    {
+        const bool isThumbnailAvailable = (media.thumbnails[VLC_ML_THUMBNAIL_SMALL].i_status == VLC_ML_THUMBNAIL_STATUS_AVAILABLE);
+        if (isThumbnailAvailable)
+        {
+            result.existing.push_back(toValidLocalFile(media.thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl));
+        } else if (media.i_type == VLC_ML_MEDIA_TYPE_VIDEO)
+        {
+            result.toGenerate.insert(media.i_id);
+        }
+    }
+
+    return result;
+}
+
+}
 
 QString MsToString( int64_t time , bool doShort )
 {
@@ -47,58 +83,93 @@ QString MsToString( int64_t time , bool doShort )
 
 }
 
-QString getVideoListCover( const MLBaseModel* model, MLItemCover* item, int width, int height,
-                           int role )
+QStringList extractMediaThumbnails(vlc_medialibrary_t *p_ml, const int count, const MLItemId &itemID)
+{
+    // NOTE: We retrieve twice the count to maximize our chances to get a valid thumbnail.
+    return extractChildMediaThumbnailsOrIDs(p_ml, count * 2, itemID).existing;
+}
+
+QString createGroupMediaCover(const MLBaseModel* model, MLItemCover* parent
+                              , int role
+                              , const std::shared_ptr<CoverGenerator> generator)
 {
-    QString cover = item->getCover();
+    QString cover = parent->getCover();
 
     // NOTE: Making sure we're not already generating a cover.
-    if (cover.isNull() == false || item->hasGenerator())
+    if (cover.isNull() == false || parent->hasGenerator())
         return cover;
 
-    MLItemId itemId = item->getId();
-
-    struct Context { QString cover; };
-
-    item->setGenerator(true);
-
-    model->ml()->runOnMLThread<Context>(model,
-    //ML thread
-    [itemId, width, height]
-    (vlc_medialibrary_t * ml, Context & ctx)
-    {
-        CoverGenerator generator{ ml, itemId };
-
-        generator.setSize(QSize(width, height));
+    if (generator->cachedFileAvailable())
+        return generator->cachedFileURL();
 
-        generator.setDefaultThumbnail(":/noart_videoCover.svg");
+    MLItemId itemId = parent->getId();
+    parent->setGenerator(true);
 
-        if (generator.cachedFileAvailable())
-            ctx.cover = generator.cachedFileURL();
-        else
-            ctx.cover = generator.execute();
-    },
-    //UI Thread
-    [model, itemId, role]
-    (quint64, Context & ctx)
+    const auto generateCover = [=](const QStringList &childCovers)
     {
-        int row;
-
-        // NOTE: We want to avoid calling 'MLBaseModel::item' for performance issues.
-        auto item = static_cast<MLItemCover *>(model->findInCache(itemId, &row));
-
-        if (!item)
-            return;
-
-        item->setCover(ctx.cover);
-
-        item->setGenerator(false);
-
-        QModelIndex modelIndex = model->index(row);
-
-        //we're running in a callback
-        emit const_cast<MLBaseModel *>(model)->dataChanged(modelIndex, modelIndex, { role });
-    });
+        struct Context { QString cover; };
+
+        model->ml()->runOnMLThread<Context>(model,
+            //ML thread
+            [generator, childCovers]
+            (vlc_medialibrary_t * , Context & ctx)
+            {
+                ctx.cover = generator->execute(childCovers);
+            },
+            //UI Thread
+            [model, itemId, role]
+            (quint64, Context & ctx)
+            {
+                int row;
+
+                // NOTE: We want to avoid calling 'MLBaseModel::item' for performance issues.
+                auto item = static_cast<MLItemCover *>(model->findInCache(itemId, &row));
+                if (!item)
+                    return;
+
+                item->setCover(ctx.cover);
+                item->setGenerator(false);
+
+                QModelIndex modelIndex = model->index(row);
+                emit const_cast<MLBaseModel *>(model)->dataChanged(modelIndex, modelIndex, { role });
+            }
+        );
+    };
+
+    model->ml()->runOnMLThread<ThumbnailList>(model,
+        //ML thread (get child thumbnails or ids)
+        [itemId, generator](vlc_medialibrary_t *p_ml, ThumbnailList &ctx)
+        {
+            ctx = extractChildMediaThumbnailsOrIDs(p_ml, generator->requiredNoOfThumbnails(), itemId);
+        }
+        //UI Thread
+        , [=](quint64, ThumbnailList & ctx)
+        {
+            if (ctx.toGenerate.empty())
+            {
+                generateCover(ctx.existing);
+                return;
+            }
+
+            // request child thumbnail generation, when finished generate the cover
+            auto collector = new ThumbnailCollector(const_cast<MLBaseModel *>(model));
+            QObject::connect(collector, &ThumbnailCollector::finished, model, [=]()
+            {
+                const auto thumbnails = ctx.existing + collector->allGenerated().values();
+                generateCover(thumbnails);
+
+                collector->deleteLater();
+            });
+
+            collector->start(model->ml(), ctx.toGenerate);
+        }
+    );
 
     return cover;
 }
+
+QString toValidLocalFile(const char *mrl)
+{
+    QUrl url(mrl);
+    return url.isLocalFile() ? url.toLocalFile() : QString {};
+}


=====================================
modules/gui/qt/medialibrary/mlhelper.hpp
=====================================
@@ -31,6 +31,8 @@
 // Forward declarations
 class MLBaseModel;
 class MLItemCover;
+class MLItemId;
+class CoverGenerator;
 
 template<typename T>
 class MLDeleter
@@ -75,9 +77,33 @@ MLListRange<T> ml_range_iterate(L& list)
     return MLListRange<T>{ list->p_items, list->p_items + list->i_nb_items };
 }
 
+QString toValidLocalFile(const char *mrl);
+
+template <typename T, typename O>
+void thumbnailCopy(const MLListRange<T> &list, O dst, const int max)
+{
+    int count = 0;
+    for (const auto &item : list)
+    {
+        if (item.thumbnails[VLC_ML_THUMBNAIL_SMALL].i_status != VLC_ML_THUMBNAIL_STATUS_AVAILABLE)
+            continue;
+
+        const auto path = toValidLocalFile(item.thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl);
+        if (path.isEmpty())
+            continue;
+
+        *dst++ = path;
+        ++count;
+        if (count == max)
+            return;
+    }
+}
+
 QString MsToString( int64_t time, bool doShort = false );
 
-QString getVideoListCover( const MLBaseModel* model, MLItemCover* item, int width, int height,
-                           int role );
+QStringList extractMediaThumbnails(vlc_medialibrary_t *p_ml, const int count, const MLItemId &itemID);
+
+QString createGroupMediaCover(const MLBaseModel* model, MLItemCover* parent
+                              , int role, const std::shared_ptr<CoverGenerator> generator);
 
 #endif // MLHELPER_HPP


=====================================
modules/gui/qt/medialibrary/mlplaylistlistmodel.cpp
=====================================
@@ -33,12 +33,16 @@
 //-------------------------------------------------------------------------------------------------
 // Static variables
 
-// NOTE: We multiply by 2 to cover most dpi settings.
-static const int MLPLAYLISTMODEL_COVER_WIDTH  = 512 * 2; // 16 / 10 ratio
-static const int MLPLAYLISTMODEL_COVER_HEIGHT = 320 * 2;
 
 namespace  {
 
+// NOTE: We multiply by 2 to cover most dpi settings.
+const int MLPLAYLISTMODEL_COVER_WIDTH  = 512 * 2; // 16 / 10 ratio
+const int MLPLAYLISTMODEL_COVER_HEIGHT = 320 * 2;
+
+const int PLAYLIST_COVERX = 2;
+const int PLAYLIST_COVERY = 2;
+
 void appendMediaIntoPlaylist(vlc_medialibrary_t* ml, int64_t playlistId, const std::vector<MLItemId>& itemList)
 {
     vlc_ml_query_params_t query;
@@ -296,54 +300,21 @@ void MLPlaylistListModel::endTransaction()
 
 QString MLPlaylistListModel::getCover(MLPlaylist * playlist) const
 {
-    QString cover = playlist->getCover();
-
-    // NOTE: Making sure we're not already generating a cover.
-    if (cover.isNull() == false || playlist->hasGenerator())
-        return cover;
-
-    MLItemId playlistId = playlist->getId();
-    struct Context{
-        QString cover;
-    };
-    playlist->setGenerator(true);
-    m_mediaLib->runOnMLThread<Context>(this,
-    //ML thread
-    [playlistId, coverSize = m_coverSize, coverDefault = m_coverDefault, coverPrefix = m_coverPrefix]
-    (vlc_medialibrary_t* ml, Context& ctx)
-    {
-        CoverGenerator generator{ml, playlistId};
+    auto generator = std::make_shared<CoverGenerator>(playlist->getId());
 
-        generator.setSize(coverSize);
+    generator->setCountX(PLAYLIST_COVERX);
+    generator->setCountY(PLAYLIST_COVERY);
 
-        if (!coverDefault.isEmpty())
-            generator.setDefaultThumbnail(coverDefault);
+    generator->setSize(m_coverSize);
 
-        generator.setPrefix(coverPrefix);
+    if (!m_coverDefault.isEmpty())
+        generator->setDefaultThumbnail(m_coverDefault);
 
-        if (generator.cachedFileAvailable())
-            ctx.cover = generator.cachedFileURL();
-        else
-            ctx.cover = generator.execute();
-    },
-    //UI thread
-    [this, playlistId]
-    (quint64, Context& ctx)
-    {
-        int row;
-        // NOTE: We want to avoid calling 'MLBaseModel::item' for performance issues.
-        auto playlist = static_cast<MLPlaylist *>(findInCache(playlistId, &row));
-        if (!playlist)
-            return;
-        playlist->setCover(ctx.cover);
-        playlist->setGenerator(false);
-
-        //we're running in a callback
-        QModelIndex modelIndex = index(row);
-        emit const_cast<MLPlaylistListModel*>(this)->dataChanged(modelIndex, modelIndex, { PLAYLIST_THUMBNAIL });
-    });
+    generator->setPrefix(m_coverPrefix);
 
-    return cover;
+    return createGroupMediaCover(this, playlist
+                                 , PLAYLIST_THUMBNAIL
+                                 , generator);
 }
 
 //-------------------------------------------------------------------------------------------------


=====================================
modules/gui/qt/medialibrary/mlplaylistmodel.cpp
=====================================
@@ -340,11 +340,13 @@ QVariant MLPlaylistModel::itemRoleData(MLItem *item, int role) const /* override
         {
             vlc_ml_thumbnail_status_t status;
             QString thumbnail = media->getThumbnail(&status);
-            if (media->getType() == VLC_ML_MEDIA_TYPE_AUDIO
-                && (status == VLC_ML_THUMBNAIL_STATUS_MISSING || status == VLC_ML_THUMBNAIL_STATUS_FAILURE))
+            if ((media->getType() == VLC_ML_MEDIA_TYPE_VIDEO)
+                && (status == VLC_ML_THUMBNAIL_STATUS_MISSING
+                    || status == VLC_ML_THUMBNAIL_STATUS_FAILURE))
             {
                 generateThumbnail(item->getId());
             }
+
             return QVariant::fromValue(thumbnail);
         }
         case MEDIA_DURATION:


=====================================
modules/gui/qt/medialibrary/mlvideofoldersmodel.cpp
=====================================
@@ -85,8 +85,13 @@ QVariant MLVideoFoldersModel::itemRoleData(MLItem * item, const int role) const
         case FOLDER_TITLE:
             return QVariant::fromValue(folder->getTitle());
         case FOLDER_THUMBNAIL:
-            return getVideoListCover(this, folder, MLVIDEOFOLDERSMODEL_COVER_WIDTH,
-                                     MLVIDEOFOLDERSMODEL_COVER_HEIGHT, FOLDER_THUMBNAIL);
+        {
+            auto generator = std::make_shared<CoverGenerator>(folder->getId());
+            generator->setSize(QSize(MLVIDEOFOLDERSMODEL_COVER_WIDTH, MLVIDEOFOLDERSMODEL_COVER_HEIGHT));
+            generator->setDefaultThumbnail(":/noart_videoCover.svg");
+
+            return createGroupMediaCover(this, folder, FOLDER_THUMBNAIL, generator);
+        }
         case FOLDER_DURATION:
             return QVariant::fromValue(folder->getDuration());
         case FOLDER_COUNT:


=====================================
modules/gui/qt/medialibrary/mlvideogroupsmodel.cpp
=====================================
@@ -92,8 +92,15 @@ QVariant MLVideoGroupsModel::itemRoleData(MLItem * item, const int role) const /
             case VIDEO_TITLE:
                 return QVariant::fromValue(group->getTitle());
             case VIDEO_THUMBNAIL:
-                return getVideoListCover(this, group, MLVIDEOGROUPSMODEL_COVER_WIDTH,
-                                         MLVIDEOGROUPSMODEL_COVER_HEIGHT, VIDEO_THUMBNAIL);
+            {
+                auto generator = std::make_shared<CoverGenerator>(group->getId());
+                generator->setSize(QSize(MLVIDEOGROUPSMODEL_COVER_WIDTH, MLVIDEOGROUPSMODEL_COVER_HEIGHT));
+                generator->setDefaultThumbnail(":/noart_videoCover.svg");
+
+                return createGroupMediaCover(this, group
+                                             , VIDEO_THUMBNAIL
+                                             , generator);
+            }
             case VIDEO_DURATION:
                 return QVariant::fromValue(group->getDuration());
             case GROUP_IS_VIDEO:


=====================================
modules/gui/qt/medialibrary/thumbnailcollector.cpp
=====================================
@@ -0,0 +1,86 @@
+/*****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *****************************************************************************/
+
+#include "thumbnailcollector.hpp"
+
+#include "medialibrary/medialib.hpp"
+#include "medialibrary/mlhelper.hpp"
+
+
+ThumbnailCollector::ThumbnailCollector(QObject *parent)
+    : QObject(parent)
+    , m_ml_event_handle(nullptr, [this](vlc_ml_event_callback_t *cb)
+    {
+        assert(m_ml);
+        QMutexLocker lock(&m_mut);
+        m_ml->unregisterEventListener(cb);
+    })
+{
+}
+
+void ThumbnailCollector::start(MediaLib *ml, const QSet<int64_t> &mlIds)
+{
+    assert(!m_ml); // class object is only one time usable
+    m_ml = ml;
+    m_ml_event_handle.reset(ml->registerEventListener(&onVlcMLEvent, this));
+
+    m_pending = mlIds;
+    m_ml->runOnMLThread(this, [ids = mlIds](vlc_medialibrary_t* ml)
+    {
+        for (const auto id : ids)
+            vlc_ml_media_generate_thumbnail(ml, id, VLC_ML_THUMBNAIL_SMALL, 512, 320, .15);
+    });
+}
+
+void ThumbnailCollector::onVlcMLEvent(void *data, const vlc_ml_event_t *event)
+{
+    static const auto mediaID = [](const vlc_ml_event_t *event)
+    {
+        return (event->i_type == VLC_ML_EVENT_MEDIA_DELETED)
+                   ? event->deletion.i_entity_id
+                   : event->media_thumbnail_generated.p_media->i_id;
+    };
+
+    if ((event->i_type != VLC_ML_EVENT_MEDIA_DELETED)
+        && (event->i_type != VLC_ML_EVENT_MEDIA_THUMBNAIL_GENERATED))
+        return;
+
+    const auto self = reinterpret_cast<ThumbnailCollector *>(data);
+    QMutexLocker lock(&self->m_mut);
+
+    const auto id = mediaID(event);
+    if (!self->m_pending.contains(id))
+        return;
+
+    self->m_pending.remove(id);
+
+    if (event->i_type == VLC_ML_EVENT_MEDIA_THUMBNAIL_GENERATED)
+    {
+        const auto media = event->media_thumbnail_generated.p_media;
+        const auto url = toValidLocalFile(media->thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl);
+
+        if (event->media_thumbnail_generated.b_success && !url.isEmpty()) {
+            self->m_thumbnails.insert(id, url);
+        } else {
+            qDebug("thumbnail generation failed, id: %ld, url: '%s'", id, qUtf8Printable(url));
+        }
+    }
+
+    if (self->m_pending.empty())
+        emit self->finished();
+}


=====================================
modules/gui/qt/medialibrary/thumbnailcollector.hpp
=====================================
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * Copyright (C) 2022 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 THUMBNAILCOLLECTOR_HPP
+#define THUMBNAILCOLLECTOR_HPP
+
+
+#include <QObject>
+#include <QHash>
+#include <QSet>
+#include <QMutex>
+#include <memory>
+
+#include <functional>
+
+class MediaLib;
+struct vlc_medialibrary_t;
+struct vlc_ml_event_callback_t;
+struct vlc_ml_event_t;
+
+
+class ThumbnailCollector : public QObject
+{
+    Q_OBJECT
+
+public:
+    ThumbnailCollector(QObject *parent = nullptr);
+
+    void start(MediaLib *ml, const QSet<int64_t> &mlIds);
+
+    QHash<int64_t, QString> allGenerated() { return m_thumbnails; }
+
+signals:
+    void finished();
+
+private:
+    static void onVlcMLEvent(void *data, const vlc_ml_event_t *event);
+
+    QMutex m_mut;
+    MediaLib *m_ml {};
+    std::unique_ptr<vlc_ml_event_callback_t,
+                    std::function<void(vlc_ml_event_callback_t*)>> m_ml_event_handle {};
+
+    QSet<int64_t> m_pending;
+    QHash<int64_t, QString> m_thumbnails;
+};
+
+
+#endif // THUMBNAILCOLLECTOR_HPP


=====================================
modules/gui/qt/util/covergenerator.cpp
=====================================
@@ -53,9 +53,8 @@ static const QString COVERGENERATOR_DEFAULT = ":/noart_albumCover.svg";
 // Ctor / dtor
 //-------------------------------------------------------------------------------------------------
 
-CoverGenerator::CoverGenerator(vlc_medialibrary_t * ml, const MLItemId & itemId)
-    : m_ml(ml)
-    , m_id(itemId)
+CoverGenerator::CoverGenerator(const MLItemId & itemId)
+    : m_id(itemId)
     , m_countX(COVERGENERATOR_COUNT)
     , m_countY(COVERGENERATOR_COUNT)
     , m_split(Divide)
@@ -114,6 +113,11 @@ void CoverGenerator::setPrefix(const QString & prefix)
     m_prefix = prefix;
 }
 
+int CoverGenerator::requiredNoOfThumbnails() const
+{
+    return m_countX * m_countY;
+}
+
 bool CoverGenerator::cachedFileAvailable() const
 {
     return QFile::exists(fileName());
@@ -138,31 +142,20 @@ QString CoverGenerator::fileName() const
 // QRunnable implementation
 //-------------------------------------------------------------------------------------------------
 
-QString CoverGenerator::execute() /* override */
+QString CoverGenerator::execute(QStringList thumbnails) const
 {
     QDir dir(config_GetUserDir(VLC_CACHE_DIR) + COVERGENERATOR_STORAGE);
 
     dir.mkpath(dir.absolutePath());
 
-    vlc_ml_parent_type type = m_id.type;
-
-    int64_t id = m_id.id;
-
     QString fileName = this->fileName();
     if (dir.exists(fileName))
     {
         return QUrl::fromLocalFile(fileName).toString();
     }
 
-    QStringList thumbnails;
-
     int count = m_countX * m_countY;
 
-    if (type == VLC_ML_PARENT_GENRE)
-        thumbnails = getGenre(count, id);
-    else
-        thumbnails = getMedias(count, id, type);
-
     int countX;
     int countY;
 
@@ -233,7 +226,7 @@ QString CoverGenerator::execute() /* override */
 //-------------------------------------------------------------------------------------------------
 
 void CoverGenerator::draw(QPainter & painter,
-                          const QStringList & fileNames, int countX, int countY)
+                          const QStringList & fileNames, int countX, int countY) const
 {
     int count = fileNames.count();
 
@@ -268,7 +261,7 @@ void CoverGenerator::draw(QPainter & painter,
     }
 }
 
-void CoverGenerator::drawImage(QPainter & painter, const QString & fileName, const QRect & target)
+void CoverGenerator::drawImage(QPainter & painter, const QString & fileName, const QRect & target) const
 {
     //QFile expect the :/ instead of qrc:// for resources files
     const QUrl fileURL {fileName};
@@ -329,7 +322,7 @@ void CoverGenerator::drawImage(QPainter & painter, const QString & fileName, con
 
 //-------------------------------------------------------------------------------------------------
 
-void CoverGenerator::blur(QImage& image)
+void CoverGenerator::blur(QImage& image) const
 {
     if (Q_LIKELY(&qt_blurImage))
     {
@@ -390,71 +383,3 @@ QString CoverGenerator::getPrefix(vlc_ml_parent_type type) const
             return "unknown";
     }
 }
-
-//-------------------------------------------------------------------------------------------------
-
-QStringList CoverGenerator::getGenre(int count, int64_t id) const
-{
-    QStringList thumbnails;
-
-    vlc_ml_query_params_t params;
-
-    memset(&params, 0, sizeof(vlc_ml_query_params_t));
-
-    // NOTE: We retrieve twice the count to maximize our chances to get a valid thumbnail.
-    params.i_nbResults = count * 2;
-
-    ml_unique_ptr<vlc_ml_album_list_t> list(vlc_ml_list_genre_albums(m_ml, &params, id));
-
-    for (const vlc_ml_album_t & album : ml_range_iterate<vlc_ml_album_t>(list))
-    {
-        if (album.thumbnails[VLC_ML_THUMBNAIL_SMALL].i_status != VLC_ML_THUMBNAIL_STATUS_AVAILABLE)
-            continue;
-
-        QUrl url(album.thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl);
-
-        // NOTE: We only want local files to compose the cover.
-        if (url.isLocalFile() == false)
-            continue;
-
-        thumbnails.append(url.toLocalFile());
-
-        if (thumbnails.count() == count)
-            return thumbnails;
-    }
-
-    return thumbnails;
-}
-
-QStringList CoverGenerator::getMedias(int count, int64_t id, vlc_ml_parent_type type) const
-{
-    QStringList thumbnails;
-
-    vlc_ml_query_params_t params;
-
-    memset(&params, 0, sizeof(vlc_ml_query_params_t));
-
-    // NOTE: We retrieve twice the count to maximize our chances to get a valid thumbnail.
-    params.i_nbResults = count * 2;
-
-    ml_unique_ptr<vlc_ml_media_list_t> list(vlc_ml_list_media_of(m_ml, &params, type, id));
-
-    for (const vlc_ml_media_t & media : ml_range_iterate<vlc_ml_media_t>(list))
-    {
-        if (media.thumbnails[VLC_ML_THUMBNAIL_SMALL].i_status != VLC_ML_THUMBNAIL_STATUS_AVAILABLE)
-            continue;
-
-        QUrl url(media.thumbnails[VLC_ML_THUMBNAIL_SMALL].psz_mrl);
-
-        // NOTE: We only want local files to compose the cover.
-        if (url.isLocalFile() == false)
-            continue;
-
-        thumbnails.append(url.toLocalFile());
-
-        if (thumbnails.count() == count)
-            return thumbnails;
-    }
-
-    return thumbnails;
-}


=====================================
modules/gui/qt/util/covergenerator.hpp
=====================================
@@ -48,7 +48,7 @@ public: // Enums
     };
 
 public:
-    CoverGenerator(vlc_medialibrary_t * ml, const MLItemId & itemId);
+    CoverGenerator(const MLItemId & itemId);
 
 public: // Interface
     MLItemId getId();
@@ -72,30 +72,26 @@ public: // Interface
     // NOTE: This lets us enforce a specific prefix for the cover fileName.
     void setPrefix(const QString & prefix);
 
+    int requiredNoOfThumbnails() const;
+
     bool cachedFileAvailable() const;
 
     QString cachedFileURL() const;
 
-public:
-    QString execute();
+    QString execute(QStringList thumbnails) const;
 
 private: // Functions
     QString fileName() const;
 
-    void draw(QPainter & painter, const QStringList & fileNames, int countX, int countY);
+    void draw(QPainter & painter, const QStringList & fileNames, int countX, int countY) const;
 
-    void drawImage(QPainter & painter, const QString & fileName, const QRect & rect);
+    void drawImage(QPainter & painter, const QString & fileName, const QRect & rect) const;
 
-    void blur(QImage &image);
+    void blur(QImage &image) const;
 
     QString getPrefix(vlc_ml_parent_type type) const;
 
-    QStringList getMedias(int count, int64_t id, vlc_ml_parent_type type) const;
-    QStringList getGenre (int count, int64_t id) const;
-
 private:
-    vlc_medialibrary_t * m_ml;
-
     MLItemId m_id;
 
     QSize m_size;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/aecc375d02952272d89e59aacf18d19cdc4a6572...492561fa5f64cb501e4f39520ebd62da29757865

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/aecc375d02952272d89e59aacf18d19cdc4a6572...492561fa5f64cb501e4f39520ebd62da29757865
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list