All pastes #1589050 Raw Edit

Mine

public text v1 · immutable
#1589050 ·published 2009-10-02 07:30 UTC
rendered paste body
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,212 @@
  *  \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)
 {
     Clear();
 
     SetRedraw();
 
-//     if (!IsVisible(true))
-//         return false;
-
     if (m_Filename.isEmpty() && (!m_gradient))
         return false;
 
-    QSize newSize;
+//    if (!IsVisible(true))
+//        return false;
 
-    VERBOSE(VB_FILE, QString("MythUIImage::Load (%1) Object %2").arg(m_Filename).arg(objectName()));
+    int w = -1;
+    int h = -1;
 
+    if (!m_ForceSize.isNull())
+    {
+        if (m_ForceSize.width() != -1)
+            w = m_ForceSize.width();
+
+        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, m_Filename, i);
+            GetMythUI()->GetImageLoaderThreadPool()->start(m_imageLoadThread);
         }
         else
-            bNeedLoad = true;
+        {
+            // Perform a blocking load
+            MythImage *image = LoadImage(filename, i);
+            if (image)
+            {
+                if (m_ForceSize.isNull())
+                    SetSize(image->size());
 
-        int w = -1;
-        int h = -1;
+                m_ImagesLock.lock();
+                m_Images[i] = image;
+                m_ImagesLock.unlock();
 
-        bool bForceResize = false;
-        bool bFoundInCache = false;
+                SetRedraw();
+                m_LastDisplay = QTime::currentTime();
+            }
+        }
+    }
 
-        QString imagelabel;
+    return true;
+}
 
-        if (!m_ForceSize.isNull())
-        {
-            if (m_ForceSize.width() != -1)
-                w = m_ForceSize.width();
+/**
+*  \brief Load an image
+*/
+MythImage *MythUIImage::LoadImage(const QString &imFile, int imageNumber) const
+{
+    QString filename = imFile;
 
-            if (m_ForceSize.height() != -1)
-                h = m_ForceSize.height();
+    VERBOSE(VB_FILE, QString("MythUIImage::LoadImage(%1) Object %2").arg(filename)
+                                                .arg(objectName()));
 
-            bForceResize = true;
-        }
+    MythImage *image = NULL;
+    bool bNeedLoad = false;
 
-        if (bNeedLoad)
-        {
+    if (m_gradient)
+    {
+        QSize gradsize;
+        if (!m_Area.isEmpty())
+            gradsize = m_Area.size();
+        else
+            gradsize = QSize(10, 10);
 
-            QString filename = m_Filename;
-            if (m_HighNum >= 1)
-                filename = QString(m_Filename).arg(i);
+        image = MythImage::Gradient(gradsize, m_gradientStart,
+                                    m_gradientEnd, m_gradientAlpha,
+                                    m_gradientDirection);
+        image->UpRef();
+    }
+    else
+        bNeedLoad = true;
 
-            imagelabel = GenImageLabel(filename, w, h);
 
-            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);
+    bool bForceResize = false;
+    bool bFoundInCache = 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;
-                }
-            }
-        }
-        else
-            imagelabel = GenImageLabel(w,h);
+    QString imagelabel;
 
-        if (!bFoundInCache)
-        {
-            if (bForceResize)
-                image->Resize(QSize(w, h), m_preserveAspect);
+    int w = -1;
+    int h = -1;
 
-            if (m_isMasked)
-            {
-                QRect imageArea = image->rect();
-                QRect maskArea = m_maskImage->rect();
+    if (!m_ForceSize.isNull())
+    {
+        if (m_ForceSize.width() != -1)
+            w = m_ForceSize.width();
 
-                // 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 (m_ForceSize.height() != -1)
+            h = m_ForceSize.height();
 
-                if (x > 0 || y > 0)
-                    imageArea.translate(x,y);
-                QImage mask = m_maskImage->copy(imageArea);
-                image->setAlphaChannel(mask.alphaChannel());
-            }
+        bForceResize = true;
+    }
 
-            if (m_isReflected)
-                image->Reflect(m_reflectAxis, m_reflectShear, m_reflectScale,
-                            m_reflectLength, m_reflectSpacing);
+    if (bNeedLoad)
+    {
+        if (imageNumber >= 1)
+            filename = QString(filename).arg(imageNumber);
 
-            if (m_isGreyscale)
-                image->ToGreyscale();
+        imagelabel = GenImageLabel(filename, w, h);
 
-            // Save scaled copy to cache
-            if (bNeedLoad)
-                GetMythUI()->CacheImage(imagelabel, image);
-        }
-
-        if (!bForceResize)
+        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 +634,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 +657,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 +680,7 @@
         int alpha = CalcAlpha(alphaMod);
 
         MythImage *currentImage = m_Images[m_CurPos];
+        m_ImagesLock.unlock();
         QRect currentImageArea = currentImage->rect();
 
         if (!m_ForceSize.isNull())
@@ -569,6 +706,8 @@
 
         p->DrawImage(area, currentImage, srcRect, alpha);
     }
+    else
+        m_ImagesLock.unlock();
 }
 
 /**
@@ -784,8 +923,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 *GetImageLoaderThreadPool(void) {return imageLoaderThreadPool;}
+
   protected:
     MythUIHelper();
    ~MythUIHelper();
@@ -130,6 +134,8 @@
 
     QMutex m_locationLock;
     QStringList m_currentLocation;
+
+    QThreadPool *imageLoaderThreadPool;
 };
 
 MPUBLIC MythUIHelper *GetMythUI();
Index: libs/libmythui/mythuihelper.cpp
===================================================================
--- libs/libmythui/mythuihelper.cpp	(revision 22173)
+++ libs/libmythui/mythuihelper.cpp	(working copy)
@@ -325,6 +325,8 @@
              : m_cacheSize(0)
 {
     d = new MythUIHelperPrivate(this);
+
+    imageLoaderThreadPool = new QThreadPool();
 }
 
 MythUIHelper::~MythUIHelper()
@@ -1216,7 +1218,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 +1237,7 @@
         {
             // Check Memory Cache
             ret = GetImageFromCache(label);
-            if (!ret)
+            if (!ret && allowLoadFromDisk)
             {
                 // Load file from disk cache to memory cache
                 ret = GetMythPainter()->GetFormatImage();
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
@@ -43,7 +46,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 +60,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 +75,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 +116,13 @@
 
     bool m_isGreyscale;
 
+    ImageLoadThread *m_imageLoadThread;
+
     friend class MythThemeBase;
     friend class MythUIButtonListItem;
     friend class MythUIProgressBar;
     friend class MythUITextEdit;
+    friend class ImageLoadThread;
 };
 
 #endif