00001
00007
00008 #include <stdint.h>
00009
00010
00011 #include <qdir.h>
00012 #include <qfile.h>
00013 #include <qfileinfo.h>
00014 #include <qdatastream.h>
00015 #include <qdeepcopy.h>
00016
00017
00018 #include "mythcontext.h"
00019 #include "osdimagecache.h"
00020
00021
00022
00023
00024 #define LOC QString("OSDImgCache: ")
00025 #define LOC_ERR QString("OSDImgCache, Error: ")
00026
00027 uint OSDImageCache::kMaximumMemoryCacheSize = 5 * 1024 * 1024;
00028
00035 OSDImageCacheValue::OSDImageCacheValue(
00036 QString cacheKey,
00037 unsigned char *yuv, unsigned char *ybuffer,
00038 unsigned char *ubuffer, unsigned char *vbuffer,
00039 unsigned char *alpha, QRect imagesize) :
00040 m_yuv(yuv), m_ybuffer(ybuffer),
00041 m_ubuffer(ubuffer), m_vbuffer(vbuffer),
00042 m_alpha(alpha), m_imagesize(imagesize),
00043 m_cacheKey(QDeepCopy<QString>(cacheKey))
00044 {
00045 uint yuv_size = m_imagesize.width() * m_imagesize.height() * 3 / 2;
00046 m_size_in_bytes =
00047 (sizeof(OSDImageCacheValue)) + yuv_size +
00048 (m_imagesize.width() * m_imagesize.height());
00049 }
00050
00054 OSDImageCacheValue::~OSDImageCacheValue()
00055 {
00056 delete [] m_yuv;
00057 m_yuv = NULL;
00058 delete [] m_alpha;
00059 m_alpha = NULL;
00060 }
00061
00065 OSDImageCache::OSDImageCache() :
00066 m_cacheLock(true), m_imageCache(kMaximumMemoryCacheSize, 50),
00067 m_memHits(0), m_diskHits(0), m_misses(0)
00068 {
00069
00070
00071 m_imageCache.setAutoDelete(true);
00072 }
00073
00077 OSDImageCache::~OSDImageCache()
00078 {
00079 #ifdef PRINT_OSD_IMAGE_CACHE_STATS
00080 int totalAccess = m_memHits + m_diskHits + m_misses;
00081 if (totalAccess == 0)
00082 return;
00083
00084 #define LOG_PREFIX "OSDImageCache: "
00085 VERBOSE(VB_IMPORTANT, LOC << " Statistics: " << endl
00086 << LOG_PREFIX << m_imageCache.totalCost() << " bytes in cache\n"
00087 << LOG_PREFIX << " memory hits: "
00088 << m_memHits << ", " << m_memHits*100.0/totalAccess << "%\n"
00089 << LOG_PREFIX << " disk hits: "
00090 << m_diskHits << ", " << m_diskHits*100.0/totalAccess << "%\n"
00091 << LOG_PREFIX << " misses: "
00092 << m_misses << ", " << m_misses*100.0/totalAccess << "%");
00093 #undef LOC_PREFIX
00094 #endif
00095 Reset();
00096 }
00097
00104 bool OSDImageCache::Contains(const QString &key, bool useFile) const
00105 {
00106 QMutexLocker locker(&m_cacheLock);
00107
00108 if (m_imageCache.find(key) != NULL)
00109 return true;
00110
00111 if (!useFile)
00112 return false;
00113
00114 return InFileCache(key);
00115 }
00116
00117 bool OSDImageCache::InFileCache(const QString &key) const
00118 {
00119
00120 QDir dir(MythContext::GetConfDir() + "/osdcache/");
00121 QFileInfo cFile(dir.path() + "/" + key);
00122 if (!cFile.exists() || !cFile.isReadable())
00123 return false;
00124
00125
00126 QString orig = ExtractOriginal(key);
00127 if (orig.isEmpty())
00128 return false;
00129
00130 QFileInfo oFile(orig);
00131 if (!oFile.exists())
00132 {
00133 VERBOSE(VB_IMPORTANT, LOC + QString("Can't find '%1'").arg(orig));
00134 return false;
00135 }
00136
00137
00138 if (cFile.lastModified() < oFile.lastModified())
00139 {
00140 cFile.dir().remove(cFile.baseName(true));
00141 return false;
00142 }
00143
00144 return true;
00145 }
00146
00157 OSDImageCacheValue *OSDImageCache::Get(const QString &key, bool useFile)
00158 {
00159 QMutexLocker locker(&m_cacheLock);
00160 OSDImageCacheValue* item = m_imageCache.find(key);
00161 if (item)
00162 {
00163 m_memHits++;
00164 return m_imageCache.take(key);
00165 }
00166
00167 if (!useFile || !InFileCache(key))
00168 {
00169 m_misses++;
00170 return NULL;
00171 }
00172
00173 QDir dir(MythContext::GetConfDir() + "/osdcache/");
00174 QFile cacheFile(dir.path() + "/" + key);
00175 cacheFile.open(IO_ReadOnly);
00176 uint32_t imwidth = 0;
00177 uint32_t imheight = 0;
00178
00179 QDataStream stream(&cacheFile);
00180 stream >> imwidth >> imheight;
00181
00182 uint yuv_size = imwidth * imheight * 3 / 2;
00183 uint tot_size = (sizeof(imwidth) * 2) + yuv_size + (imwidth * imheight);
00184
00185 if (cacheFile.size() != tot_size)
00186 {
00187 VERBOSE(VB_IMPORTANT, LOC_ERR + key + " wrong cache file size!"
00188 << cacheFile.size() << " != " << tot_size);
00189 return NULL;
00190 }
00191
00192 unsigned char *yuv = new unsigned char[yuv_size];
00193 unsigned char *alpha = new unsigned char[imwidth * imheight];
00194 stream.readRawBytes((char*)yuv, yuv_size);
00195 stream.readRawBytes((char*)alpha, imwidth * imheight);
00196 cacheFile.close();
00197
00198 OSDImageCacheValue* value =
00199 new OSDImageCacheValue(
00200 key,
00201 yuv, yuv,
00202 yuv + (imwidth * imheight),
00203 yuv + (imwidth * imheight * 5 / 4),
00204 alpha, QRect(0, 0, imwidth, imheight));
00205
00206 m_diskHits++;
00207 return value;
00208 }
00209
00218 void OSDImageCache::Insert(OSDImageCacheValue *value)
00219 {
00220 if (!value)
00221 return;
00222
00223 QMutexLocker locker(&m_cacheLock);
00224 if (!m_imageCache.insert(value->GetKey(), value, value->GetSize()))
00225 {
00226 VERBOSE(VB_IMPORTANT,
00227 LOC_ERR + QString("inserting image to memory cache failed"));
00228 }
00229 }
00230
00231
00240 void OSDImageCache::SaveToDisk(const OSDImageCacheValue *value)
00241 {
00242 if (InFileCache(value->GetKey()))
00243 return;
00244
00245 QDir dir(MythContext::GetConfDir() + "/osdcache/");
00246 if (!dir.exists() && !dir.mkdir(dir.path()))
00247 {
00248 VERBOSE(VB_IMPORTANT, LOC_ERR + "Creating osdcache directory failed.");
00249 return;
00250 }
00251
00252 QFile cacheFile(dir.path() + "/" + value->GetKey());
00253 if (!cacheFile.open(IO_WriteOnly | IO_Truncate))
00254 {
00255 VERBOSE(VB_IMPORTANT, LOC_ERR + "Creating osdcache file failed.");
00256 return;
00257 }
00258
00259 uint32_t imwidth = value->m_imagesize.width();
00260 uint32_t imheight = value->m_imagesize.height();
00261 uint yuv_size = imwidth * imheight * 3 / 2;
00262
00263 QDataStream stream(&cacheFile);
00264 stream << imwidth << imheight;
00265 stream.writeRawBytes((const char*)value->m_yuv, yuv_size);
00266 stream.writeRawBytes((const char*)value->m_alpha, imwidth * imheight);
00267 cacheFile.close();
00268 }
00269
00275 QString OSDImageCache::CreateKey(const QString &filename, float wmult,
00276 float hmult, int scalew, int scaleh)
00277 {
00278 QString tmp = filename;
00279 return QString("cache_%1@%2_%3_%4_%5").arg(tmp.replace(QChar('/'), "+"))
00280 .arg(wmult).arg(hmult).arg(scalew).arg(scaleh);
00281 }
00282
00283 QString OSDImageCache::ExtractOriginal(const QString &key)
00284 {
00285 QString tmp0 = key.mid(6);
00286 QString tmp1 = tmp0.left(tmp0.find("@"));
00287 QString tmp2 = tmp1.replace(QChar('+'), "/");
00288 return tmp2;
00289 }
00290
00291 void OSDImageCache::Reset(void)
00292 {
00293 QMutexLocker locker(&m_cacheLock);
00294
00295 m_imageCache.clear();
00296 }