Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (13)
Showing
with 388 additions and 338 deletions
......@@ -179,8 +179,6 @@ libqt_plugin_la_SOURCES = \
gui/qt/medialibrary/mlgroup.hpp \
gui/qt/medialibrary/mlhelper.cpp \
gui/qt/medialibrary/mlhelper.hpp \
gui/qt/medialibrary/mlitemcover.cpp \
gui/qt/medialibrary/mlitemcover.hpp \
gui/qt/medialibrary/mllistcache.cpp \
gui/qt/medialibrary/mllistcache.hpp \
gui/qt/medialibrary/mlthreadpool.cpp \
......@@ -212,6 +210,8 @@ libqt_plugin_la_SOURCES = \
gui/qt/medialibrary/mlplaylistmodel.hpp \
gui/qt/medialibrary/thumbnailcollector.hpp \
gui/qt/medialibrary/thumbnailcollector.cpp \
gui/qt/medialibrary/mlcustomcover.hpp \
gui/qt/medialibrary/mlcustomcover.cpp \
gui/qt/menus/custom_menus.cpp \
gui/qt/menus/custom_menus.hpp \
gui/qt/menus/qml_menu_wrapper.cpp \
......
......@@ -4,6 +4,7 @@
#include "medialibrary/medialib.hpp"
#include "medialibrary/mlqmltypes.hpp"
#include "medialibrary/mlcustomcover.hpp"
#include "medialibrary/mlalbummodel.hpp"
#include "medialibrary/mlartistmodel.hpp"
#include "medialibrary/mlalbumtrackmodel.hpp"
......@@ -63,6 +64,8 @@ using namespace vlc::playlist;
namespace {
const QString MLCUSTOMCOVER_PROVIDERID = "mlcustomcover";
template<class T>
class SingletonRegisterHelper
{
......@@ -148,6 +151,14 @@ bool MainUI::setup(QQmlEngine* engine)
engine->setOutputWarningsToStandardError(false);
connect(engine, &QQmlEngine::warnings, this, &MainUI::onQmlWarning);
if (m_mainCtx->hasMediaLibrary())
{
auto customCover = new MLCustomCover(MLCUSTOMCOVER_PROVIDERID, m_mainCtx->getMediaLibrary());
m_mainCtx->getMediaLibrary()->setCustomCover(customCover);
engine->addImageProvider(MLCUSTOMCOVER_PROVIDERID, customCover);
}
m_component = new QQmlComponent(engine, QStringLiteral("qrc:/main/MainInterface.qml"), QQmlComponent::PreferSynchronous, engine);
if (m_component->isLoading())
{
......
......@@ -520,3 +520,13 @@ void MediaLib::runOnMLThreadTargetDestroyed(QObject * object)
//no need to disconnect QObject::destroyed, as object is currently being destroyed
}
}
MLCustomCover *MediaLib::customCover() const
{
return m_customCover;
}
void MediaLib::setCustomCover(MLCustomCover *newCustomCover)
{
m_customCover = newCustomCover;
}
......@@ -29,6 +29,8 @@
#include "util/qmlinputitem.hpp"
class MLCustomCover;
namespace vlc {
namespace playlist {
class Media;
......@@ -176,6 +178,9 @@ public:
*/
void cancelMLTask(const QObject* object, quint64 taskId);
MLCustomCover *customCover() const;
void setCustomCover(MLCustomCover *newCustomCover);
signals:
void discoveryStarted();
void discoveryCompleted();
......@@ -195,6 +200,7 @@ private slots:
private:
qt_intf_t* m_intf;
MLCustomCover *m_customCover {};
bool m_idle = false;
bool m_discoveryPending = false;
......
......@@ -38,8 +38,6 @@
// Fordward declarations
class MLListCache;
class MediaLib;
class MLItemCover;
class CoverGenerator;
class MLBaseModel : public QAbstractListModel
{
......@@ -194,11 +192,6 @@ protected:
//loader used to load single items
std::shared_ptr<BaseLoader> m_itemLoader;
private: // Friends
friend QString createGroupMediaCover(const MLBaseModel* model, MLItemCover* parent
, int role
, const std::shared_ptr<CoverGenerator> generator);
};
#endif // MLBASEMODEL_HPP
/*****************************************************************************
* Copyright (C) 2022 VLC authors and VideoLAN
*
* Authors: Prince Gupta <guptaprince8832@gmail.com>
*
* 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 "mlcustomcover.hpp"
#include "medialibrary/medialib.hpp"
#include "medialibrary/mlhelper.hpp"
#include "medialibrary/thumbnailcollector.hpp"
#include "util/asynctask.hpp"
#include "util/covergenerator.hpp"
#include <qhashfunctions.h>
#include <QCache>
#include <QMutex>
#include <QUrl>
#include <QUrlQuery>
namespace
{
const QString ID_KEY = QStringLiteral("id");
const QString TYPE_KEY = QStringLiteral("type");
const QString WIDTH_KEY = QStringLiteral("width");
const QString HEIGHT_KEY = QStringLiteral("height");
const QString COUNTX_KEY = QStringLiteral("countX");
const QString COUNTY_KEY = QStringLiteral("countY");
const QString BLUR_KEY = QStringLiteral("blur");
const QString SPLIT_KEY = QStringLiteral("split");
const QString DEFAULT_COVER_KEY = QStringLiteral("default_cover");
struct CoverData
{
MLItemId id;
QSize size;
int countX;
int countY;
int blur;
int split;
QString defaultCover;
};
QUrlQuery toQuery(const CoverData &data)
{
QUrlQuery query;
query.addQueryItem(ID_KEY, QString::number(data.id.id));
query.addQueryItem(TYPE_KEY, QString::number(data.id.type));
query.addQueryItem(WIDTH_KEY, QString::number(data.size.width()));
query.addQueryItem(HEIGHT_KEY, QString::number(data.size.height()));
query.addQueryItem(COUNTX_KEY, QString::number(data.countX));
query.addQueryItem(COUNTY_KEY, QString::number(data.countY));
query.addQueryItem(BLUR_KEY, QString::number(data.blur));
query.addQueryItem(SPLIT_KEY, QString::number(data.split));
query.addQueryItem(DEFAULT_COVER_KEY, data.defaultCover);
return query;
}
CoverData fromQuery(const QUrlQuery &query, QString *error)
{
try
{
const auto getValue = [&](const QString &key)
{
if (!query.hasQueryItem(key))
throw QString("key '%1' doesn't exist").arg(key);
return query.queryItemValue(key);
};
const auto intValue = [&](const QString &key)
{
auto value = getValue(key);
bool ok;
int iValue = value.toInt(&ok);
if (!ok)
throw QString("invalid value for key '%1'").arg(key);
return iValue;
};
CoverData data;
data.id.id = intValue(ID_KEY);
data.id.type = static_cast<vlc_ml_parent_type>(intValue(TYPE_KEY));
data.size.setWidth(intValue(WIDTH_KEY));
data.size.setHeight(intValue(HEIGHT_KEY));
data.countX = intValue(COUNTX_KEY);
data.countY = intValue(COUNTY_KEY);
data.blur = intValue(BLUR_KEY);
data.split = intValue(SPLIT_KEY);
data.defaultCover = getValue(DEFAULT_COVER_KEY);
return data;
}
catch (const QString &e)
{
if (error)
*error = e;
return {};
}
}
struct ThumbnailList
{
QSet<int64_t> toGenerate;
QStringList existing;
};
QStringList getGenreMediaThumbnails(vlc_medialibrary_t* p_ml, const int count, const int64_t id)
{
QStringList thumbnails;
vlc_ml_query_params_t params {};
// 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;
}
ThumbnailList extractChildMediaThumbnailsOrIDs(vlc_medialibrary_t *p_ml, const int count, const MLItemId &itemID)
{
ThumbnailList result;
vlc_ml_query_params_t params {};
// 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(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);
}
}
if (result.existing.size() > count)
{
const auto removeStart = result.existing.end() - (result.existing.size() - count);
result.existing.erase(removeStart, result.existing.end());
}
while (result.toGenerate.size() + result.existing.size() > count)
{
result.toGenerate.erase(result.toGenerate.begin());
}
return result;
}
} // anonymous namespace
class CustomCoverImageResponse : public QQuickImageResponse
{
public:
CustomCoverImageResponse(CoverData data, MediaLib *ml)
: ml {ml}
, data{data}
{
// uses Qt::QueuedConnection to give the receiver time to connect to finish()
QMetaObject::invokeMethod(this, &CustomCoverImageResponse::start, Qt::QueuedConnection);
}
QQuickTextureFactory *textureFactory() const override
{
return !image.isNull() ? QQuickTextureFactory::textureFactoryForImage(image) : nullptr;
}
private:
void start()
{
const int thumbnailCount = data.countX * data.countY;
ml->runOnMLThread<ThumbnailList>(this,
//ML thread (get child thumbnails or ids)
[itemId = data.id, thumbnailCount](vlc_medialibrary_t *p_ml, ThumbnailList &ctx)
{
if (itemId.type == VLC_ML_PARENT_GENRE)
ctx.existing = getGenreMediaThumbnails(p_ml, thumbnailCount, itemId.id);
else
ctx = extractChildMediaThumbnailsOrIDs(p_ml, thumbnailCount, 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(this);
QObject::connect(collector, &ThumbnailCollector::finished, this, [=]()
{
const auto thumbnails = ctx.existing + collector->allGenerated().values();
generateCover(thumbnails);
collector->deleteLater();
});
collector->start(ml, ctx.toGenerate);
}
);
}
void generateCover(const QStringList &thumbnails)
{
struct Context { QImage img; };
ml->runOnMLThread<Context>(this,
//ML thread
[data = this->data, thumbnails]
(vlc_medialibrary_t * , Context & ctx)
{
CoverGenerator generator;
generator.setCountX(data.countX);
generator.setCountY(data.countY);
generator.setSize(data.size);
generator.setSplit((CoverGenerator::Split)data.split);
generator.setBlur(data.blur);
if (!data.defaultCover.isEmpty())
generator.setDefaultThumbnail(data.defaultCover);
ctx.img = generator.execute(thumbnails);
},
//UI Thread
[this]
(quint64, Context & ctx)
{
doFinish(ctx.img);
}
);
}
void doFinish(const QImage &result)
{
image = result;
emit finished();
}
MediaLib *ml;
CoverData data;
QImage image;
};
MLCustomCover::MLCustomCover(const QString &providerId, MediaLib *ml)
: m_providerId {providerId}
, m_ml {ml}
{
}
QString MLCustomCover::get(const MLItemId &parentId, const QSize &size, const QString &defaultCover
, const int countX, const int countY, const int blur, const bool split_duplicate)
{
QUrl url;
url.setScheme(QStringLiteral("image"));
url.setHost(m_providerId);
url.setQuery(toQuery({parentId, size, countX, countY, blur, split_duplicate, defaultCover}));
return url.toString();
}
QQuickImageResponse *MLCustomCover::requestImageResponse(const QString &id, const QSize &requestedSize)
{
QString error;
CoverData data = fromQuery(QUrlQuery(id), &error);
if (!error.isEmpty())
{
qDebug("failed to parse url %s, error %s", qUtf8Printable(id), qUtf8Printable(error));
return nullptr;
}
if (requestedSize.isValid())
data.size = requestedSize;
return new CustomCoverImageResponse(data, m_ml);
}
/*****************************************************************************
* Copyright (C) 2021 VLC authors and VideoLAN
* Copyright (C) 2022 VLC authors and VideoLAN
*
* Authors: Benjamin Arnaud <bunjee@omega.gg>
* Authors: Prince Gupta <guptaprince8832@gmail.com>
*
* 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
......@@ -18,35 +18,34 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef MLITEMCOVER_HPP
#define MLITEMCOVER_HPP
#ifndef MLCUSTOMCOVER_HPP
#define MLCUSTOMCOVER_HPP
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <QQuickAsyncImageProvider>
// Util includes
#include "util/covergenerator.hpp"
#include <memory>
// MediaLibrary includes
#include "mlqmltypes.hpp"
class MLItemId;
class MediaLib;
class MLItemCover : public MLItem
class MLCustomCover : public QQuickAsyncImageProvider
{
public:
/* explicit */ MLItemCover(const MLItemId & id);
MLCustomCover(const QString &providerId, MediaLib *ml);
public: // Interface
bool hasGenerator() const;
void setGenerator(bool generating);
QString get(const MLItemId &parentId
, const QSize &size
, const QString &defaultCover
, const int countX = 2
, const int countY = 2
, const int blur = 0
, const bool split_duplicate = false);
QString getCover() const;
void setCover(const QString & fileName);
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize);
private:
bool m_isGenerating = false;
QString m_cover;
const QString m_providerId;
MediaLib *m_ml = nullptr;
};
#endif
#endif // MLCUSTOMCOVER_HPP
......@@ -23,7 +23,7 @@
// Ctor / dtor
MLFolder::MLFolder(const vlc_ml_folder_t * data)
: MLItemCover(MLItemId(data->i_id, VLC_ML_PARENT_FOLDER))
: MLItem(MLItemId(data->i_id, VLC_ML_PARENT_FOLDER))
, m_present(data->b_present)
, m_banned(data->b_banned)
, m_title(data->psz_name)
......
......@@ -22,9 +22,9 @@
#define MLFOLDER_HPP
// MediaLibrary includes
#include "mlitemcover.hpp"
#include "mlqmltypes.hpp"
class MLFolder : public MLItemCover
class MLFolder : public MLItem
{
public:
MLFolder(const vlc_ml_folder_t * data);
......
......@@ -19,21 +19,12 @@
#include "mlgenre.hpp"
MLGenre::MLGenre(const vlc_ml_genre_t *_data )
: MLItemCover( MLItemId( _data->i_id, VLC_ML_PARENT_GENRE ) )
: MLItem( MLItemId( _data->i_id, VLC_ML_PARENT_GENRE ) )
, m_name ( QString::fromUtf8( _data->psz_name ) )
, m_nbTracks ( (unsigned int)_data->i_nb_tracks )
{
assert(_data);
for (int i = VLC_ML_THUMBNAIL_SMALL; i < VLC_ML_THUMBNAIL_SIZE_COUNT; ++i)
{
if (_data->thumbnails[i].psz_mrl)
{
setCover(_data->thumbnails[i].psz_mrl);
break;
}
}
}
QString MLGenre::getName() const
......
......@@ -24,9 +24,9 @@
#endif
// MediaLibrary includes
#include "mlitemcover.hpp"
#include "mlqmltypes.hpp"
class MLGenre : public MLItemCover
class MLGenre : public MLItem
{
public:
MLGenre(const vlc_ml_genre_t * _data);
......
......@@ -22,14 +22,15 @@
#include "util/covergenerator.hpp"
// MediaLibrary includes
#include "mlcustomcover.hpp"
#include "mlartistmodel.hpp"
//-------------------------------------------------------------------------------------------------
// Static variables
// NOTE: We multiply by 2 to cover most dpi settings.
static const int MLGENREMODEL_COVER_WIDTH = 260 * 2;
static const int MLGENREMODEL_COVER_HEIGHT = 130 * 2;
// NOTE: We multiply by 3 to cover most dpi settings.
static const int MLGENREMODEL_COVER_WIDTH = 260 * 3;
static const int MLGENREMODEL_COVER_HEIGHT = 130 * 3;
static const int MLGENREMODEL_COVER_COUNTX = 4;
static const int MLGENREMODEL_COVER_COUNTY = 2;
......@@ -38,29 +39,6 @@ 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}
};
......@@ -161,65 +139,13 @@ vlc_ml_sorting_criteria_t MLGenreModel::nameToCriteria(QByteArray name) const
QString MLGenreModel::getCover(MLGenre * genre) const
{
QString cover = genre->getCover();
// NOTE: Making sure we're not already generating a cover.
if (cover.isNull() == false || genre->hasGenerator())
return cover;
MLItemId genreId = genre->getId();
struct Context{
QString cover;
};
genre->setGenerator(true);
m_mediaLib->runOnMLThread<Context>(this,
//ML thread
[genreId, coverDefault = m_coverDefault]
(vlc_medialibrary_t* ml, Context& ctx)
{
CoverGenerator generator {genreId};
generator.setSize(QSize(MLGENREMODEL_COVER_WIDTH,
MLGENREMODEL_COVER_HEIGHT));
generator.setCountX(MLGENREMODEL_COVER_COUNTX);
generator.setCountY(MLGENREMODEL_COVER_COUNTY);
generator.setSplit(CoverGenerator::Duplicate);
generator.setBlur(MLGENREMODEL_COVER_BLUR);
if (!coverDefault.isEmpty())
generator.setDefaultThumbnail(coverDefault);
if (generator.cachedFileAvailable())
ctx.cover = generator.cachedFileURL();
else
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
[this, genreId]
(quint64, Context& ctx)
{
int row = 0;
// NOTE: We want to avoid calling 'MLBaseModel::item' for performance issues.
auto genre = static_cast<MLGenre *>(findInCache(genreId, &row));
if (!genre)
return;
genre->setCover(ctx.cover);
genre->setGenerator(false);
//we're running in a callback
QModelIndex modelIndex =this->index(row);
//we're running in a callback
emit const_cast<MLGenreModel*>(this)->dataChanged(modelIndex, modelIndex, { GENRE_COVER });
});
return cover;
return ml()->customCover()->get(genre->getId()
, QSize(MLGENREMODEL_COVER_WIDTH, MLGENREMODEL_COVER_HEIGHT)
, m_coverDefault
, MLGENREMODEL_COVER_COUNTX
, MLGENREMODEL_COVER_COUNTY
, MLGENREMODEL_COVER_BLUR
, true);
}
//-------------------------------------------------------------------------------------------------
......
......@@ -28,7 +28,7 @@
//-------------------------------------------------------------------------------------------------
MLGroup::MLGroup(const vlc_ml_group_t * data)
: MLItemCover(MLItemId(data->i_id, VLC_ML_PARENT_GROUP))
: MLItem(MLItemId(data->i_id, VLC_ML_PARENT_GROUP))
, m_title(qfu(data->psz_name))
, m_duration(data->i_duration)
, m_date(data->i_creation_date)
......
......@@ -26,9 +26,9 @@
#endif
// MediaLibrary includes
#include "mlitemcover.hpp"
#include "mlqmltypes.hpp"
class MLGroup : public MLItemCover
class MLGroup : public MLItem
{
public:
MLGroup(const vlc_ml_group_t * data);
......
......@@ -20,43 +20,6 @@
// 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 )
{
......@@ -83,91 +46,6 @@ QString MsToString( int64_t time , bool doShort )
}
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 = parent->getCover();
// NOTE: Making sure we're not already generating a cover.
if (cover.isNull() == false || parent->hasGenerator())
return cover;
if (generator->cachedFileAvailable())
return generator->cachedFileURL();
MLItemId itemId = parent->getId();
parent->setGenerator(true);
const auto generateCover = [=](const QStringList &childCovers)
{
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);
......
......@@ -30,7 +30,6 @@
// Forward declarations
class MLBaseModel;
class MLItemCover;
class MLItemId;
class CoverGenerator;
......@@ -101,9 +100,4 @@ void thumbnailCopy(const MLListRange<T> &list, O dst, const int max)
QString MsToString( int64_t time, bool doShort = false );
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
/*****************************************************************************
* Copyright (C) 2021 VLC authors and VideoLAN
*
* Authors: Benjamin Arnaud <bunjee@omega.gg>
*
* 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 "mlitemcover.hpp"
//-------------------------------------------------------------------------------------------------
// Ctor / dtor
//-------------------------------------------------------------------------------------------------
MLItemCover::MLItemCover(const MLItemId & id)
: MLItem(id)
{}
//-------------------------------------------------------------------------------------------------
// Interface
//-------------------------------------------------------------------------------------------------
bool MLItemCover::hasGenerator() const
{
return m_isGenerating;
}
void MLItemCover::setGenerator(bool generating)
{
m_isGenerating = generating;
}
//-------------------------------------------------------------------------------------------------
QString MLItemCover::getCover() const
{
return m_cover;
}
void MLItemCover::setCover(const QString & fileName)
{
m_cover = fileName;
}
......@@ -26,7 +26,7 @@
//-------------------------------------------------------------------------------------------------
MLPlaylist::MLPlaylist(const vlc_ml_playlist_t * data)
: MLItemCover(MLItemId(data->i_id, VLC_ML_PARENT_PLAYLIST))
: MLItem(MLItemId(data->i_id, VLC_ML_PARENT_PLAYLIST))
, m_name(qfu(data->psz_name))
, m_duration(0) // TODO m_duration
, m_count(data->i_nb_media)
......
......@@ -24,9 +24,9 @@
#endif
// MediaLibrary includes
#include "mlitemcover.hpp"
#include "mlqmltypes.hpp"
class MLPlaylist : public MLItemCover
class MLPlaylist : public MLItem
{
public:
MLPlaylist(const vlc_ml_playlist_t * data);
......
......@@ -28,6 +28,7 @@
// MediaLibrary includes
#include "mlhelper.hpp"
#include "mlcustomcover.hpp"
#include "mlplaylist.hpp"
//-------------------------------------------------------------------------------------------------
......@@ -36,9 +37,9 @@
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;
// NOTE: We multiply by 3 to cover most dpi settings.
const int MLPLAYLISTMODEL_COVER_WIDTH = 260 * 3; // 16 / 10 ratio
const int MLPLAYLISTMODEL_COVER_HEIGHT = 162 * 3;
const int PLAYLIST_COVERX = 2;
const int PLAYLIST_COVERY = 2;
......@@ -300,21 +301,10 @@ void MLPlaylistListModel::endTransaction()
QString MLPlaylistListModel::getCover(MLPlaylist * playlist) const
{
auto generator = std::make_shared<CoverGenerator>(playlist->getId());
generator->setCountX(PLAYLIST_COVERX);
generator->setCountY(PLAYLIST_COVERY);
generator->setSize(m_coverSize);
if (!m_coverDefault.isEmpty())
generator->setDefaultThumbnail(m_coverDefault);
generator->setPrefix(m_coverPrefix);
return createGroupMediaCover(this, playlist
, PLAYLIST_THUMBNAIL
, generator);
return ml()->customCover()->get(playlist->getId()
, m_coverSize
, m_coverDefault
, PLAYLIST_COVERX, PLAYLIST_COVERY);
}
//-------------------------------------------------------------------------------------------------
......