Ticket #1681: osdimagecache-sizelimit-0.19-fixes.diff
File osdimagecache-sizelimit-0.19-fixes.diff, 17.1 KB (added by , 18 years ago) |
---|
-
libs/libmythtv/osdtypes.h
274 274 int m_drawwidth; 275 275 bool m_onlyusefirst; 276 276 277 OSDImageCache cache; 277 static OSDImageCache cache; 278 OSDImageCacheValue* m_cacheitem; 278 279 }; 279 280 280 281 class OSDTypePosSlider : public OSDTypeImage -
libs/libmythtv/osdtypes.cpp
657 657 658 658 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 659 659 660 // share the OSD image cache between all OSDTypeImages by using a static 661 // class variable 662 OSDImageCache OSDTypeImage::cache; 663 660 664 OSDTypeImage::OSDTypeImage(const QString &name, const QString &filename, 661 665 QPoint displaypos, float wmult, float hmult, 662 666 int scalew, int scaleh) … … 674 678 675 679 m_scalew = scalew; 676 680 m_scaleh = scaleh; 681 m_cacheitem = NULL; 677 682 678 683 LoadImage(filename, wmult, hmult, scalew, scaleh); 679 684 } … … 691 696 m_name = other.m_name; 692 697 m_scalew = other.m_scalew; 693 698 m_scaleh = other.m_scaleh; 699 m_cacheitem = NULL; 694 700 695 701 m_alpha = m_yuv = NULL; 696 702 if (m_isvalid) … … 727 733 m_vbuffer = NULL; 728 734 m_isvalid = false; 729 735 m_filename = ""; 736 m_cacheitem = NULL; 730 737 } 731 738 732 739 OSDTypeImage::OSDTypeImage(void) … … 746 753 m_vbuffer = NULL; 747 754 m_isvalid = false; 748 755 m_filename = ""; 756 m_cacheitem = NULL; 749 757 } 750 758 751 759 OSDTypeImage::~OSDTypeImage() 752 760 { 753 if (!cache.InMemCache()) 754 { 755 if (m_yuv) 756 delete [] m_yuv; 757 if (m_alpha) 758 delete [] m_alpha; 759 } 760 cache.Reset(); 761 // in case we have a cache item in hand, it's safe to delete it, as it 762 // should not be in OSDImageCache anymore (see Take()) and it should have 763 // been written to the file cache for faster access in the future 764 delete m_cacheitem; 765 m_cacheitem = NULL; 761 766 } 762 767 763 768 void OSDTypeImage::SetName(const QString &name) … … 785 790 void OSDTypeImage::LoadImage(const QString &filename, float wmult, float hmult, 786 791 int scalew, int scaleh) 787 792 { 788 // Try to get it from the cache first 789 QString ckey = OSDImageCache::CreateKey( 790 filename, wmult, hmult, scalew, scaleh); 791 OSDImageCacheValue value = cache.Load(ckey, !filename.isEmpty()); 793 QString ckey; 794 795 if (!filename.isEmpty() && filename.length() >= 2) { 796 ckey = OSDImageCache::CreateKey( 797 filename, wmult, hmult, scalew, scaleh); 798 } else { 799 // this method requires a backing file 800 return; 801 } 802 803 // take the item from the cache so it's not freed while in use 804 OSDImageCacheValue* value = cache.Take(ckey, true); 792 805 793 if (value .IsValid())806 if (value != NULL) 794 807 { 795 m_yuv = value.m_yuv; 796 m_ybuffer = value.m_ybuffer; 797 m_ubuffer = value.m_ubuffer; 798 m_vbuffer = value.m_vbuffer; 799 m_alpha = value.m_alpha; 800 m_imagesize = value.m_imagesize; 801 m_isvalid = true; 802 return; 808 m_yuv = value->m_yuv; 809 m_ybuffer = value->m_ybuffer; 810 m_ubuffer = value->m_ubuffer; 811 m_vbuffer = value->m_vbuffer; 812 m_alpha = value->m_alpha; 813 m_imagesize = value->m_imagesize; 814 m_isvalid = true; 815 // put the old image back to the cache so it can be reused in the 816 // future, and possibly freed by the cache system if the size limit 817 // is reached 818 if (m_cacheitem != NULL) 819 cache.Insert(m_cacheitem); 820 m_cacheitem = value; 821 return; 803 822 } 804 805 if (filename.length() < 2) 806 return; 807 823 824 // scaled image was not found in cache, have to create it 825 808 826 QImage tmpimage(filename); 809 827 810 828 if (tmpimage.width() == 0) … … 843 861 844 862 m_imagesize = QRect(0, 0, imwidth, imheight); 845 863 846 cache.Save(ckey, !filename.isEmpty(), 847 OSDImageCacheValue(m_yuv, m_ybuffer, m_ubuffer, 848 m_vbuffer, m_alpha, m_imagesize)); 864 // put the old image back to the cache so it can be reused in the 865 // future, and possibly freed by the cache system if the size limit 866 // is reached 867 if (m_cacheitem != NULL) 868 cache.Insert(m_cacheitem); 869 870 m_cacheitem = new OSDImageCacheValue( 871 ckey, 872 m_yuv, m_ybuffer, m_ubuffer, 873 m_vbuffer, m_alpha, m_imagesize); 874 875 // save the new cache item to the file cache 876 if (!filename.isEmpty()) 877 cache.SaveToDisk(m_cacheitem); 849 878 } 850 879 851 880 void OSDTypeImage::LoadFromQImage(const QImage &img) … … 853 882 // this method is not cached as it's used mostly for 854 883 // subtitles which are displayed only once anyways, caching 855 884 // would probably only slow things down overall 856 if (m_isvalid && !cache.InMemCache())885 if (m_isvalid) 857 886 { 858 if (m_yuv) 859 delete [] m_yuv; 860 if (m_alpha) 861 delete [] m_alpha; 862 887 delete m_cacheitem; 888 m_cacheitem = NULL; 863 889 m_isvalid = false; 864 890 m_yuv = NULL; 865 891 m_alpha = NULL; … … 1195 1221 1196 1222 m_displaypos = m_displayrect.topLeft(); 1197 1223 1198 if (!cache.InMemCache())1199 {1200 if (m_ryuv)1201 delete [] m_ryuv;1202 if (m_ralpha)1203 delete [] m_ralpha;1204 }1205 1206 1224 LoadImage(m_redname, wmult, hmult, m_scalew, m_scaleh); 1207 1225 if (m_isvalid) 1208 1226 { -
libs/libmythtv/osdimagecache.h
5 5 #include <qrect.h> 6 6 #include <qmutex.h> 7 7 #include <qstring.h> 8 #include <qasciicache.h> 8 9 10 // the maximum total size of OSD images cached in *memory* 11 #define OSD_MEMCACHE_MAX_SIZE 5000000 12 13 // print statistics of OSD image access in the destructor of OSDImageCache 14 //#define PRINT_OSD_IMAGE_CACHE_STATS 15 9 16 class OSDImageCacheValue 10 17 { 11 18 public: 12 OSDImageCacheValue(unsigned char *yuv, unsigned char *ybuffer, 19 OSDImageCacheValue(QString cacheKey, 20 unsigned char *yuv, unsigned char *ybuffer, 13 21 unsigned char *ubuffer, unsigned char *vbuffer, 14 unsigned char *alpha, QRect imagesize) : 15 m_yuv(yuv), m_ybuffer(ybuffer), 16 m_ubuffer(ubuffer), m_vbuffer(vbuffer), 17 m_alpha(alpha), m_imagesize(imagesize) {} 22 unsigned char *alpha, QRect imagesize); 18 23 19 OSDImageCacheValue() : 20 m_yuv(NULL), m_ybuffer(NULL), 21 m_ubuffer(NULL), m_vbuffer(NULL), 22 m_alpha(NULL), m_imagesize(0,0,0,0) {} 24 virtual ~OSDImageCacheValue(); 23 25 24 bool IsValid(void) const { return m_alpha; } 26 int SizeInBytes() const { return m_size_in_bytes; } 27 QString Key() const { return m_cacheKey; } 25 28 26 29 unsigned char *m_yuv; 27 30 unsigned char *m_ybuffer; … … 29 32 unsigned char *m_vbuffer; 30 33 unsigned char *m_alpha; 31 34 QRect m_imagesize; 35 private: 36 int m_size_in_bytes; 37 QString m_cacheKey; 32 38 }; 33 39 34 typedef Q Map<QString,OSDImageCacheValue> img_cache_t;40 typedef QAsciiCache<OSDImageCacheValue> img_cache_t; 35 41 36 42 class OSDImageCache 37 43 { 38 44 public: 39 OSDImageCache() : m_cacheLock(true), m_cached(false) {} 45 OSDImageCache(); 46 virtual ~OSDImageCache(); 40 47 41 bool InMemCache(void) const { return m_cached; }42 48 bool InFileCache(const QString &key) const; 43 49 44 50 bool Contains(const QString &key, bool useFile) const; 45 51 46 OSDImageCacheValue Load(const QString &key, bool useFile); 52 OSDImageCacheValue* Take(const QString &key, bool useFile); 53 void Insert(OSDImageCacheValue* value); 47 54 48 void Save(const QString &key, bool useFile, 49 const OSDImageCacheValue &value); 55 void SaveToDisk(const OSDImageCacheValue *value); 50 56 51 57 void Reset(void); 52 58 … … 59 65 private: 60 66 mutable QMutex m_cacheLock; 61 67 img_cache_t m_imageCache; 62 bool m_cached; 68 int m_memHits; 69 int m_diskHits; 70 int m_misses; 63 71 }; -
libs/libmythtv/osdimagecache.cpp
1 1 // -*- Mode: c++ -*- 2 2 /** OSDImageCache 3 * Copyright (c) 2006 by Pekka J aaskelainen, Daniel Thor Kristjansson3 * Copyright (c) 2006 by Pekka Jääskeläinen, Daniel Thor Kristjansson 4 4 * Distributed as part of MythTV under GPL v2 and later. 5 5 */ 6 6 … … 17 17 #include "mythcontext.h" 18 18 #include "osdimagecache.h" 19 19 20 #ifdef PRINT_OSD_IMAGE_CACHE_STATS 21 #include <iostream> 22 using std::cerr; 23 using std::endl; 24 #define LOG_PREFIX "OSDImageCache: " 25 #endif 26 20 27 #define LOC QString("OSDImgCache: ") 21 28 #define LOC_ERR QString("OSDImgCache, Error: ") 22 29 30 /** 31 * \fn OSDImageCacheValue::OSDImageCacheValue(unsigned char*, unsigned char*, 32 * unsighed char*, unsigned char*, unsighed char*, QRect) 33 * 34 * \brief The main constructor that takes the image data as arguments. The 35 * image data becomes property of the OSDImageCacheValue and will be deleted 36 * by it. 37 * 38 */ 39 OSDImageCacheValue::OSDImageCacheValue( 40 QString cacheKey, 41 unsigned char *yuv, unsigned char *ybuffer, 42 unsigned char *ubuffer, unsigned char *vbuffer, 43 unsigned char *alpha, QRect imagesize) : 44 m_yuv(yuv), m_ybuffer(ybuffer), 45 m_ubuffer(ubuffer), m_vbuffer(vbuffer), 46 m_alpha(alpha), m_imagesize(imagesize), 47 m_cacheKey(cacheKey) { 48 49 uint yuv_size = m_imagesize.width() * m_imagesize.height() * 3 / 2; 50 m_size_in_bytes = 51 (sizeof(OSDImageCacheValue)) + yuv_size + 52 (m_imagesize.width() * m_imagesize.height()); 53 } 54 55 /** 56 * \fn OSDImageCacheValue::~OSDImageCacheValue() 57 * \brief Destructor, frees the cached bitmaps. 58 * 59 */ 60 OSDImageCacheValue::~OSDImageCacheValue() { 61 delete [] m_yuv; 62 m_yuv = NULL; 63 delete [] m_alpha; 64 m_alpha = NULL; 65 } 66 67 68 /** 69 * \fn OSDImageCache::OSDImageCache() 70 * \brief Constructor, initializes the internal cache structures. 71 */ 72 OSDImageCache::OSDImageCache() : 73 m_cacheLock(true), m_imageCache(OSD_MEMCACHE_MAX_SIZE, 50), 74 m_memHits(0), m_diskHits(0), m_misses(0) 75 { 76 77 // when the cache gets too large, items are automatically deleted from it 78 // in LRU order 79 m_imageCache.setAutoDelete(true); 80 } 81 82 /** 83 * \fn OSDImageCache::~OSDImageCache() 84 * \brief Destructor, frees all cached OSD images. 85 */ 86 OSDImageCache::~OSDImageCache() 87 { 88 #ifdef PRINT_OSD_IMAGE_CACHE_STATS 89 int totalAccess = m_memHits + m_diskHits + m_misses; 90 if (totalAccess == 0) 91 return; 92 cout << LOG_PREFIX << " Statistics: " << std::endl 93 << LOG_PREFIX << m_imageCache.totalCost() << " bytes in cache\n" 94 << LOG_PREFIX << " memory hits: " 95 << m_memHits << ", " << m_memHits*100.0/totalAccess << "%\n" 96 << LOG_PREFIX << " disk hits: " 97 << m_diskHits << ", " << m_diskHits*100.0/totalAccess << "%\n" 98 << LOG_PREFIX << " misses: " 99 << m_misses << ", " << m_misses*100.0/totalAccess << "%\n"; 100 #endif 101 Reset(); 102 } 103 23 104 /** \fn OSDImageCache::Contains(const QString&,bool) 24 105 * \brief Returns true if cached OSD image was found in the cache. 25 106 * 26 * \param imageKey The key for this image.27 * \param use DiskCache If true, also look from the disk cache.107 * \param key The key for this image. 108 * \param useFile If true, also look from the disk cache. 28 109 */ 29 110 bool OSDImageCache::Contains(const QString &key, bool useFile) const 30 111 { 31 112 QMutexLocker locker(&m_cacheLock); 32 113 33 if (m_imageCache.find(key) != m_imageCache.end())114 if (m_imageCache.find(key) != NULL) 34 115 return true; 35 116 36 117 if (!useFile) … … 69 150 return true; 70 151 } 71 152 72 /** \fn OSDImageCache::Load(const QString&,bool) 73 * \brief Returns OSD image data from cache. 153 /** \fn OSDImageCache::Take(const QString&,bool) 154 * \brief Returns OSD image data from cache and removes the image from 155 * the cache so it won't be deleted while in use. The deletion of the 156 * taken item becomes responsibility of the client. Returns NULL if item 157 * with the given key is not found. 74 158 * 75 159 * \param key The key for this image. 76 * \param useFile If true, also look fromthe disk cache.160 * \param useFile If true, also search the disk cache. 77 161 */ 78 OSDImageCacheValue OSDImageCache::Load(const QString &key, bool useFile)162 OSDImageCacheValue* OSDImageCache::Take(const QString &key, bool useFile) 79 163 { 80 164 QMutexLocker locker(&m_cacheLock); 81 img_cache_t::const_iterator it = m_imageCache.find(key); 82 if (it != m_imageCache.end()) 83 return *it; 165 OSDImageCacheValue* item = m_imageCache.find(key); 166 if (item != NULL) { 167 m_memHits++; 168 return m_imageCache.take(key); 169 } 84 170 85 OSDImageCacheValue val; 171 if (!useFile || !InFileCache(key)) { 172 m_misses++; 173 return NULL; 174 } 86 175 87 if (!useFile || !InFileCache(key))88 return val;89 90 176 QDir dir(MythContext::GetConfDir() + "/osdcache/"); 91 177 QFile cacheFile(dir.path() + "/" + key); 92 178 cacheFile.open(IO_ReadOnly); … … 103 189 { 104 190 VERBOSE(VB_IMPORTANT, LOC_ERR + key + " wrong cache file size!" 105 191 << cacheFile.size() << " != " << tot_size); 106 return val;192 return NULL; 107 193 } 108 194 109 unsigned char * tmpA= new unsigned char[yuv_size];110 unsigned char * tmpB= new unsigned char[imwidth * imheight];111 stream.readRawBytes((char*) tmpA, yuv_size);112 stream.readRawBytes((char*) tmpB, imwidth * imheight);195 unsigned char *yuv = new unsigned char[yuv_size]; 196 unsigned char *alpha = new unsigned char[imwidth * imheight]; 197 stream.readRawBytes((char*)yuv, yuv_size); 198 stream.readRawBytes((char*)alpha, imwidth * imheight); 113 199 cacheFile.close(); 114 200 115 OSDImageCacheValue value(tmpA, tmpA, 116 tmpA + (imwidth * imheight), 117 tmpA + (imwidth * imheight * 5 / 4), 118 tmpB, QRect(0, 0, imwidth, imheight)); 119 120 Save(key, false, value); 121 201 OSDImageCacheValue* value = 202 new OSDImageCacheValue( 203 key, 204 yuv, yuv, 205 yuv + (imwidth * imheight), 206 yuv + (imwidth * imheight * 5 / 4), 207 alpha, QRect(0, 0, imwidth, imheight)); 208 m_diskHits++; 122 209 return value; 123 210 } 124 211 125 /** \fn OSDImageCache::Save(const QString&,bool,const OSDImageCacheValue&) 126 * \brief Saves OSD image data to cache. 212 /** \fn OSDImageCache::Insert(OSDImageCacheValue*) 213 * \brief Inserts OSD image data to memory cache. The item becomes property 214 * of the OSDImageCache and may be deleted any time by it. 127 215 * 128 * \param key The key for this image. 129 * \param useFile If true, also save to the disk cache. 216 * \param value The cache item. 130 217 */ 131 void OSDImageCache::Save(const QString &key, bool useFile, 132 const OSDImageCacheValue &value) 218 void OSDImageCache::Insert(OSDImageCacheValue *value) 133 219 { 134 if ( Contains(key, useFile))135 220 if (value == NULL) 221 return; 136 222 137 223 m_cacheLock.lock(); 138 m_imageCache[key] = value; 139 m_cached = true; 224 if (!m_imageCache.insert(value->Key(), value, value->SizeInBytes())) { 225 VERBOSE( 226 VB_IMPORTANT, 227 LOC_ERR + QString("inserting image to memory cache failed")); 228 } 140 229 m_cacheLock.unlock(); 230 } 141 231 142 if (!useFile) 232 233 /** \fn OSDImageCache::SaveToDisk(const OSDImageCacheValue*) 234 * \brief Saves OSD image data to disk cache. Item is not written to the 235 * memory cache, i.e., it stays as property of the client. 236 * 237 * \param value The cached OSD image to save. 238 */ 239 void OSDImageCache::SaveToDisk(const OSDImageCacheValue *value) 240 { 241 if (InFileCache(value->Key())) 143 242 return; 144 243 145 244 QDir dir(MythContext::GetConfDir() + "/osdcache/"); … … 149 248 return; 150 249 } 151 250 152 QFile cacheFile(dir.path() + "/" + key);251 QFile cacheFile(dir.path() + "/" + value->Key()); 153 252 if (!cacheFile.open(IO_WriteOnly | IO_Truncate)) 154 253 { 155 254 VERBOSE(VB_IMPORTANT, LOC_ERR + "Creating osdcache file failed."); 156 255 return; 157 256 } 158 257 159 uint32_t imwidth = value .m_imagesize.width();160 uint32_t imheight = value .m_imagesize.height();258 uint32_t imwidth = value->m_imagesize.width(); 259 uint32_t imheight = value->m_imagesize.height(); 161 260 uint yuv_size = imwidth * imheight * 3 / 2; 162 261 163 262 QDataStream stream(&cacheFile); 164 263 stream << imwidth << imheight; 165 stream.writeRawBytes((const char*)value .m_yuv, yuv_size);166 stream.writeRawBytes((const char*)value .m_alpha, imwidth * imheight);264 stream.writeRawBytes((const char*)value->m_yuv, yuv_size); 265 stream.writeRawBytes((const char*)value->m_alpha, imwidth * imheight); 167 266 cacheFile.close(); 168 267 } 169 268 … … 190 289 191 290 void OSDImageCache::Reset(void) 192 291 { 193 // cleanup the OSD image cache in memory194 292 QMutexLocker locker(&m_cacheLock); 195 QMapIterator<QString, OSDImageCacheValue> i = m_imageCache.begin(); 196 while (i != m_imageCache.end()) 197 { 198 OSDImageCacheValue& value = i.data(); 199 delete [] value.m_yuv; 200 delete [] value.m_alpha; 201 ++i; 202 } 293 // this also deletes the images due to setAutoDelete(true) 203 294 m_imageCache.clear(); 204 m_cached = false;205 295 }