Index: libs/libmythtv/osdtypes.cpp
===================================================================
--- libs/libmythtv/osdtypes.cpp	(revision 9320)
+++ libs/libmythtv/osdtypes.cpp	(working copy)
@@ -1,6 +1,10 @@
 #include <qimage.h>
 #include <qmap.h>
 #include <qregexp.h>
+#include <qstring.h>
+#include <qfile.h>
+#include <qdatastream.h>
+#include <qdir.h>
 
 #include <iostream>
 using namespace std;
@@ -175,15 +179,16 @@
     m_yoffsetbase = yoff;
 
     vector<OSDType *>::iterator iter = allTypes->begin();
-    for (;iter != allTypes->end(); iter++)
+    for (;iter != allTypes->end(); ++iter)
     {
-        if (OSDTypeCC *cc608 = dynamic_cast<OSDTypeCC*>(*iter))
-            cc608->Reinit(xoff, yoff, displaywidth, displayheight,
-                          wmult, hmult);
-        else if (OSDType708CC *cc708 = dynamic_cast<OSDType708CC*>(*iter))
-            cc708->Reinit(xoff, yoff, displaywidth, displayheight);
-        else
-            (*iter)->Reinit(wmult, hmult);
+	// Use polymorphism instead of the dynamic_cast hack.
+	// Have two Reinit() versions in base OSDType, one with all the 
+	// arguments, and one with the minimum args. Call the version with all
+	// the arguments, and the derived classes then use the arguments
+	// if they want to. This was one slow piece of code while optimizing
+	// the OSD rescale. --visit0r
+	(*iter)->Reinit(xoff, yoff, displaywidth, displayheight,
+			wmult, hmult);
     }
 }
 
@@ -389,6 +394,16 @@
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
 
+void 
+OSDType::Reinit(int, int, int, int, float wmult, float hmult) 
+{
+// The default implementation delegates the call to the Reinit(wmult, hmult) 
+// method.
+// This allows cleaner dynamically bound call in OSDSet::Reinit() without
+// the ugly (and slow!) dynamic_cast.
+    Reinit(wmult, hmult);
+}
+
 OSDType::OSDType(const QString &name)
 {
     m_hidden = false;
@@ -674,6 +689,7 @@
     m_scalew = scalew;
     m_scaleh = scaleh;
     m_dontround = false;
+    m_cached = false;
 
     LoadImage(filename, wmult, hmult, scalew, scaleh);
 }
@@ -753,10 +769,17 @@
 
 OSDTypeImage::~OSDTypeImage()
 {
-    if (m_yuv)
-        delete [] m_yuv;
-    if (m_alpha)
-        delete [] m_alpha;
+    // cleanup the OSD image cache in memory
+    m_cacheLock.lock();
+    QMapIterator<QString, OSDImageCacheValue> i = m_imageCache.begin();
+    while (i != m_imageCache.end()) {
+	OSDImageCacheValue& value = i.data();
+	delete [] value.m_yuv;
+	delete [] value.m_alpha;
+	++i;
+    }
+    m_imageCache.clear();
+    m_cacheLock.unlock();
 }
 
 void OSDTypeImage::SetName(const QString &name)
@@ -781,19 +804,188 @@
     LoadImage(m_filename, wmult, hmult, m_scalew, m_scaleh);
 }
 
+#include <iostream>
+
+/**
+ * Returns true in case cached OSD image was found in the cache.
+ *
+ * @param imageKey The key for this image.
+ * @param useDiskCache If true, also look from the disk cache.
+ */
+bool OSDTypeImage::isCached(QString imageKey, bool useDiskCache) {
+
+    QMutexLocker locker(&m_cacheLock);
+
+    if (m_imageCache.find(imageKey) != m_imageCache.end()) {
+	return true;
+    }
+
+    if (!useDiskCache)
+	return false;
+
+    QDir dir(MythContext::GetConfDir() + "/osdcache/");
+
+    QFile cacheFile(dir.path() + "/" + imageKey);
+    if (cacheFile.exists()) {
+	return true;
+    } 
+    return false;
+}
+
+/**
+ * Loads OSD image data from cache.
+ *
+ * @param imageKey The key for this image.
+ * @param useDiskCache If true, also look from the disk cache.
+ */
+void OSDTypeImage::loadFromCache(QString imageKey, bool useDiskCache) {
+
+    OSDImageCacheValue value;
+
+    QMutexLocker locker(&m_cacheLock);
+
+    if (m_imageCache.find(imageKey) != m_imageCache.end()) {
+	// the image was found in the memory cache
+	value = m_imageCache[imageKey];
+    } else if (useDiskCache) {
+
+	QDir dir(MythContext::GetConfDir() + "/osdcache/");
+
+	QFile cacheFile(dir.path() + "/" + imageKey);
+	if (!cacheFile.exists()) {
+	    return;
+	}
+
+	cacheFile.open(IO_ReadOnly);
+	QDataStream stream(&cacheFile);
+	Q_INT32 imwidth = 0, imheight = 0;
+	stream >> imwidth >> imheight;   
+	
+	int yuv_size = imwidth * imheight * 3 / 2;
+	value.m_yuv = new unsigned char[yuv_size];
+	value.m_ybuffer = value.m_yuv;
+	value.m_ubuffer = value.m_yuv + (imwidth * imheight);
+	value.m_vbuffer = value.m_yuv + (imwidth * imheight * 5 / 4);
+
+	unsigned expectedFileSize = 
+	    2*sizeof(Q_INT32) + yuv_size + imwidth*imheight;
+	if (cacheFile.size() != expectedFileSize) {
+	    VERBOSE(VB_IMPORTANT, imageKey + " wrong cache file size!");
+	    std::cout << "LOG: " 
+		      << cacheFile.size() << " != " 
+		      << expectedFileSize << std::endl;
+	    return;
+	}
+
+	stream.readRawBytes((char*)value.m_yuv, yuv_size);
+
+	value.m_alpha = new unsigned char[imwidth * imheight];
+
+	stream.readRawBytes((char*)value.m_alpha, imwidth * imheight);
+
+	value.m_imagesize = QRect(0, 0, imwidth, imheight);
+	m_imageCache[imageKey] = value;
+	cacheFile.close();
+	// the image was found and loaded from disk cache
+    } else {
+	// image was not found in neither of the caches
+	return;
+    }
+    m_yuv = value.m_yuv;
+    m_ybuffer = value.m_ybuffer;
+    m_ubuffer = value.m_ubuffer;
+    m_vbuffer = value.m_vbuffer;
+    m_alpha = value.m_alpha;
+    m_imagesize = value.m_imagesize;
+    m_isvalid = true;
+}
+
+/**
+ * Saves the current OSD image data from cache.
+ *
+ * @param imageKey The key for this image.
+ * @param useDiskCache If true, also save to the disk cache.
+ */
+void OSDTypeImage::saveToCache(QString imageKey, bool useDiskCache) {
+
+    if (isCached(imageKey, useDiskCache))
+	return;
+
+    OSDImageCacheValue value;
+
+    value.m_yuv = m_yuv;
+    value.m_ybuffer = m_ybuffer;
+    value.m_ubuffer = m_ubuffer;
+    value.m_vbuffer = m_vbuffer;
+    value.m_alpha = m_alpha; 
+    value.m_imagesize = m_imagesize;
+
+    m_cacheLock.lock();
+    m_imageCache[imageKey] = value;
+    m_cacheLock.unlock();
+
+    if (!useDiskCache)
+	return;
+
+    QDir dir(MythContext::GetConfDir() + "/osdcache/");
+
+    if (!dir.exists()) {
+        if (!dir.mkdir(dir.path())) {
+	    VERBOSE(VB_IMPORTANT, "Creating osdcache directory failed.");
+	    return;
+	}
+    }
+
+    QFile cacheFile(dir.path() + "/" + imageKey);
+
+    if (!cacheFile.open(IO_WriteOnly | IO_Truncate)) {
+	VERBOSE(VB_IMPORTANT, "Creating osdcache file failed.");
+	return;
+    }
+    QDataStream stream(&cacheFile);
+    Q_INT32 imwidth = m_imagesize.width(), imheight = m_imagesize.height();
+    stream << imwidth << imheight;   
+
+    int yuv_size = imwidth * imheight * 3 / 2;
+
+    stream.writeRawBytes((const char*)m_yuv, yuv_size);
+    stream.writeRawBytes((const char*)m_alpha, imwidth * imheight);
+    // saved the image to disk cache
+    cacheFile.close();
+}
+
+/**
+ * Generates a cache key from the given OSD image parameters.
+ *
+ * The returned key is a string that can be safely used as a file name.
+ */
+QString OSDTypeImage::generateCacheKey(const QString &filename, float wmult, 
+				       float hmult, int scalew, int scaleh) {
+    
+    QString cacheKey = 
+	QString("%1_%2_%3_%4_%5")
+	.arg(filename).arg(wmult).arg(hmult).arg(scalew).arg(scaleh)
+	.replace(QChar('/'), ".").replace(QChar(' '), ".")
+	.replace(QChar(' '), ".");
+
+    return cacheKey;
+}
+
+
 void OSDTypeImage::LoadImage(const QString &filename, float wmult, float hmult,
                              int scalew, int scaleh)
 {
-    if (m_isvalid)
-    {
-        if (m_yuv)
-            delete [] m_yuv;
-        if (m_alpha)
-            delete [] m_alpha;
+    QString cacheKey = generateCacheKey(filename, wmult, hmult, scalew, 
+					scaleh);
 
-        m_isvalid = false;
-        m_yuv = NULL;
-        m_alpha = NULL;
+    // if there's no filename, do not use file buffering (cannot
+    // generate an unique filename for the cache file), but only
+    // the memory cache as it's safe to do so, because the
+    // memory cache is per OSDTypeImage
+    if (isCached(cacheKey, !filename.isEmpty())) {
+	loadFromCache(cacheKey, !filename.isEmpty());
+	m_cached = true;
+	return;
     }
 
     if (filename.length() < 2)
@@ -836,17 +1028,22 @@
                      imwidth, imheight, tmp2.width());
 
     m_imagesize = QRect(0, 0, imwidth, imheight);
+
+    saveToCache(cacheKey, !filename.isEmpty());
+    m_cached = true;
 }
 
 void OSDTypeImage::LoadFromQImage(const QImage &img)
 {
-    if (m_isvalid)
+    // this method is not cached as it's used mostly for
+    // subtitles which are displayed only once anyways, caching
+    // would probably only slow things down overall
+    if (m_isvalid && !m_cached)
     {
         if (m_yuv)
             delete [] m_yuv;
         if (m_alpha)
             delete [] m_alpha;
-
         m_isvalid = false;
         m_yuv = NULL;
         m_alpha = NULL;
@@ -1149,11 +1346,6 @@
 OSDTypeEditSlider::~OSDTypeEditSlider()
 {
     delete [] m_drawMap;
-
-    if (m_ryuv)
-        delete [] m_ryuv;
-    if (m_ralpha)
-        delete [] m_ralpha;
 }
 
 void OSDTypeEditSlider::Reinit(float wmult, float hmult)
@@ -1169,10 +1361,12 @@
 
     m_displaypos = m_displayrect.topLeft();
 
-    if (m_ryuv)
-        delete [] m_ryuv;
-    if (m_ralpha)
-        delete [] m_ralpha;
+    if (!m_cached) {
+	if (m_ryuv)
+	    delete [] m_ryuv;
+	if (m_ralpha)
+	    delete [] m_ralpha;
+    }
 
     LoadImage(m_redname, wmult, hmult, m_scalew, m_scaleh);
     if (m_isvalid)
@@ -1893,7 +2087,7 @@
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-void OSDType708CC::Reinit(int x, int y, int dispw, int disph)
+void OSDType708CC::Reinit(int x, int y, int dispw, int disph, float, float)
 {
     xoffset = x;
     yoffset = y;
Index: libs/libmythtv/osdtypes.h
===================================================================
--- libs/libmythtv/osdtypes.h	(revision 9320)
+++ libs/libmythtv/osdtypes.h	(working copy)
@@ -156,6 +156,9 @@
 
     QString Name() { return m_name; }
 
+    virtual void Reinit(int xoff, int yoff, int dispw, int disph,
+			float wmult, float hmult);
+
     virtual void Reinit(float wmult, float hmult) = 0;
 
     virtual void Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
@@ -282,7 +285,25 @@
     QString m_filename;
 
     bool m_isvalid;
+    
+    struct OSDImageCacheValue {
+	unsigned char *m_yuv;
+	unsigned char *m_ybuffer;
+	unsigned char *m_ubuffer;
+	unsigned char *m_vbuffer;
+	unsigned char *m_alpha;
+	QRect m_imagesize;
+    };
 
+    QMap<QString, OSDImageCacheValue> m_imageCache;
+    QMutex m_cacheLock;
+
+    QString generateCacheKey(const QString &filename, float wmult, float hmult,
+			     int scalew, int scaleh);
+    bool isCached(QString imageKey, bool useDiskCache);
+    void loadFromCache(QString imageKey, bool useDiskCache);
+    void saveToCache(QString imageKey, bool useDiskCache);
+
     unsigned char *m_yuv;
     unsigned char *m_ybuffer;
     unsigned char *m_ubuffer;
@@ -295,6 +316,7 @@
     int m_drawwidth;
     bool m_onlyusefirst;
     bool m_dontround;
+    bool m_cached;
 };
 
 class OSDTypePosSlider : public OSDTypeImage
@@ -514,7 +536,7 @@
     virtual ~OSDType708CC() {}
 
     void Reinit(float, float) {}
-    void Reinit(int xoff, int yoff, int dispw, int disph);
+    void Reinit(int xoff, int yoff, int dispw, int disph, float, float);
 
     void SetCCService(const CC708Service *service)
         { cc708data = service; }
@@ -535,4 +557,5 @@
     int xoffset, yoffset, displaywidth, displayheight;
 };
 
+
 #endif
