[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(¶ms, 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, ¶ms, 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, ¶ms, 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(¶ms, 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, ¶ms, 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(¶ms, 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, ¶ms, 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