rendered paste bodyIndex: libs/libmythui/mythpainter_vdpau.cpp
===================================================================
--- libs/libmythui/mythpainter_vdpau.cpp (revision 22170)
+++ libs/libmythui/mythpainter_vdpau.cpp (working copy)
@@ -9,6 +9,7 @@
#include <QApplication>
#include <QPixmap>
#include <QPainter>
+#include <QMutex>
#include <QX11Info>
// Mythdb headers
@@ -87,6 +88,9 @@
int surfaceNum;
bool initialized;
+ std::list<VdpBitmapSurface> m_surfaceDeleteList;
+ QMutex m_surfaceDeleteLock;
+
VdpOutputSurface curOutput;
VdpRect outRect;
@@ -369,6 +373,19 @@
initialized = true;
}
+ if (m_surfaceDeleteList.size())
+ {
+ m_surfaceDeleteLock.lock();
+ while (m_surfaceDeleteList.size())
+ {
+ VdpBitmapSurface bitmap = m_surfaceDeleteList.front();
+ m_surfaceDeleteList.pop_front();
+
+ vdp_bitmap_surface_destroy(bitmap);
+ }
+ m_surfaceDeleteLock.unlock();
+ }
+
curOutput = outputSurfaces[surfaceNum];
vdp_st = vdp_presentation_queue_block_until_surface_idle(
vdpFlipQueue,
@@ -411,8 +428,9 @@
{
if (m_ImageBitmapMap.contains(im))
{
- VdpBitmapSurface bitmap = m_ImageBitmapMap[im];
- vdp_bitmap_surface_destroy(bitmap);
+ m_surfaceDeleteLock.lock();
+ m_surfaceDeleteList.push_back(m_ImageBitmapMap[im]);
+ m_surfaceDeleteLock.unlock();
m_ImageBitmapMap.remove(im);
m_ImageExpireList.remove(im);
Index: libs/libmythui/mythpainter_ogl.h
===================================================================
--- libs/libmythui/mythpainter_ogl.h (revision 22170)
+++ libs/libmythui/mythpainter_ogl.h (working copy)
@@ -2,6 +2,7 @@
#define MYTHPAINTER_OPENGL_H_
#include <QMap>
+#include <QMutex>
#include <list>
@@ -60,6 +61,9 @@
bool init_extensions;
bool generate_mipmaps;
+
+ std::list<long long> m_textureDeleteList;
+ QMutex m_textureDeleteLock;
};
#endif
Index: libs/libmythui/mythuiimage.cpp
===================================================================
--- libs/libmythui/mythuiimage.cpp (revision 22173)
+++ libs/libmythui/mythuiimage.cpp (working copy)
@@ -1,20 +1,81 @@
#include "mythuiimage.h"
+// C/C++
#include <cstdlib>
+// QT
#include <QFile>
#include <QDir>
#include <QDomDocument>
#include <QImageReader>
+#include <QRunnable>
+#include <QEvent>
+#include <QCoreApplication>
+// Libmythdb
#include "mythverbose.h"
+// Mythui
#include "mythpainter.h"
#include "mythmainwindow.h"
#include "mythuihelper.h"
#include "mythscreentype.h"
+class ImageLoadThread;
+
+const int kImageLoadEventType = 35112;
+
+/*!
+ * \class ImageLoadThread
+ */
+class ImageLoadEvent : public QEvent
+{
+ public:
+ ImageLoadEvent(ImageLoadThread *thread, MythImage *image,
+ const QString &filename, int number)
+ : QEvent((QEvent::Type)kImageLoadEventType),
+ m_thread(thread), m_image(image), m_filename(filename),
+ m_number(number) { }
+
+ ImageLoadThread *GetThread() const { return m_thread; }
+ MythImage *GetImage() const { return m_image; }
+ const QString GetFilename() const { return m_filename; }
+ const int GetNumber() const { return m_number; }
+
+ private:
+ ImageLoadThread *m_thread;
+ MythImage *m_image;
+ QString m_filename;
+ int m_number;
+};
+
+/*!
+* \class ImageLoadThread
+*/
+class ImageLoadThread : public QRunnable
+{
+ public:
+ ImageLoadThread(MythUIImage *parent, const QString &filename,
+ int number)
+ : m_parent(parent), m_filename(filename), m_number(number) { };
+
+ void run()
+ {
+ MythImage *image = m_parent->LoadImage(m_filename, m_number);
+ ImageLoadEvent *le = new ImageLoadEvent(this, image, m_filename,
+ m_number);
+ QCoreApplication::postEvent(m_parent, le);
+ }
+
+ private:
+ MythUIImage *m_parent;
+ QString m_filename;
+ int m_number;
+};
+
+/////////////////////////////////////////////////////////////////
+
MythUIImage::MythUIImage(const QString &filepattern,
int low, int high, int delayms,
MythUIType *parent, const QString &name)
@@ -26,6 +87,8 @@
m_Delay = delayms;
+ m_imageLoadThread = NULL;
+
Init();
}
@@ -65,10 +128,12 @@
*/
void MythUIImage::Clear(void)
{
+ QMutexLocker locker(&m_ImagesLock);
while (!m_Images.isEmpty())
{
- m_Images.back()->DownRef();
- m_Images.pop_back();
+ QHash<int, MythImage*>::iterator it = m_Images.begin();
+ (*it)->DownRef();
+ m_Images.remove(it.key());
}
}
@@ -192,7 +257,10 @@
if (m_ForceSize.isNull())
SetSize(img->size());
- m_Images.push_back(img);
+ m_ImagesLock.lock();
+ m_Images[0] = img;
+ m_ImagesLock.unlock();
+
m_CurPos = 0;
SetRedraw();
}
@@ -237,7 +305,9 @@
if (m_isGreyscale && !im->isGrayscale())
im->ToGreyscale();
- m_Images.push_back(im);
+ m_ImagesLock.lock();
+ m_Images[m_Images.size()] = im;
+ m_ImagesLock.unlock();
aSize = aSize.expandedTo(im->size());
}
@@ -263,8 +333,9 @@
return;
QSize aSize = m_Area.size();
+ QMutexLocker locker(&m_ImagesLock);
- QVector<MythImage *>::iterator it;
+ QHash<int, MythImage *>::iterator it;
for (it = m_Images.begin(); it != m_Images.end(); ++it)
{
MythImage *im = (*it);
@@ -319,7 +390,7 @@
* \brief Generates a unique identifying string for this image which is used
* as a key in the image cache.
*/
-QString MythUIImage::GenImageLabel(const QString &filename, int w, int h)
+QString MythUIImage::GenImageLabel(const QString &filename, int w, int h) const
{
QString imagelabel;
QString s_Attrib;
@@ -347,165 +418,214 @@
* \brief Generates a unique identifying string for this image which is used
* as a key in the image cache.
*/
-QString MythUIImage::GenImageLabel(int w, int h)
+QString MythUIImage::GenImageLabel(int w, int h) const
{
return GenImageLabel(m_Filename, w, h);
}
/**
- * \brief Load the image(s)
+ * \brief Load the image(s), wraps LoadImage()
*/
-bool MythUIImage::Load(void)
+bool MythUIImage::Load(bool allowLoadInBackground)
{
+ if (m_Filename.isEmpty() && (!m_gradient))
+ {
+ Clear();
+ SetRedraw();
+
+ return false;
+ }
+
Clear();
- SetRedraw();
+// SetRedraw();
-// if (!IsVisible(true))
-// return false;
+// if (!IsVisible(true))
+// return false;
- if (m_Filename.isEmpty() && (!m_gradient))
- return false;
+ int w = -1;
+ int h = -1;
- QSize newSize;
+ if (!m_ForceSize.isNull())
+ {
+ if (m_ForceSize.width() != -1)
+ w = m_ForceSize.width();
- VERBOSE(VB_FILE, QString("MythUIImage::Load (%1) Object %2").arg(m_Filename).arg(objectName()));
+ if (m_ForceSize.height() != -1)
+ h = m_ForceSize.height();
+ }
+ QString imagelabel;
+ QString filename = m_Filename;
+
for (int i = m_LowNum; i <= m_HighNum; i++)
{
- MythImage *image = NULL;
- bool bNeedLoad = false;
+ if (m_HighNum >= 1)
+ filename = m_Filename.arg(i);
- if (m_gradient)
+ imagelabel = GenImageLabel(filename, w, h);
+
+ // Only load in the background if allowed and the image is
+ // not already in our mem cache
+ if ((allowLoadInBackground) &&
+ (!GetMythUI()->LoadCacheImage(filename, imagelabel, false)))
{
- QSize gradsize;
- if (!m_Area.isEmpty())
- gradsize = m_Area.size();
- else
- gradsize = QSize(10, 10);
-
- image = MythImage::Gradient(gradsize, m_gradientStart,
- m_gradientEnd, m_gradientAlpha,
- m_gradientDirection);
- image->UpRef();
+ m_imageLoadThread = new ImageLoadThread(this, filename, i);
+ GetMythUI()->GetImageThreadPool()->start(m_imageLoadThread);
}
else
- bNeedLoad = true;
-
- int w = -1;
- int h = -1;
-
- bool bForceResize = false;
- bool bFoundInCache = false;
-
- QString imagelabel;
-
- if (!m_ForceSize.isNull())
{
- if (m_ForceSize.width() != -1)
- w = m_ForceSize.width();
+ // Perform a blocking load
+ MythImage *image = LoadImage(filename, i);
+ if (image)
+ {
+ if (m_ForceSize.isNull())
+ SetSize(image->size());
- if (m_ForceSize.height() != -1)
- h = m_ForceSize.height();
+ m_ImagesLock.lock();
+ m_Images[i] = image;
+ m_ImagesLock.unlock();
- bForceResize = true;
+ SetRedraw();
+ m_LastDisplay = QTime::currentTime();
+ }
}
+ }
- if (bNeedLoad)
- {
+ return true;
+}
- QString filename = m_Filename;
- if (m_HighNum >= 1)
- filename = QString(m_Filename).arg(i);
+/**
+* \brief Load an image
+*/
+MythImage *MythUIImage::LoadImage(const QString &imFile, int imageNumber) const
+{
+ QString filename = imFile;
- imagelabel = GenImageLabel(filename, w, h);
+ VERBOSE(VB_FILE, QString("MythUIImage::LoadImage(%1) Object %2").arg(filename)
+ .arg(objectName()));
- image = GetMythUI()->LoadCacheImage(filename, imagelabel);
- if (image)
- {
- image->UpRef();
- VERBOSE(VB_FILE, QString("MythUIImage::Load found in cache :%1:").arg(imagelabel));
- if (m_isReflected)
- image->setIsReflected(true);
+ MythImage *image = NULL;
+ bool bNeedLoad = false;
- bFoundInCache = true;
- }
- else
- {
- VERBOSE(VB_FILE, QString("MythUIImage::Load Not Found in "
- "cache. Loading Directly :%1:")
- .arg(filename));
- image = GetMythPainter()->GetFormatImage();
- image->UpRef();
- if (!image->Load(filename))
- {
- VERBOSE(VB_FILE, QString("MythUIImage::Load Could not load :%1:").arg(filename));
- image->DownRef();
- SetRedraw();
- return false;
- }
- }
- }
+ if (m_gradient)
+ {
+ QSize gradsize;
+ if (!m_Area.isEmpty())
+ gradsize = m_Area.size();
else
- imagelabel = GenImageLabel(w,h);
+ gradsize = QSize(10, 10);
- if (!bFoundInCache)
- {
- if (bForceResize)
- image->Resize(QSize(w, h), m_preserveAspect);
+ image = MythImage::Gradient(gradsize, m_gradientStart,
+ m_gradientEnd, m_gradientAlpha,
+ m_gradientDirection);
+ image->UpRef();
+ }
+ else
+ bNeedLoad = true;
- if (m_isMasked)
- {
- QRect imageArea = image->rect();
- QRect maskArea = m_maskImage->rect();
- // Crop the mask to the image
- int x = 0;
- int y = 0;
- if (maskArea.width() > imageArea.width())
- x = (maskArea.width() - imageArea.width()) / 2;
- if (maskArea.height() > imageArea.height())
- y = (maskArea.height() - imageArea.height()) / 2;
+ bool bForceResize = false;
+ bool bFoundInCache = false;
- if (x > 0 || y > 0)
- imageArea.translate(x,y);
- QImage mask = m_maskImage->copy(imageArea);
- image->setAlphaChannel(mask.alphaChannel());
- }
+ QString imagelabel;
- if (m_isReflected)
- image->Reflect(m_reflectAxis, m_reflectShear, m_reflectScale,
- m_reflectLength, m_reflectSpacing);
+ int w = -1;
+ int h = -1;
- if (m_isGreyscale)
- image->ToGreyscale();
+ if (!m_ForceSize.isNull())
+ {
+ if (m_ForceSize.width() != -1)
+ w = m_ForceSize.width();
- // Save scaled copy to cache
- if (bNeedLoad)
- GetMythUI()->CacheImage(imagelabel, image);
- }
+ if (m_ForceSize.height() != -1)
+ h = m_ForceSize.height();
- if (!bForceResize)
+ bForceResize = true;
+ }
+
+ if (bNeedLoad)
+ {
+ imagelabel = GenImageLabel(filename, w, h);
+
+ image = GetMythUI()->LoadCacheImage(filename, imagelabel);
+ if (image)
{
- newSize = newSize.expandedTo(image->size());
- SetSize(newSize);
- }
+ image->UpRef();
+ VERBOSE(VB_FILE, QString("MythUIImage::LoadImage found in cache :%1:").arg(imagelabel));
+ if (m_isReflected)
+ image->setIsReflected(true);
- if (image->isNull())
- {
- VERBOSE(VB_FILE, QString("MythUIImage::Load Image is NULL :%1:").arg(m_Filename));
- image->DownRef();
+ bFoundInCache = true;
}
else
{
- image->SetChanged();
- m_Images.push_back(image);
+ VERBOSE(VB_FILE, QString("MythUIImage::LoadImage Not Found in "
+ "cache. Loading Directly :%1:")
+ .arg(filename));
+ image = GetMythPainter()->GetFormatImage();
+ image->UpRef();
+ if (!image->Load(filename))
+ {
+ VERBOSE(VB_FILE, QString("MythUIImage::LoadImage Could not load "
+ ":%1:").arg(filename));
+ image->DownRef();
+ return NULL;
+ }
}
}
+ else
+ imagelabel = GenImageLabel(w,h);
- m_LastDisplay = QTime::currentTime();
+ if (!bFoundInCache)
+ {
+ if (bForceResize)
+ image->Resize(QSize(w, h), m_preserveAspect);
- return true;
+ if (m_isMasked)
+ {
+ QRect imageArea = image->rect();
+ QRect maskArea = m_maskImage->rect();
+
+ // Crop the mask to the image
+ int x = 0;
+ int y = 0;
+ if (maskArea.width() > imageArea.width())
+ x = (maskArea.width() - imageArea.width()) / 2;
+ if (maskArea.height() > imageArea.height())
+ y = (maskArea.height() - imageArea.height()) / 2;
+
+ if (x > 0 || y > 0)
+ imageArea.translate(x,y);
+ QImage mask = m_maskImage->copy(imageArea);
+ image->setAlphaChannel(mask.alphaChannel());
+ }
+
+ if (m_isReflected)
+ image->Reflect(m_reflectAxis, m_reflectShear, m_reflectScale,
+ m_reflectLength, m_reflectSpacing);
+
+ if (m_isGreyscale)
+ image->ToGreyscale();
+
+ // Save scaled copy to cache
+ if (bNeedLoad)
+ GetMythUI()->CacheImage(imagelabel, image);
+ }
+
+ if (image->isNull())
+ {
+ VERBOSE(VB_FILE, QString("MythUIImage::LoadImage Image is NULL :%1:")
+ .arg(filename));
+ image->DownRef();
+ return NULL;
+ }
+ else
+ {
+ image->SetChanged();
+ }
+
+ return image;
}
/**
@@ -516,9 +636,15 @@
if (m_Delay > 0 &&
abs(m_LastDisplay.msecsTo(QTime::currentTime())) > m_Delay)
{
- m_CurPos++;
- if (m_CurPos >= (uint)m_Images.size())
- m_CurPos = 0;
+ m_ImagesLock.lock();
+ unsigned int origPos = m_CurPos;
+ do
+ {
+ m_CurPos++;
+ if (m_CurPos >= (uint)m_Images.size())
+ m_CurPos = 0;
+ } while (!m_Images.contains(m_CurPos) && m_CurPos != origPos);
+ m_ImagesLock.unlock();
SetRedraw();
m_LastDisplay = QTime::currentTime();
@@ -533,10 +659,22 @@
void MythUIImage::DrawSelf(MythPainter *p, int xoffset, int yoffset,
int alphaMod, QRect clipRect)
{
+ m_ImagesLock.lock();
if (m_Images.size() > 0)
{
if (m_CurPos > (uint)m_Images.size())
m_CurPos = 0;
+ if (!m_Images.contains(m_CurPos))
+ {
+ unsigned int origPos = m_CurPos;
+ m_CurPos++;
+ while (!m_Images.contains(m_CurPos) && m_CurPos != origPos)
+ {
+ m_CurPos++;
+ if (m_CurPos >= (uint)m_Images.size())
+ m_CurPos = 0;
+ }
+ }
QRect area = m_Area.toQRect();
area.translate(xoffset, yoffset);
@@ -544,6 +682,7 @@
int alpha = CalcAlpha(alphaMod);
MythImage *currentImage = m_Images[m_CurPos];
+ m_ImagesLock.unlock();
QRect currentImageArea = currentImage->rect();
if (!m_ForceSize.isNull())
@@ -569,6 +708,8 @@
p->DrawImage(area, currentImage, srcRect, alpha);
}
+ else
+ m_ImagesLock.unlock();
}
/**
@@ -784,8 +925,65 @@
return;
m_NeedLoad = true;
- Load();
+ Load(false);
MythUIType::LoadNow();
}
+/**
+* \copydoc MythUIType::customEvent()
+*/
+void MythUIImage::customEvent(QEvent *event)
+{
+ if (event->type() == kImageLoadEventType)
+ {
+ ImageLoadEvent *le = dynamic_cast<ImageLoadEvent*>(event);
+
+ ImageLoadThread *thread = le->GetThread();
+
+ if (thread && m_imageLoadThread && thread != m_imageLoadThread)
+ return;
+
+ MythImage *image = le->GetImage();
+
+ if (image)
+ {
+ QString filename = le->GetFilename();
+
+ if (filename == m_Filename)
+ {
+ int number = le->GetNumber();
+
+ if (m_ForceSize.isNull())
+ SetSize(image->size());
+
+ m_ImagesLock.lock();
+ if (m_Images.contains(number))
+ {
+ // There should be no image at this location, if
+ // we find one then something is wrong.
+ VERBOSE(VB_IMPORTANT, QString("DEBUG Image Thread: "
+ "Found image in m_Images position %1 where "
+ "there should be none. Filename: %2")
+ .arg(number).arg(filename));
+ image->DownRef();
+ }
+ else
+ {
+ m_Images[number] = image;
+ }
+ m_ImagesLock.unlock();
+
+ SetRedraw();
+ m_LastDisplay = QTime::currentTime();
+ }
+ else
+ {
+ // should never get here unless a non-thread sent the event
+ VERBOSE(VB_IMPORTANT, QString("Mis-Match File: %1 Not: %2")
+ .arg(filename).arg(m_Filename));
+ image->DownRef();
+ }
+ }
+ }
+}
Index: libs/libmythui/mythuihelper.h
===================================================================
--- libs/libmythui/mythuihelper.h (revision 22173)
+++ libs/libmythui/mythuihelper.h (working copy)
@@ -5,6 +5,7 @@
#include <QString>
#include <QFont>
#include <QMutex>
+#include <QThreadPool>
#include "mythexp.h"
@@ -64,7 +65,8 @@
QPixmap *LoadScalePixmap(QString filename, bool fromcache = true);
QImage *LoadScaleImage(QString filename, bool fromcache = true);
- MythImage *LoadCacheImage(QString srcfile, QString label);
+ MythImage *LoadCacheImage(QString srcfile, QString label,
+ bool allowLoadFromDisk = true);
void ThemeWidget(QWidget *widget);
@@ -113,6 +115,8 @@
QString RemoveCurrentLocation(void);
QString GetCurrentLocation(bool fullPath = false, bool mainStackOnly = true);
+ QThreadPool *GetImageThreadPool(void);
+
protected:
MythUIHelper();
~MythUIHelper();
@@ -126,8 +130,6 @@
MythUIHelperPrivate *d;
- size_t m_cacheSize;
-
QMutex m_locationLock;
QStringList m_currentLocation;
};
Index: libs/libmythui/mythpainter_ogl.cpp
===================================================================
--- libs/libmythui/mythpainter_ogl.cpp (revision 22170)
+++ libs/libmythui/mythpainter_ogl.cpp (working copy)
@@ -93,6 +93,22 @@
return;
}
+ if (m_textureDeleteList.size())
+ {
+ GLuint textures[1];
+
+ m_textureDeleteLock.lock();
+ while (m_textureDeleteList.size())
+ {
+ textures[0] = m_textureDeleteList.front();
+ m_textureDeleteList.pop_front();
+
+ glDeleteTextures(1, textures);
+ }
+ m_textureDeleteLock.unlock();
+ }
+
+
realParent->makeCurrent();
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
@@ -156,10 +172,10 @@
{
if (m_ImageIntMap.contains(im))
{
- GLuint textures[1];
- textures[0] = m_ImageIntMap[im];
+ m_textureDeleteLock.lock();
+ m_textureDeleteList.push_back(m_ImageIntMap[im]);
+ m_textureDeleteLock.unlock();
- glDeleteTextures(1, textures);
m_ImageIntMap.remove(im);
m_ImageExpireList.remove(im);
Index: libs/libmythui/mythuihelper.cpp
===================================================================
--- libs/libmythui/mythuihelper.cpp (revision 22173)
+++ libs/libmythui/mythuihelper.cpp (working copy)
@@ -14,6 +14,7 @@
#include <QPainter>
#include <QDesktopWidget>
#include <QStyleFactory>
+#include <QThreadPool>
#include "mythdirs.h"
#include "mythverbose.h"
@@ -97,6 +98,8 @@
QMap<QString, MythImage*> imageCache;
QMap<QString, uint> CacheTrack;
+ QMutex *m_cacheLock;
+ size_t m_cacheSize;
uint maxImageCacheSize;
@@ -121,6 +124,8 @@
DisplayRes *display_res;
bool screenSetup;
+ QThreadPool *m_imageThreadPool;
+
MythUIMenuCallbacks callbacks;
MythUIHelper *parent;
@@ -138,10 +143,11 @@
m_wmult(1.0), m_hmult(1.0),
m_xbase(0), m_ybase(0), m_height(0), m_width(0),
m_baseWidth(800), m_baseHeight(600), m_isWide(false),
+ m_cacheLock(new QMutex(QMutex::Recursive)), m_cacheSize(0),
m_screenxbase(0), m_screenybase(0), m_screenwidth(0), m_screenheight(0),
bigfontsize(0), mediumfontsize(0), smallfontsize(0),
screensaver(NULL), screensaverEnabled(false), display_res(NULL),
- screenSetup(false), parent(p)
+ screenSetup(false), m_imageThreadPool(new QThreadPool()), parent(p)
{
}
@@ -158,6 +164,7 @@
CacheTrack.clear();
+ delete m_imageThreadPool;
delete m_qtThemeSettings;
delete screensaver;
if(display_res)
@@ -322,7 +329,6 @@
}
MythUIHelper::MythUIHelper()
- : m_cacheSize(0)
{
d = new MythUIHelperPrivate(this);
}
@@ -336,8 +342,11 @@
{
d->Init();
d->callbacks = cbs;
+
+ d->m_cacheLock->lock();
d->maxImageCacheSize = GetMythDB()->GetNumSetting("UIImageCacheSize", 20)
* 1024 * 1024;
+ d->m_cacheLock->unlock();
VERBOSE(VB_GENERAL, QString("MythUI Image Cache size set to %1 bytes")
.arg(d->maxImageCacheSize));
@@ -424,6 +433,8 @@
void MythUIHelper::UpdateImageCache(void)
{
+ QMutexLocker locker(d->m_cacheLock);
+
QMutableMapIterator<QString, MythImage*> i(d->imageCache);
while (i.hasNext())
{
@@ -434,13 +445,14 @@
}
d->CacheTrack.clear();
- m_cacheSize = 0;
+ d->m_cacheSize = 0;
ClearOldImageCache();
}
MythImage *MythUIHelper::GetImageFromCache(const QString &url)
{
+ QMutexLocker locker(d->m_cacheLock);
if (d->imageCache.contains(url))
return d->imageCache[url];
@@ -461,7 +473,9 @@
if (!im)
return;
- m_cacheSize += im->numBytes();
+ d->m_cacheLock->lock();
+ d->m_cacheSize += im->numBytes();
+ d->m_cacheLock->unlock();
}
void MythUIHelper::ExcludeFromCacheSize(MythImage *im)
@@ -469,7 +483,9 @@
if (!im)
return;
- m_cacheSize -= im->numBytes();
+ d->m_cacheLock->lock();
+ d->m_cacheSize -= im->numBytes();
+ d->m_cacheLock->unlock();
}
MythImage *MythUIHelper::CacheImage(const QString &url, MythImage *im,
@@ -494,7 +510,8 @@
}
// delete the oldest cached images until we fall below threshold.
- while (m_cacheSize + im->numBytes() >= d->maxImageCacheSize &&
+ QMutexLocker locker(d->m_cacheLock);
+ while (d->m_cacheSize + im->numBytes() >= d->maxImageCacheSize &&
d->imageCache.size())
{
QMap<QString, MythImage*>::iterator it = d->imageCache.begin();
@@ -519,7 +536,7 @@
if (count > 0)
{
VERBOSE(VB_FILE, QString("Cache too big (%1), removing :%2:")
- .arg(m_cacheSize + im->numBytes()).arg(oldestKey));
+ .arg(d->m_cacheSize + im->numBytes()).arg(oldestKey));
d->imageCache[oldestKey]->DownRef();
d->imageCache.remove(oldestKey);
@@ -538,18 +555,19 @@
im->SetIsInCache(true);
VERBOSE(VB_FILE, QString("NOT IN RAM CACHE, Adding, and adding to size "
- ":%1: :%2:").arg(url).arg(m_cacheSize));
+ ":%1: :%2:").arg(url).arg(d->m_cacheSize));
}
VERBOSE(VB_FILE, QString("MythUIHelper::CacheImage : Cache Count = :%1: "
"size :%2:")
- .arg(d->imageCache.count()).arg(m_cacheSize));
+ .arg(d->imageCache.count()).arg(d->m_cacheSize));
return d->imageCache[url];
}
void MythUIHelper::RemoveFromCacheByURL(const QString &url)
{
+ QMutexLocker locker(d->m_cacheLock);
QMap<QString, MythImage*>::iterator it = d->imageCache.find(url);
if (it != d->imageCache.end())
@@ -576,11 +594,13 @@
QString partialKey = fname;
partialKey.replace('/', '-');
+ d->m_cacheLock->lock();
for (it = d->imageCache.begin(); it != d->imageCache.end(); ++it)
{
if (it.key().contains(partialKey))
RemoveFromCacheByURL(it.key());
}
+ d->m_cacheLock->unlock();
// Loop through files to cache any that were not caught by
// RemoveFromCacheByURL
@@ -600,6 +620,8 @@
bool MythUIHelper::IsImageInCache(const QString &url)
{
+ QMutexLocker locker(d->m_cacheLock);
+
if (d->imageCache.contains(url))
return true;
@@ -1216,7 +1238,8 @@
return ret;
}
-MythImage *MythUIHelper::LoadCacheImage(QString srcfile, QString label)
+MythImage *MythUIHelper::LoadCacheImage(QString srcfile, QString label,
+ bool allowLoadFromDisk)
{
//VERBOSE(VB_GENERAL, QString("LoadCacheImage %1:%2").arg(srcfile).arg(label));
@@ -1234,7 +1257,7 @@
{
// Check Memory Cache
ret = GetImageFromCache(label);
- if (!ret)
+ if (!ret && allowLoadFromDisk)
{
// Load file from disk cache to memory cache
ret = GetMythPainter()->GetFormatImage();
@@ -1458,3 +1481,8 @@
return result;
}
+
+QThreadPool *MythUIHelper::GetImageThreadPool(void)
+{
+ return d->m_imageThreadPool;
+}
Index: libs/libmythui/mythuiimage.h
===================================================================
--- libs/libmythui/mythuiimage.h (revision 22173)
+++ libs/libmythui/mythuiimage.h (working copy)
@@ -2,11 +2,14 @@
#define MYTHUI_IMAGE_H_
#include <QDateTime>
+#include <QHash>
+#include <QMutex>
#include "mythuitype.h"
#include "mythimage.h"
class MythScreenType;
+class ImageLoadThread;
/**
* \class MythUIImage
@@ -22,6 +25,8 @@
MythUIImage(MythUIType *parent, const QString &name);
~MythUIImage();
+ QString GetFilename(void) { return m_Filename; }
+
/** Must be followed by a call to Load() to load the image. */
void SetFilename(const QString &filename);
@@ -43,7 +48,7 @@
void SetDelay(int delayms);
void Reset(void);
- bool Load(void);
+ bool Load(bool allowLoadInBackground = true);
bool IsGradient(void) const { return m_gradient; }
@@ -57,6 +62,8 @@
void Init(void);
void Clear(void);
+ MythImage* LoadImage(const QString &imFile, int imageNumber = 0) const;
+ void customEvent(QEvent *event);
virtual bool ParseElement(QDomElement &element);
virtual void CopyFrom(MythUIType *base);
@@ -70,13 +77,14 @@
void SetCropRect(int x, int y, int width, int height);
void SetCropRect(const MythRect &rect);
- QString GenImageLabel(const QString &filename, int w, int h);
- QString GenImageLabel(int w, int h);
+ QString GenImageLabel(const QString &filename, int w, int h) const;
+ QString GenImageLabel(int w, int h) const;
QString m_Filename;
QString m_OrigFilename;
- QVector<MythImage *> m_Images;
+ QHash<int, MythImage *> m_Images;
+ QMutex m_ImagesLock;
MythRect m_cropRect;
QSize m_ForceSize;
@@ -110,10 +118,13 @@
bool m_isGreyscale;
+ ImageLoadThread *m_imageLoadThread;
+
friend class MythThemeBase;
friend class MythUIButtonListItem;
friend class MythUIProgressBar;
friend class MythUITextEdit;
+ friend class ImageLoadThread;
};
#endif
Index: programs/mythfrontend/playbackbox.cpp
===================================================================
--- programs/mythfrontend/playbackbox.cpp (revision 22171)
+++ programs/mythfrontend/playbackbox.cpp (working copy)
@@ -541,15 +541,15 @@
InfoMap infoMap;
int countInGroup;
- if (m_fanart)
- m_fanart->SetVisible(false);
-
if (groupname.isEmpty())
{
countInGroup = m_progLists[""].size();
infoMap["title"] = m_groupDisplayName;
infoMap["group"] = m_groupDisplayName;
infoMap["show"] = ProgramInfo::i18n("All Programs");
+
+ if (m_fanart)
+ m_fanart->Reset();
}
else
{
@@ -561,30 +561,26 @@
if (m_fanart)
{
- m_fanart->Reset();
- m_fanartTimer->stop();
-
- QString fanartHost;
+ static int itemsPast = 0;
+VERBOSE(VB_IMPORTANT, QString("have m_fanart, itemsPast: %1").arg(itemsPast));
+ QString artworkHost;
if (gContext->GetNumSetting("MasterBackendOverride", 0))
- fanartHost = gContext->GetMasterHostName();
+ artworkHost = gContext->GetMasterHostName();
else
- fanartHost = (*(m_progLists[groupname].begin()))->hostname;
+ artworkHost = (*(m_progLists[groupname].begin()))->hostname;
- QString fanartDir = gContext->GetSetting("mythvideo.fanartDir");
- QString fanartTitle = groupname;
- QString fanartSeriesID;
- QString fanartFile = testImageFiles(fanartDir, fanartSeriesID,
- fanartTitle, "fanart",
- fanartHost);
- if (!fanartFile.isEmpty())
- {
- m_fanart->SetFilename(fanartFile);
-
- m_fanartTimer->setSingleShot(true);
- m_fanartTimer->start(500);
- }
+ QString artworkDir = gContext->GetSetting("mythvideo.fanartDir");
+ QString artworkTitle = groupname;
+ QString artworkSeriesID;
+ QString artworkFile = findArtworkFile(artworkDir, artworkSeriesID,
+ artworkTitle, "fanart",
+ artworkHost);
+ if (loadArtwork(artworkFile, m_fanart, m_fanartTimer, 300,
+ itemsPast > 2))
+ itemsPast++;
+ else
+ itemsPast = 0;
}
-
}
if (countInGroup > 1)
@@ -615,13 +611,13 @@
jobState->Reset();
if (m_previewImage)
- m_previewImage->SetVisible(false);
+ m_previewImage->Reset();
if (m_banner)
- m_banner->SetVisible(false);
+ m_banner->Reset();
if (m_coverart)
- m_coverart->SetVisible(false);
+ m_coverart->Reset();
updateIcons();
}
@@ -684,84 +680,57 @@
if (m_previewImage)
{
imagefile = (imagefile.isEmpty()) ? oldimgfile : imagefile;
- m_previewImage->SetVisible(!imagefile.isEmpty());
m_previewImage->SetFilename(imagefile);
m_previewImage->Load();
}
- QString artworkHost;
- if (gContext->GetNumSetting("MasterBackendOverride", 0))
- artworkHost = gContext->GetMasterHostName();
- else
- artworkHost = pginfo->hostname;
-
- if (m_fanart)
+ if (m_fanart || m_banner || m_coverart)
{
- m_fanartTimer->stop();
- m_fanart->SetVisible(false);
- m_fanart->Reset();
+ QString artworkHost;
+ QString artworkDir;
+ QString artworkFile;
+ QString artworkTitle = pginfo->title;
+ QString artworkSeriesID = pginfo->seriesid;
- QString fanartDir = gContext->GetSetting("mythvideo.fanartDir");
- QString fanartTitle = pginfo->title;
- QString fanartSeriesID = pginfo->seriesid;
- QString fanartFile = testImageFiles(fanartDir,
- fanartSeriesID,
- fanartTitle,
- "fanart",
- artworkHost);
- if (!fanartFile.isEmpty())
+ if (gContext->GetNumSetting("MasterBackendOverride", 0))
+ artworkHost = gContext->GetMasterHostName();
+ else
+ artworkHost = pginfo->hostname;
+
+ if (m_fanart)
{
- m_fanart->SetFilename(fanartFile);
-
- m_fanartTimer->stop();
- m_fanartTimer->setSingleShot(true);
- m_fanartTimer->start(500);
+ static int itemsPast = 0;
+VERBOSE(VB_IMPORTANT, QString("have m_fanart, itemsPast: %1").arg(itemsPast));
+ artworkDir = gContext->GetSetting("mythvideo.fanartDir");
+ artworkFile = findArtworkFile(artworkDir, artworkSeriesID,
+ artworkTitle, "fanart",
+ artworkHost);
+ if (loadArtwork(artworkFile, m_fanart, m_fanartTimer, 300,
+ itemsPast > 2))
+ itemsPast++;
+ else
+ itemsPast = 0;
}
- }
- if (m_banner)
- {
- m_bannerTimer->stop();
- m_banner->SetVisible(false);
- m_banner->Reset();
-
- QString bannerDir = gContext->GetSetting("mythvideo.bannerDir");
- QString bannerTitle = pginfo->title;
- QString bannerSeriesID = pginfo->seriesid;
- QString bannerFile = testImageFiles(bannerDir,
- bannerSeriesID,
- bannerTitle,
- "banner",
- artworkHost);
- if (!bannerFile.isEmpty())
+ if (m_banner)
{
- m_banner->SetFilename(bannerFile);
-
- m_bannerTimer->setSingleShot(true);
- m_bannerTimer->start(500);
+VERBOSE(VB_IMPORTANT, "have m_banner");
+ artworkDir = gContext->GetSetting("mythvideo.bannerDir");
+ artworkFile = findArtworkFile(artworkDir, artworkSeriesID,
+ artworkTitle, "banner",
+ artworkHost);
+ loadArtwork(artworkFile, m_banner, m_bannerTimer, 50);
}
- }
- if (m_coverart)
- {
- m_coverartTimer->stop();
- m_coverart->SetVisible(false);
- m_coverart->Reset();
-
- QString coverDir = gContext->GetSetting("VideoArtworkDir");
- QString coverTitle = pginfo->title;
- QString coverSeriesID = pginfo->seriesid;
- QString coverFile = testImageFiles(coverDir,
- coverSeriesID,
- coverTitle,
- "coverart",
- artworkHost);
- if (!coverFile.isEmpty())
+ if (m_coverart)
{
- m_coverart->SetFilename(coverFile);
-
- m_coverartTimer->setSingleShot(true);
- m_coverartTimer->start(500);
+VERBOSE(VB_IMPORTANT, "have m_coverart");
+ artworkDir = gContext->GetSetting("VideoArtworkDir");
+ artworkFile = findArtworkFile(artworkDir, artworkSeriesID,
+ artworkTitle, "coverart",
+ artworkHost);
+VERBOSE(VB_IMPORTANT, QString("have m_coverart, artworkfile: %1").arg(artworkFile));
+ loadArtwork(artworkFile, m_coverart, m_coverartTimer, 50);
}
}
@@ -2020,25 +1989,59 @@
void PlaybackBox::fanartLoad(void)
{
- m_fanart->SetVisible(true);
m_fanart->Load();
}
void PlaybackBox::bannerLoad(void)
{
- m_banner->SetVisible(true);
m_banner->Load();
}
void PlaybackBox::coverartLoad(void)
{
- m_coverart->SetVisible(true);
m_coverart->Load();
}
-QString PlaybackBox::testImageFiles(QString &testDirectory, QString &seriesID,
- QString &titleIn, QString imagetype, QString host)
+bool PlaybackBox::loadArtwork(QString artworkFile, MythUIImage *image, QTimer *timer,
+ int delay, bool resetImage)
{
+VERBOSE(VB_IMPORTANT, QString("PBB::loadArtwork('%1', '%2', timer, %3, %4)").arg(artworkFile).arg(image->GetFilename()).arg(delay).arg((int)resetImage));
+ bool wasActive = timer->isActive();
+
+ if (artworkFile.isEmpty())
+ {
+ if (wasActive)
+ timer->stop();
+
+ image->Reset();
+
+ return true;
+ }
+ else
+ {
+ if (artworkFile != image->GetFilename())
+ {
+ if (wasActive)
+ timer->stop();
+
+ if (resetImage)
+ image->Reset();
+
+ image->SetFilename(artworkFile);
+
+ timer->setSingleShot(true);
+ timer->start(delay);
+
+ return wasActive;
+ }
+ }
+
+ return false;
+}
+
+QString PlaybackBox::findArtworkFile(QString &testDirectory, QString &seriesID,
+ QString &titleIn, QString imagetype, QString host)
+{
static QHash <QString, QString>imageFileCache;
QString cacheKey = QString("%1:%2:%3").arg(imagetype).arg(seriesID)
Index: programs/mythfrontend/playbackbox.h
===================================================================
--- programs/mythfrontend/playbackbox.h (revision 22171)
+++ programs/mythfrontend/playbackbox.h (working copy)
@@ -309,9 +309,11 @@
QString getRecGroupPassword(const QString &recGroup);
void fillRecGroupPasswordCache(void);
- QString testImageFiles(QString &testDirectory,
- QString &seriesID, QString &titleIn,
- QString imagetype, QString host);
+ bool loadArtwork(QString artworkFile, MythUIImage *image, QTimer *timer,
+ int delay = 500, bool resetImage = false);
+ QString findArtworkFile(QString &testDirectory,
+ QString &seriesID, QString &titleIn,
+ QString imagetype, QString host);
void updateGroupList();
void updateIcons(const ProgramInfo *pginfo = NULL);