Make in memory cache size configurable

This commit is contained in:
craig.p.drummond
2014-03-14 19:07:31 +00:00
committed by craig.p.drummond
parent f39f1d342f
commit 6cf6548f8d
8 changed files with 75 additions and 60 deletions

7
README
View File

@@ -355,6 +355,12 @@ maxCoverUpdatePerIteration=<Integer>
displayed. This config controls the number of covers that are sent in one
batch. The default is again 5. (Values 1..20 are acceptable)
coverCacheSize=<Integer>
Cantata stores scaled versions of covers in a cache in memory, to reduce
memory usage and/or disk acicess. This setting controls the maximum size
(in megabytes) that Cantata will use for this cache. The default is 4
(Values 1..512 are acceptable)
cueFileCodecs=<Comma separated list of codecs>
List of extra text codecs to try when loading CUE files. UTF-8 and System
default are tried first, and then the entries from this config are tried.
@@ -434,6 +440,7 @@ e.g.
iconTheme=oxygen
maxCoverFindPerIteration=5
maxCoverUpdatePerIteration=5
coverCacheSize=4
cueFileCodecs=GBK, big5-0
networkAccessEnabled=false
volumeStep=2

View File

@@ -54,7 +54,6 @@
#include <QFont>
#include <QXmlStreamReader>
#include <QTimer>
#include <QCache>
#ifdef ENABLE_KDE_SUPPORT
#include <KDE/KStandardDirs>
@@ -89,9 +88,6 @@ static bool saveInMpdDir=true;
static bool fetchCovers=true;
static QString constCoverInTagPrefix=QLatin1String("{tag}");
static QSet<int> cacheSizes;
static QCache<QString, QPixmap> cache(4*1024*1024);
static bool canSaveTo(const QString &dir)
{
QString mpdDir=MPDConnection::self()->getDetails().dir;
@@ -224,52 +220,6 @@ static void clearScaledCache(const Song &song)
}
}
QPixmap * Covers::getScaledCover(const QString &artist, const QString &album, int size)
{
if (size<4) {
return 0;
}
// DBUG_CLASS("Covers") << artist << album << size;
QString key=cacheKey(artist, album, size);
QPixmap *pix(cache.object(key));
if (!pix && cacheScaledCovers) {
QString fileName=getScaledCoverName(artist, album, size, false);
if (!fileName.isEmpty() && QFile::exists(fileName)) {
QImage img(fileName);
if (!img.isNull() && (img.width()==size || img.height()==size)) {
DBUG_CLASS("Covers") << artist << album << size << "scaled cover found" << fileName;
pix=new QPixmap(QPixmap::fromImage(img));
cache.insert(key, pix, pix->width()*pix->height()*(pix->depth()/8));
}
}
if (!pix) {
// Create a dummy pixmap so that we dont keep on stating files that do not exist!
pix=new QPixmap(1, 1);
cache.insert(key, pix, 4);
}
cacheSizes.insert(size);
}
return pix && pix->width()>1 ? pix : 0;
}
QPixmap * Covers::saveScaledCover(const QImage &img, const QString &artist, const QString &album, int size)
{
if (size<4) {
return 0;
}
if (cacheScaledCovers) {
QString fileName=getScaledCoverName(artist, album, size, true);
bool status=img.save(fileName);
DBUG_CLASS("Covers") << artist << album << size << fileName << status;
}
QPixmap *pix=new QPixmap(QPixmap::fromImage(img));
cache.insert(cacheKey(artist, album, size), pix, pix->width()*pix->height()*(pix->depth()/8));
cacheSizes.insert(size);
return pix;
}
bool Covers::isJpg(const QByteArray &data)
{
return data.size()>9 && /*data[0]==0xFF && data[1]==0xD8 && data[2]==0xFF*/ data[6]=='J' && data[7]=='F' && data[8]=='I' && data[9]=='F';
@@ -921,6 +871,7 @@ Covers::Covers()
{
maxPerLoopIteration=Settings::self()->maxCoverUpdatePerIteration();
maxFindPerLoopIteration=Settings::self()->maxCoverFindPerIteration();
cache.setMaxCost(Settings::self()->coverCacheSize()*1024*1024);
}
void Covers::readConfig()
@@ -948,6 +899,52 @@ void Covers::stop()
#endif
}
QPixmap * Covers::getScaledCover(const QString &artist, const QString &album, int size)
{
if (size<4) {
return 0;
}
// DBUG_CLASS("Covers") << artist << album << size;
QString key=cacheKey(artist, album, size);
QPixmap *pix(cache.object(key));
if (!pix && cacheScaledCovers) {
QString fileName=getScaledCoverName(artist, album, size, false);
if (!fileName.isEmpty() && QFile::exists(fileName)) {
QImage img(fileName);
if (!img.isNull() && (img.width()==size || img.height()==size)) {
DBUG_CLASS("Covers") << artist << album << size << "scaled cover found" << fileName;
pix=new QPixmap(QPixmap::fromImage(img));
cache.insert(key, pix, pix->width()*pix->height()*(pix->depth()/8));
}
}
if (!pix) {
// Create a dummy pixmap so that we dont keep on stating files that do not exist!
pix=new QPixmap(1, 1);
cache.insert(key, pix, 4);
}
cacheSizes.insert(size);
}
return pix && pix->width()>1 ? pix : 0;
}
QPixmap * Covers::saveScaledCover(const QImage &img, const QString &artist, const QString &album, int size)
{
if (size<4) {
return 0;
}
if (cacheScaledCovers) {
QString fileName=getScaledCoverName(artist, album, size, true);
bool status=img.save(fileName);
DBUG_CLASS("Covers") << artist << album << size << fileName << status;
}
QPixmap *pix=new QPixmap(QPixmap::fromImage(img));
cache.insert(cacheKey(artist, album, size), pix, pix->width()*pix->height()*(pix->depth()/8));
cacheSizes.insert(size);
return pix;
}
QPixmap * Covers::get(const Song &song, int size)
{
if (song.isUnknown()) {

View File

@@ -31,6 +31,7 @@
#include <QImage>
#include <QPixmap>
#include <QMutex>
#include <QCache>
#include "song.h"
#include "config.h"
@@ -171,8 +172,6 @@ public:
static QString albumFileName(const Song &song);
static QString artistFileName(const Song &song);
static QString fixArtist(const QString &artist);
static QPixmap * getScaledCover(const QString &artist, const QString &album, int size);
static QPixmap *saveScaledCover(const QImage &img, const QString &artist, const QString &album, int size);
static bool isJpg(const QByteArray &data);
static bool isPng(const QByteArray &data);
static const char * imageFormat(const QByteArray &data);
@@ -181,6 +180,8 @@ public:
void readConfig();
void stop();
QPixmap * getScaledCover(const QString &artist, const QString &album, int size);
QPixmap * saveScaledCover(const QImage &img, const QString &artist, const QString &album, int size);
// Get cover image of specified size. If this is not found 0 will be returned, and the cover
// will be downloaded.
QPixmap * get(const Song &song, int size);
@@ -227,6 +228,8 @@ private:
int retrieved;
QSet<QString> currentImageRequests;
QList<Song> queue;
QSet<int> cacheSizes;
QCache<QString, QPixmap> cache;
QMap<QString, QString> filenames;
CoverDownloader *downloader;
CoverLocator *locator;

View File

@@ -890,6 +890,12 @@ int Settings::maxCoverUpdatePerIteration()
return RESTRICT(v, 1, 20);
}
int Settings::coverCacheSize()
{
int v=GET_INT("coverCacheSize", 4);
return RESTRICT(v, 1, 512);
}
QStringList Settings::cueFileCodecs()
{
return GET_STRINGLIST("cueFileCodecs", QStringList());

View File

@@ -210,6 +210,7 @@ public:
bool podcastAutoDownload();
int maxCoverFindPerIteration();
int maxCoverUpdatePerIteration();
int coverCacheSize();
QStringList cueFileCodecs();
bool networkAccessEnabled();
int volumeStep();

View File

@@ -598,7 +598,7 @@ void AlbumsModel::AlbumItem::updateStats()
QPixmap * AlbumsModel::AlbumItem::cover()
{
if (Song::SingleTracks!=type && songs.count()) {
QPixmap *pix=Covers::getScaledCover(artist, album, iconSize());
QPixmap *pix=Covers::self()->getScaledCover(artist, album, iconSize());
if (pix) {
return pix;
}
@@ -635,7 +635,7 @@ QPixmap * AlbumsModel::AlbumItem::setCover(const QImage &img)
coverRequested=false;
if (Song::SingleTracks!=type && songs.count() && !img.isNull()) {
int size=iconSize();
return Covers::saveScaledCover(img.scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), artist, album, size);
return Covers::self()->saveScaledCover(img.scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), artist, album, size);
}
return 0;
}

View File

@@ -169,7 +169,7 @@ QPixmap * MusicLibraryItemAlbum::setCoverImage(const QImage &img) const
int size=iconSize(largeImages());
QImage scaled=img.scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
m_coverRequested=false;
return Covers::saveScaledCover(scaled, parentItem()->data(), data(), size);
return Covers::self()->saveScaledCover(scaled, parentItem()->data(), data(), size);
}
QString MusicLibraryItemAlbum::displayData(bool full) const
@@ -190,7 +190,7 @@ const QPixmap & MusicLibraryItemAlbum::cover() const
{
int iSize=iconSize(largeImages());
if (Song::SingleTracks!=m_type && parentItem() && iSize && childCount()) {
QPixmap *pix=Covers::getScaledCover(parentItem()->data(), data(), iSize);
QPixmap *pix=Covers::self()->getScaledCover(parentItem()->data(), data(), iSize);
if (pix) {
return *pix;
}

View File

@@ -91,7 +91,7 @@ bool MusicLibraryItemArtist::setCover(const QImage &img, bool update) const
scaled=scaled.copy((scaled.width()-size)/2, 0, size, size);
}
m_coverRequested=false;
Covers::saveScaledCover(scaled, data(), QString(), size);
Covers::self()->saveScaledCover(scaled, data(), QString(), size);
return true;
}
@@ -116,7 +116,7 @@ const QPixmap & MusicLibraryItemArtist::cover() const
return *theVariousArtistsIcon;
}
QPixmap *pix=Covers::getScaledCover(data(), QString(), iSize);
QPixmap *pix=Covers::self()->getScaledCover(data(), QString(), iSize);
if (pix) {
return *pix;
}
@@ -160,8 +160,7 @@ const QPixmap & MusicLibraryItemArtist::cover() const
if (!img.img.isNull()) {
setCover(img.img);
m_coverRequested=false;
pix=Covers::getScaledCover(data(), QString(), iSize);
pix=Covers::self()->getScaledCover(data(), QString(), iSize);
if (pix) {
return *pix;
}
@@ -292,3 +291,5 @@ bool MusicLibraryItemArtist::largeImages() const
return m_parentItem && Type_Root==m_parentItem->itemType() &&
static_cast<MusicLibraryItemRoot *>(m_parentItem)->useLargeImages();
}
Images();
}