Index: libs/libmythtv/osdtypes.h
===================================================================
--- libs/libmythtv/osdtypes.h	(revision 9710)
+++ libs/libmythtv/osdtypes.h	(working copy)
@@ -274,7 +274,8 @@
     int m_drawwidth;
     bool m_onlyusefirst;
 
-    OSDImageCache cache;
+    static OSDImageCache cache;
+    OSDImageCacheValue* m_cacheitem;
 };
 
 class OSDTypePosSlider : public OSDTypeImage
Index: libs/libmythtv/osdtypes.cpp
===================================================================
--- libs/libmythtv/osdtypes.cpp	(revision 9710)
+++ libs/libmythtv/osdtypes.cpp	(working copy)
@@ -657,6 +657,10 @@
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+// share the OSD image cache between all OSDTypeImages by using a static
+// class variable
+OSDImageCache OSDTypeImage::cache;
+
 OSDTypeImage::OSDTypeImage(const QString &name, const QString &filename, 
                            QPoint displaypos, float wmult, float hmult, 
                            int scalew, int scaleh)
@@ -674,6 +678,7 @@
 
     m_scalew = scalew;
     m_scaleh = scaleh;
+    m_cacheitem = NULL;
 
     LoadImage(filename, wmult, hmult, scalew, scaleh);
 }
@@ -691,6 +696,7 @@
     m_name = other.m_name;
     m_scalew = other.m_scalew;
     m_scaleh = other.m_scaleh;
+    m_cacheitem = NULL;
 
     m_alpha = m_yuv = NULL;
     if (m_isvalid)
@@ -727,6 +733,7 @@
     m_vbuffer = NULL;
     m_isvalid = false;
     m_filename = "";
+    m_cacheitem = NULL;
 }
 
 OSDTypeImage::OSDTypeImage(void)
@@ -746,18 +753,16 @@
     m_vbuffer = NULL;
     m_isvalid = false;
     m_filename = "";
+    m_cacheitem = NULL;
 }
 
 OSDTypeImage::~OSDTypeImage()
 {
-    if (!cache.InMemCache())
-    {
-	if (m_yuv)
-	    delete [] m_yuv;
-	if (m_alpha)
-	    delete [] m_alpha;    
-    }
-    cache.Reset();
+    // in case we have a cache item in hand, it's safe to delete it, as it 
+    // should not be in OSDImageCache anymore (see Take()) and it should have 
+    // been written to the file cache for faster access in the future
+    delete m_cacheitem;
+    m_cacheitem = NULL;     
 }
 
 void OSDTypeImage::SetName(const QString &name)
@@ -785,26 +790,39 @@
 void OSDTypeImage::LoadImage(const QString &filename, float wmult, float hmult,
                              int scalew, int scaleh)
 {
-    // Try to get it from the cache first
-    QString ckey = OSDImageCache::CreateKey(
-        filename, wmult, hmult, scalew, scaleh);
-    OSDImageCacheValue value = cache.Load(ckey, !filename.isEmpty());
+    QString ckey;
+  
+    if (!filename.isEmpty() && filename.length() >= 2) {
+ 	ckey = OSDImageCache::CreateKey(
+ 	    filename, wmult, hmult, scalew, scaleh);
+    } else {
+	// this method requires a backing file
+	return;
+    }
+ 
+    // take the item from the cache so it's not freed while in use
+    OSDImageCacheValue* value = cache.Take(ckey, true);
 
-    if (value.IsValid())
+    if (value != NULL)
     {
-        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;
-        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;
+ 	// put the old image back to the cache so it can be reused in the
+ 	// future, and possibly freed by the cache system if the size limit
+ 	// is reached
+ 	if (m_cacheitem != NULL)
+ 	    cache.Insert(m_cacheitem);
+ 	m_cacheitem = value;
+	return;
     }
-
-    if (filename.length() < 2)
-        return;
-
+  
+    // scaled image was not found in cache, have to create it
+ 
     QImage tmpimage(filename);
 
     if (tmpimage.width() == 0)
@@ -843,9 +861,20 @@
 
     m_imagesize = QRect(0, 0, imwidth, imheight);
 
-    cache.Save(ckey, !filename.isEmpty(),
-               OSDImageCacheValue(m_yuv,     m_ybuffer, m_ubuffer,
-                                  m_vbuffer, m_alpha,   m_imagesize));
+    // put the old image back to the cache so it can be reused in the
+    // future, and possibly freed by the cache system if the size limit
+    // is reached
+    if (m_cacheitem != NULL)
+ 	cache.Insert(m_cacheitem);
+ 
+    m_cacheitem = new OSDImageCacheValue(
+	ckey,
+ 	m_yuv,     m_ybuffer, m_ubuffer,
+ 	m_vbuffer, m_alpha,   m_imagesize);
+
+    // save the new cache item to the file cache
+    if (!filename.isEmpty())
+ 	cache.SaveToDisk(m_cacheitem);
 }
 
 void OSDTypeImage::LoadFromQImage(const QImage &img)
@@ -853,13 +882,10 @@
     // 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 && !cache.InMemCache())
+    if (m_isvalid)
     {
-        if (m_yuv)
-            delete [] m_yuv;
-        if (m_alpha)
-            delete [] m_alpha;
-
+	delete m_cacheitem;
+	m_cacheitem = NULL;
         m_isvalid = false;
         m_yuv = NULL;
         m_alpha = NULL;
@@ -1195,14 +1221,6 @@
 
     m_displaypos = m_displayrect.topLeft();
 
-    if (!cache.InMemCache())
-    {
-        if (m_ryuv)
-            delete [] m_ryuv;
-        if (m_ralpha)
-            delete [] m_ralpha;
-    }
-
     LoadImage(m_redname, wmult, hmult, m_scalew, m_scaleh);
     if (m_isvalid)
     {
Index: libs/libmythtv/osdimagecache.h
===================================================================
--- libs/libmythtv/osdimagecache.h	(revision 9710)
+++ libs/libmythtv/osdimagecache.h	(working copy)
@@ -5,23 +5,26 @@
 #include <qrect.h>
 #include <qmutex.h>
 #include <qstring.h>
+#include <qasciicache.h>
 
+// the maximum total size of OSD images cached in *memory* 
+#define OSD_MEMCACHE_MAX_SIZE 5000000
+
+// print statistics of OSD image access in the destructor of OSDImageCache
+//#define PRINT_OSD_IMAGE_CACHE_STATS
+
 class OSDImageCacheValue
 {
   public:
-    OSDImageCacheValue(unsigned char *yuv,     unsigned char *ybuffer,
+    OSDImageCacheValue(QString cacheKey,
+		       unsigned char *yuv,     unsigned char *ybuffer,
                        unsigned char *ubuffer, unsigned char *vbuffer,
-                       unsigned char *alpha,   QRect imagesize) :
-        m_yuv(yuv),         m_ybuffer(ybuffer),
-        m_ubuffer(ubuffer), m_vbuffer(vbuffer),
-        m_alpha(alpha),     m_imagesize(imagesize) {}
+                       unsigned char *alpha,   QRect imagesize);
 
-    OSDImageCacheValue() :
-        m_yuv(NULL),     m_ybuffer(NULL),
-        m_ubuffer(NULL), m_vbuffer(NULL),
-        m_alpha(NULL),   m_imagesize(0,0,0,0) {}
+    virtual ~OSDImageCacheValue();
 
-    bool IsValid(void) const { return m_alpha; }
+    int SizeInBytes() const { return m_size_in_bytes; }
+    QString Key() const { return m_cacheKey; }
 
     unsigned char *m_yuv;
     unsigned char *m_ybuffer;
@@ -29,24 +32,27 @@
     unsigned char *m_vbuffer;
     unsigned char *m_alpha;
     QRect          m_imagesize;
+  private:
+    int            m_size_in_bytes;
+    QString        m_cacheKey;
 };
 
-typedef QMap<QString, OSDImageCacheValue> img_cache_t;
+typedef QAsciiCache<OSDImageCacheValue> img_cache_t;
 
 class OSDImageCache
 {
   public:
-    OSDImageCache() : m_cacheLock(true), m_cached(false) {}
+    OSDImageCache();
+    virtual ~OSDImageCache();
 
-    bool InMemCache(void) const { return m_cached; }
     bool InFileCache(const QString &key) const;
 
     bool Contains(const QString &key, bool useFile) const;
 
-    OSDImageCacheValue Load(const QString &key, bool useFile);
+    OSDImageCacheValue* Take(const QString &key, bool useFile);
+    void Insert(OSDImageCacheValue* value);
 
-    void Save(const QString &key, bool useFile,
-              const OSDImageCacheValue &value);
+    void SaveToDisk(const OSDImageCacheValue *value);
 
     void Reset(void);
 
@@ -59,5 +65,7 @@
   private:
     mutable QMutex m_cacheLock;
     img_cache_t    m_imageCache;
-    bool           m_cached;
+    int            m_memHits;
+    int            m_diskHits;
+    int            m_misses;
 };
Index: libs/libmythtv/osdimagecache.cpp
===================================================================
--- libs/libmythtv/osdimagecache.cpp	(revision 9710)
+++ libs/libmythtv/osdimagecache.cpp	(working copy)
@@ -1,6 +1,6 @@
 // -*- Mode: c++ -*-
 /** OSDImageCache
- *  Copyright (c) 2006 by Pekka Jaaskelainen, Daniel Thor Kristjansson
+ *  Copyright (c) 2006 by Pekka Jääskeläinen, Daniel Thor Kristjansson
  *  Distributed as part of MythTV under GPL v2 and later.
  */
 
@@ -17,20 +17,101 @@
 #include "mythcontext.h"
 #include "osdimagecache.h"
 
+#ifdef PRINT_OSD_IMAGE_CACHE_STATS
+#include <iostream>
+using std::cerr;
+using std::endl;
+#define LOG_PREFIX "OSDImageCache: "
+#endif
+
 #define LOC QString("OSDImgCache: ")
 #define LOC_ERR QString("OSDImgCache, Error: ")
 
+/**
+ * \fn OSDImageCacheValue::OSDImageCacheValue(unsigned char*, unsigned char*,
+ * unsighed char*, unsigned char*, unsighed char*, QRect)
+ *
+ * \brief The main constructor that takes the image data as arguments. The
+ * image data becomes property of the OSDImageCacheValue and will be deleted
+ * by it.
+ *
+ */
+OSDImageCacheValue::OSDImageCacheValue(
+    QString cacheKey,
+    unsigned char *yuv,     unsigned char *ybuffer,
+    unsigned char *ubuffer, unsigned char *vbuffer,
+    unsigned char *alpha,   QRect imagesize) :
+    m_yuv(yuv),         m_ybuffer(ybuffer),
+    m_ubuffer(ubuffer), m_vbuffer(vbuffer),
+    m_alpha(alpha),     m_imagesize(imagesize),
+    m_cacheKey(cacheKey) {
+
+    uint yuv_size = m_imagesize.width() * m_imagesize.height() * 3 / 2;
+    m_size_in_bytes =
+	(sizeof(OSDImageCacheValue)) + yuv_size + 
+	(m_imagesize.width() * m_imagesize.height());
+}
+
+/**
+ * \fn OSDImageCacheValue::~OSDImageCacheValue()
+ * \brief Destructor, frees the cached bitmaps.
+ *
+ */
+OSDImageCacheValue::~OSDImageCacheValue() {
+    delete [] m_yuv;
+    m_yuv = NULL;
+    delete [] m_alpha;
+    m_alpha = NULL;
+}
+
+
+/**
+ * \fn OSDImageCache::OSDImageCache()
+ * \brief Constructor, initializes the internal cache structures.
+ */
+OSDImageCache::OSDImageCache() : 
+    m_cacheLock(true), m_imageCache(OSD_MEMCACHE_MAX_SIZE, 50),
+    m_memHits(0), m_diskHits(0), m_misses(0) 
+{
+
+    // when the cache gets too large, items are automatically deleted from it
+    // in LRU order
+    m_imageCache.setAutoDelete(true);
+}
+
+/**
+ * \fn OSDImageCache::~OSDImageCache()
+ * \brief Destructor, frees all cached OSD images.
+ */
+OSDImageCache::~OSDImageCache() 
+{
+#ifdef PRINT_OSD_IMAGE_CACHE_STATS
+    int totalAccess = m_memHits + m_diskHits + m_misses;
+    if (totalAccess == 0)
+	return;
+    cout << LOG_PREFIX << " Statistics: " << std::endl
+	 << LOG_PREFIX << m_imageCache.totalCost() << " bytes in cache\n" 
+	 << LOG_PREFIX << " memory hits: " 
+	 << m_memHits << ", " << m_memHits*100.0/totalAccess << "%\n"
+	 << LOG_PREFIX << "   disk hits: " 
+	 << m_diskHits << ", " << m_diskHits*100.0/totalAccess << "%\n"
+	 << LOG_PREFIX << "      misses: " 
+	 << m_misses << ", " << m_misses*100.0/totalAccess << "%\n";
+#endif
+    Reset();
+}
+
 /** \fn OSDImageCache::Contains(const QString&,bool)
  *  \brief Returns true if 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.
+ *  \param key The key for this image.
+ *  \param useFile If true, also look from the disk cache.
  */
 bool OSDImageCache::Contains(const QString &key, bool useFile) const
 {
     QMutexLocker locker(&m_cacheLock);
 
-    if (m_imageCache.find(key) != m_imageCache.end())
+    if (m_imageCache.find(key) != NULL)
         return true;
 
     if (!useFile)
@@ -69,24 +150,29 @@
     return true;
 }
 
-/** \fn OSDImageCache::Load(const QString&,bool)
- *  \brief Returns OSD image data from cache.
+/** \fn OSDImageCache::Take(const QString&,bool)
+ *  \brief Returns OSD image data from cache and removes the image from
+ *  the cache so it won't be deleted while in use. The deletion of the
+ *  taken item becomes responsibility of the client. Returns NULL if item
+ *  with the given key is not found.
  *
  *  \param key The key for this image.
- *  \param useFile If true, also look from the disk cache.
+ *  \param useFile If true, also search the disk cache.
  */
-OSDImageCacheValue OSDImageCache::Load(const QString &key, bool useFile)
+OSDImageCacheValue* OSDImageCache::Take(const QString &key, bool useFile)
 {
     QMutexLocker locker(&m_cacheLock);
-    img_cache_t::const_iterator it = m_imageCache.find(key);
-    if (it != m_imageCache.end())
-        return *it;
+    OSDImageCacheValue* item = m_imageCache.find(key);
+    if (item != NULL) {
+	m_memHits++;
+        return m_imageCache.take(key);
+    }
 
-    OSDImageCacheValue val;
+    if (!useFile || !InFileCache(key)) {
+	m_misses++;
+        return NULL;
+    }
 
-    if (!useFile || !InFileCache(key))
-        return val;
-
     QDir dir(MythContext::GetConfDir() + "/osdcache/");
     QFile cacheFile(dir.path() + "/" + key);
     cacheFile.open(IO_ReadOnly);
@@ -103,43 +189,56 @@
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR + key + " wrong cache file size!"
                 << cacheFile.size() << " != " << tot_size);
-        return val;
+        return NULL;
     }
 
-    unsigned char *tmpA = new unsigned char[yuv_size];
-    unsigned char *tmpB = new unsigned char[imwidth * imheight];
-    stream.readRawBytes((char*)tmpA, yuv_size);
-    stream.readRawBytes((char*)tmpB, imwidth * imheight);
+    unsigned char *yuv = new unsigned char[yuv_size];
+    unsigned char *alpha = new unsigned char[imwidth * imheight];
+    stream.readRawBytes((char*)yuv, yuv_size);
+    stream.readRawBytes((char*)alpha, imwidth * imheight);
     cacheFile.close();
 
-    OSDImageCacheValue value(tmpA, tmpA,
-                             tmpA + (imwidth * imheight),
-                             tmpA + (imwidth * imheight * 5 / 4),
-                             tmpB, QRect(0, 0, imwidth, imheight));
-
-    Save(key, false, value);
-
+    OSDImageCacheValue* value = 
+	new OSDImageCacheValue(
+	    key,
+	    yuv, yuv,
+	    yuv + (imwidth * imheight),
+	    yuv + (imwidth * imheight * 5 / 4),
+	    alpha, QRect(0, 0, imwidth, imheight));
+    m_diskHits++;
     return value;
 }
 
-/** \fn OSDImageCache::Save(const QString&,bool,const OSDImageCacheValue&)
- *  \brief Saves OSD image data to cache.
+/** \fn OSDImageCache::Insert(OSDImageCacheValue*)
+ *  \brief Inserts OSD image data to memory cache. The item becomes property
+ *  of the OSDImageCache and may be deleted any time by it.
  *
- *  \param key The key for this image.
- *  \param useFile If true, also save to the disk cache.
+ *  \param value The cache item.
  */
-void OSDImageCache::Save(const QString &key, bool useFile,
-                         const OSDImageCacheValue &value)
+void OSDImageCache::Insert(OSDImageCacheValue *value)
 {
-    if (Contains(key, useFile))
-        return;
+    if (value == NULL)
+	return;
 
     m_cacheLock.lock();
-    m_imageCache[key] = value;
-    m_cached = true;
+    if (!m_imageCache.insert(value->Key(), value, value->SizeInBytes())) {
+        VERBOSE(
+	    VB_IMPORTANT, 
+	    LOC_ERR + QString("inserting image to memory cache failed"));
+    }
     m_cacheLock.unlock();
+}
 
-    if (!useFile)
+
+/** \fn OSDImageCache::SaveToDisk(const OSDImageCacheValue*)
+ *  \brief Saves OSD image data to disk cache. Item is not written to the
+ *  memory cache, i.e., it stays as property of the client.
+ *
+ *  \param value The cached OSD image to save.
+ */
+void OSDImageCache::SaveToDisk(const OSDImageCacheValue *value)
+{
+    if (InFileCache(value->Key()))
         return;
 
     QDir dir(MythContext::GetConfDir() + "/osdcache/");
@@ -149,21 +248,21 @@
         return;
     }
 
-    QFile cacheFile(dir.path() + "/" + key);
+    QFile cacheFile(dir.path() + "/" + value->Key());
     if (!cacheFile.open(IO_WriteOnly | IO_Truncate))
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR + "Creating osdcache file failed.");
         return;
     }
 
-    uint32_t imwidth  = value.m_imagesize.width();
-    uint32_t imheight = value.m_imagesize.height();
+    uint32_t imwidth  = value->m_imagesize.width();
+    uint32_t imheight = value->m_imagesize.height();
     uint     yuv_size = imwidth * imheight * 3 / 2;
 
     QDataStream stream(&cacheFile);
     stream << imwidth << imheight;   
-    stream.writeRawBytes((const char*)value.m_yuv, yuv_size);
-    stream.writeRawBytes((const char*)value.m_alpha, imwidth * imheight);
+    stream.writeRawBytes((const char*)value->m_yuv, yuv_size);
+    stream.writeRawBytes((const char*)value->m_alpha, imwidth * imheight);
     cacheFile.close();
 }
 
@@ -190,16 +289,7 @@
 
 void OSDImageCache::Reset(void)
 {
-    // cleanup the OSD image cache in memory
     QMutexLocker locker(&m_cacheLock);
-    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;
-    }
+    // this also deletes the images due to setAutoDelete(true)
     m_imageCache.clear();
-    m_cached = false;
 }
