Ticket #1681: osdimagecache-sizelimit-HEAD.diff
File osdimagecache-sizelimit-HEAD.diff, 17.2 KB (added by , 18 years ago) |
---|
-
libs/libmythtv/osdtypes.h
338 338 bool m_onlyusefirst; 339 339 bool m_dontround; 340 340 341 OSDImageCache cache; 341 static OSDImageCache cache; 342 OSDImageCacheValue* m_cacheitem; 342 343 }; 343 344 344 345 class OSDTypePosSlider : public OSDTypeImage -
libs/libmythtv/osdtypes.cpp
1100 1100 1101 1101 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1102 1102 1103 // share the OSD image cache between all OSDTypeImages by using a static 1104 // class variable 1105 OSDImageCache OSDTypeImage::cache; 1106 1103 1107 OSDTypeImage::OSDTypeImage(const QString &name, const QString &filename, 1104 1108 QPoint displaypos, float wmult, float hmult, 1105 1109 int scalew, int scaleh) … … 1117 1121 1118 1122 m_scalew = scalew; 1119 1123 m_scaleh = scaleh; 1124 m_cacheitem = NULL; 1120 1125 m_dontround = false; 1121 1126 1122 1127 LoadImage(filename, wmult, hmult, scalew, scaleh); … … 1135 1140 m_name = other.m_name; 1136 1141 m_scalew = other.m_scalew; 1137 1142 m_scaleh = other.m_scaleh; 1143 m_cacheitem = NULL; 1138 1144 m_dontround = other.m_dontround; 1139 1145 1140 1146 m_alpha = m_yuv = NULL; … … 1172 1178 m_vbuffer = NULL; 1173 1179 m_isvalid = false; 1174 1180 m_filename = ""; 1181 m_cacheitem = NULL; 1175 1182 m_dontround = false; 1176 1183 } 1177 1184 … … 1197 1204 1198 1205 OSDTypeImage::~OSDTypeImage() 1199 1206 { 1200 if (!cache.InMemCache()) 1201 { 1202 if (m_yuv) 1203 delete [] m_yuv; 1204 if (m_alpha) 1205 delete [] m_alpha; 1206 } 1207 cache.Reset(); 1207 // in case we have a cache item in hand, it's safe to delete it, as it 1208 // should not be in OSDImageCache anymore (see Take()) and it should have 1209 // been written to the file cache for faster access in the future 1210 delete m_cacheitem; 1211 m_cacheitem = NULL; 1208 1212 } 1209 1213 1210 1214 void OSDTypeImage::SetName(const QString &name) … … 1232 1236 void OSDTypeImage::LoadImage(const QString &filename, float wmult, float hmult, 1233 1237 int scalew, int scaleh) 1234 1238 { 1235 // Try to get it from the cache first 1236 QString ckey = OSDImageCache::CreateKey( 1237 filename, wmult, hmult, scalew, scaleh); 1238 OSDImageCacheValue value = cache.Load(ckey, !filename.isEmpty()); 1239 1240 if (value.IsValid()) 1239 QString ckey; 1240 1241 if (!filename.isEmpty() && filename.length() >= 2) { 1242 ckey = OSDImageCache::CreateKey( 1243 filename, wmult, hmult, scalew, scaleh); 1244 } else { 1245 // this method requires a backing file 1246 return; 1247 } 1248 1249 // take the item from the cache so it's not freed while in use 1250 OSDImageCacheValue* value = cache.Take(ckey, true); 1251 1252 if (value != NULL) 1241 1253 { 1242 m_yuv = value.m_yuv; 1243 m_ybuffer = value.m_ybuffer; 1244 m_ubuffer = value.m_ubuffer; 1245 m_vbuffer = value.m_vbuffer; 1246 m_alpha = value.m_alpha; 1247 m_imagesize = value.m_imagesize; 1248 m_isvalid = true; 1249 return; 1254 m_yuv = value->m_yuv; 1255 m_ybuffer = value->m_ybuffer; 1256 m_ubuffer = value->m_ubuffer; 1257 m_vbuffer = value->m_vbuffer; 1258 m_alpha = value->m_alpha; 1259 m_imagesize = value->m_imagesize; 1260 m_isvalid = true; 1261 // put the old image back to the cache so it can be reused in the 1262 // future, and possibly freed by the cache system if the size limit 1263 // is reached 1264 if (m_cacheitem != NULL) 1265 cache.Insert(m_cacheitem); 1266 m_cacheitem = value; 1267 return; 1250 1268 } 1251 1252 if (filename.length() < 2) 1253 return; 1254 1269 1270 // scaled image was not found in cache, have to create it 1271 1255 1272 QImage tmpimage(filename); 1256 1273 1257 1274 if (tmpimage.width() == 0) … … 1290 1307 1291 1308 m_imagesize = QRect(0, 0, imwidth, imheight); 1292 1309 1293 cache.Save(ckey, !filename.isEmpty(), 1294 OSDImageCacheValue(m_yuv, m_ybuffer, m_ubuffer, 1295 m_vbuffer, m_alpha, m_imagesize)); 1310 // put the old image back to the cache so it can be reused in the 1311 // future, and possibly freed by the cache system if the size limit 1312 // is reached 1313 if (m_cacheitem != NULL) 1314 cache.Insert(m_cacheitem); 1315 1316 m_cacheitem = new OSDImageCacheValue( 1317 ckey, 1318 m_yuv, m_ybuffer, m_ubuffer, 1319 m_vbuffer, m_alpha, m_imagesize); 1320 1321 // save the new cache item to the file cache 1322 if (!filename.isEmpty()) 1323 cache.SaveToDisk(m_cacheitem); 1296 1324 } 1297 1325 1298 1326 void OSDTypeImage::LoadFromQImage(const QImage &img) … … 1300 1328 // this method is not cached as it's used mostly for 1301 1329 // subtitles which are displayed only once anyways, caching 1302 1330 // would probably only slow things down overall 1303 if (m_isvalid && !cache.InMemCache())1331 if (m_isvalid) 1304 1332 { 1305 if (m_yuv) 1306 delete [] m_yuv; 1307 if (m_alpha) 1308 delete [] m_alpha; 1333 delete m_cacheitem; 1334 m_cacheitem = NULL; 1309 1335 1310 1336 m_isvalid = false; 1311 1337 m_yuv = NULL; … … 1587 1613 1588 1614 m_scalew = scalew; 1589 1615 m_scaleh = scaleh; 1616 m_cacheitem = NULL; 1590 1617 1591 1618 LoadImage(m_redname, wmult, hmult, scalew, scaleh); 1592 1619 if (m_isvalid) … … 1624 1651 1625 1652 m_displaypos = m_displayrect.topLeft(); 1626 1653 1627 if (!cache.InMemCache())1628 {1629 if (m_ryuv)1630 delete [] m_ryuv;1631 if (m_ralpha)1632 delete [] m_ralpha;1633 }1634 1635 1654 LoadImage(m_redname, wmult, hmult, m_scalew, m_scaleh); 1636 1655 if (m_isvalid) 1637 1656 { -
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 }