Ticket #1488: osdimage-caching-0.19-v1.diff

File osdimage-caching-0.19-v1.diff, 9.8 KB (added by visit0r, 18 years ago)

the patch against the 0.19-fixes branch

  • libs/libmythtv/osdtypes.h

     
    88#include <vector>
    99#include <qobject.h>
    1010#include <qregexp.h>
     11#include <qmutex.h>
    1112
    1213using namespace std;
    1314
     
    137138
    138139    QString Name() { return m_name; }
    139140
     141    virtual void Reinit(int xoff, int yoff, int dispw, int disph,
     142                        float wmult, float hmult);
     143
    140144    virtual void Reinit(float wmult, float hmult) = 0;
    141145
    142146    virtual void Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
     
    260264    QString m_filename;
    261265
    262266    bool m_isvalid;
     267   
     268    struct OSDImageCacheValue {
     269        unsigned char *m_yuv;
     270        unsigned char *m_ybuffer;
     271        unsigned char *m_ubuffer;
     272        unsigned char *m_vbuffer;
     273        unsigned char *m_alpha;
     274        QRect m_imagesize;
     275    };
    263276
     277    QMap<QString, OSDImageCacheValue> m_imageCache;
     278    QMutex m_cacheLock;
     279
     280    QString generateCacheKey(const QString &filename, float wmult, float hmult,
     281                             int scalew, int scaleh);
     282    bool isCached(QString imageKey, bool useDiskCache);
     283    void loadFromCache(QString imageKey, bool useDiskCache);
     284    void saveToCache(QString imageKey, bool useDiskCache);
     285
    264286    unsigned char *m_yuv;
    265287    unsigned char *m_ybuffer;
    266288    unsigned char *m_ubuffer;
     
    272294
    273295    int m_drawwidth;
    274296    bool m_onlyusefirst;
     297    bool m_cached;
    275298};
    276299
    277300class OSDTypePosSlider : public OSDTypeImage
     
    483506    int xoffset, yoffset, displaywidth, displayheight;
    484507};
    485508
     509
    486510#endif
  • libs/libmythtv/osdtypes.cpp

     
    22#include <qmap.h>
    33#include <qregexp.h>
    44#include <math.h>
     5#include <qstring.h>
     6#include <qfile.h>
     7#include <qdatastream.h>
     8#include <qdir.h>
    59
    610#include <iostream>
    711using namespace std;
     
    382386
    383387//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    384388
     389void
     390OSDType::Reinit(int, int, int, int, float wmult, float hmult)
     391{
     392// The default implementation delegates the call to the Reinit(wmult, hmult)
     393// method.
     394// This allows cleaner dynamically bound call in OSDSet::Reinit() without
     395// the ugly (and slow!) dynamic_cast.
     396    Reinit(wmult, hmult);
     397}
     398
    385399OSDType::OSDType(const QString &name)
    386400{
    387401    m_hidden = false;
     
    674688
    675689    m_scalew = scalew;
    676690    m_scaleh = scaleh;
     691    m_cached = false;
    677692
    678693    LoadImage(filename, wmult, hmult, scalew, scaleh);
    679694}
     
    750765
    751766OSDTypeImage::~OSDTypeImage()
    752767{
    753     if (m_yuv)
    754         delete [] m_yuv;
    755     if (m_alpha)
    756         delete [] m_alpha;
     768    // cleanup the OSD image cache in memory
     769    m_cacheLock.lock();
     770    QMapIterator<QString, OSDImageCacheValue> i = m_imageCache.begin();
     771    while (i != m_imageCache.end()) {
     772        OSDImageCacheValue& value = i.data();
     773        delete [] value.m_yuv;
     774        delete [] value.m_alpha;
     775        ++i;
     776    }
     777    m_imageCache.clear();
     778    m_cacheLock.unlock();
    757779}
    758780
    759781void OSDTypeImage::SetName(const QString &name)
     
    778800    LoadImage(m_filename, wmult, hmult, m_scalew, m_scaleh);
    779801}
    780802
     803#include <iostream>
     804
     805/**
     806 * Returns true in case cached OSD image was found in the cache.
     807 *
     808 * @param imageKey The key for this image.
     809 * @param useDiskCache If true, also look from the disk cache.
     810 */
     811bool OSDTypeImage::isCached(QString imageKey, bool useDiskCache) {
     812
     813    QMutexLocker locker(&m_cacheLock);
     814
     815    if (m_imageCache.find(imageKey) != m_imageCache.end()) {
     816        return true;
     817    }
     818
     819    if (!useDiskCache)
     820        return false;
     821
     822    QDir dir(MythContext::GetConfDir() + "/osdcache/");
     823
     824    QFile cacheFile(dir.path() + "/" + imageKey);
     825    if (cacheFile.exists()) {
     826        return true;
     827    }
     828    return false;
     829}
     830
     831/**
     832 * Loads OSD image data from cache.
     833 *
     834 * @param imageKey The key for this image.
     835 * @param useDiskCache If true, also look from the disk cache.
     836 */
     837void OSDTypeImage::loadFromCache(QString imageKey, bool useDiskCache) {
     838
     839    OSDImageCacheValue value;
     840
     841    QMutexLocker locker(&m_cacheLock);
     842
     843    if (m_imageCache.find(imageKey) != m_imageCache.end()) {
     844        // the image was found in the memory cache
     845        value = m_imageCache[imageKey];
     846    } else if (useDiskCache) {
     847
     848        QDir dir(MythContext::GetConfDir() + "/osdcache/");
     849
     850        QFile cacheFile(dir.path() + "/" + imageKey);
     851        if (!cacheFile.exists()) {
     852            return;
     853        }
     854
     855        cacheFile.open(IO_ReadOnly);
     856        QDataStream stream(&cacheFile);
     857        Q_INT32 imwidth = 0, imheight = 0;
     858        stream >> imwidth >> imheight;   
     859       
     860        int yuv_size = imwidth * imheight * 3 / 2;
     861        value.m_yuv = new unsigned char[yuv_size];
     862        value.m_ybuffer = value.m_yuv;
     863        value.m_ubuffer = value.m_yuv + (imwidth * imheight);
     864        value.m_vbuffer = value.m_yuv + (imwidth * imheight * 5 / 4);
     865
     866        unsigned expectedFileSize =
     867            2*sizeof(Q_INT32) + yuv_size + imwidth*imheight;
     868        if (cacheFile.size() != expectedFileSize) {
     869            VERBOSE(VB_IMPORTANT, imageKey + " wrong cache file size!");
     870            std::cout << "LOG: "
     871                      << cacheFile.size() << " != "
     872                      << expectedFileSize << std::endl;
     873            return;
     874        }
     875
     876        stream.readRawBytes((char*)value.m_yuv, yuv_size);
     877
     878        value.m_alpha = new unsigned char[imwidth * imheight];
     879
     880        stream.readRawBytes((char*)value.m_alpha, imwidth * imheight);
     881
     882        value.m_imagesize = QRect(0, 0, imwidth, imheight);
     883        m_imageCache[imageKey] = value;
     884        cacheFile.close();
     885        // the image was found and loaded from disk cache
     886    } else {
     887        // image was not found in neither of the caches
     888        return;
     889    }
     890    m_yuv = value.m_yuv;
     891    m_ybuffer = value.m_ybuffer;
     892    m_ubuffer = value.m_ubuffer;
     893    m_vbuffer = value.m_vbuffer;
     894    m_alpha = value.m_alpha;
     895    m_imagesize = value.m_imagesize;
     896    m_isvalid = true;
     897}
     898
     899/**
     900 * Saves the current OSD image data from cache.
     901 *
     902 * @param imageKey The key for this image.
     903 * @param useDiskCache If true, also save to the disk cache.
     904 */
     905void OSDTypeImage::saveToCache(QString imageKey, bool useDiskCache) {
     906
     907    if (isCached(imageKey, useDiskCache))
     908        return;
     909
     910    OSDImageCacheValue value;
     911
     912    value.m_yuv = m_yuv;
     913    value.m_ybuffer = m_ybuffer;
     914    value.m_ubuffer = m_ubuffer;
     915    value.m_vbuffer = m_vbuffer;
     916    value.m_alpha = m_alpha;
     917    value.m_imagesize = m_imagesize;
     918
     919    m_cacheLock.lock();
     920    m_imageCache[imageKey] = value;
     921    m_cacheLock.unlock();
     922
     923    if (!useDiskCache)
     924        return;
     925
     926    QDir dir(MythContext::GetConfDir() + "/osdcache/");
     927
     928    if (!dir.exists()) {
     929        if (!dir.mkdir(dir.path())) {
     930            VERBOSE(VB_IMPORTANT, "Creating osdcache directory failed.");
     931            return;
     932        }
     933    }
     934
     935    QFile cacheFile(dir.path() + "/" + imageKey);
     936
     937    if (!cacheFile.open(IO_WriteOnly | IO_Truncate)) {
     938        VERBOSE(VB_IMPORTANT, "Creating osdcache file failed.");
     939        return;
     940    }
     941    QDataStream stream(&cacheFile);
     942    Q_INT32 imwidth = m_imagesize.width(), imheight = m_imagesize.height();
     943    stream << imwidth << imheight;   
     944
     945    int yuv_size = imwidth * imheight * 3 / 2;
     946
     947    stream.writeRawBytes((const char*)m_yuv, yuv_size);
     948    stream.writeRawBytes((const char*)m_alpha, imwidth * imheight);
     949    // saved the image to disk cache
     950    cacheFile.close();
     951}
     952
     953/**
     954 * Generates a cache key from the given OSD image parameters.
     955 *
     956 * The returned key is a string that can be safely used as a file name.
     957 */
     958QString OSDTypeImage::generateCacheKey(const QString &filename, float wmult,
     959                                       float hmult, int scalew, int scaleh) {
     960   
     961    QString cacheKey =
     962        QString("%1_%2_%3_%4_%5")
     963        .arg(filename).arg(wmult).arg(hmult).arg(scalew).arg(scaleh)
     964        .replace(QChar('/'), ".").replace(QChar(' '), ".")
     965        .replace(QChar(' '), ".");
     966
     967    return cacheKey;
     968}
     969
     970
    781971void OSDTypeImage::LoadImage(const QString &filename, float wmult, float hmult,
    782972                             int scalew, int scaleh)
    783973{
    784     if (m_isvalid)
    785     {
    786         if (m_yuv)
    787             delete [] m_yuv;
    788         if (m_alpha)
    789             delete [] m_alpha;
     974    QString cacheKey = generateCacheKey(filename, wmult, hmult, scalew,
     975                                        scaleh);
    790976
    791         m_isvalid = false;
    792         m_yuv = NULL;
    793         m_alpha = NULL;
     977    // if there's no filename, do not use file buffering (cannot
     978    // generate an unique filename for the cache file), but only
     979    // the memory cache as it's safe to do so, because the
     980    // memory cache is per OSDTypeImage
     981    if (isCached(cacheKey, !filename.isEmpty())) {
     982        loadFromCache(cacheKey, !filename.isEmpty());
     983        m_cached = true;
     984        return;
    794985    }
    795986
    796987    if (filename.length() < 2)
     
    8331024                     imwidth, imheight, tmp2.width());
    8341025
    8351026    m_imagesize = QRect(0, 0, imwidth, imheight);
     1027
     1028    saveToCache(cacheKey, !filename.isEmpty());
     1029    m_cached = true;
    8361030}
    8371031
    8381032void OSDTypeImage::LoadFromQImage(const QImage &img)
    8391033{
    840     if (m_isvalid)
     1034    // this method is not cached as it's used mostly for
     1035    // subtitles which are displayed only once anyways, caching
     1036    // would probably only slow things down overall
     1037    if (m_isvalid && !m_cached)
    8411038    {
    8421039        if (m_yuv)
    8431040            delete [] m_yuv;
    8441041        if (m_alpha)
    8451042            delete [] m_alpha;
    846 
    8471043        m_isvalid = false;
    8481044        m_yuv = NULL;
    8491045        m_alpha = NULL;
     
    11591355OSDTypeEditSlider::~OSDTypeEditSlider()
    11601356{
    11611357    delete [] m_drawMap;
    1162 
    1163     if (m_ryuv)
    1164         delete [] m_ryuv;
    1165     if (m_ralpha)
    1166         delete [] m_ralpha;
    11671358}
    11681359
    11691360void OSDTypeEditSlider::Reinit(float wmult, float hmult)
     
    11841375
    11851376    m_displaypos = m_displayrect.topLeft();
    11861377
    1187     if (m_ryuv)
    1188         delete [] m_ryuv;
    1189     if (m_ralpha)
    1190         delete [] m_ralpha;
     1378    if (!m_cached) {
     1379        if (m_ryuv)
     1380            delete [] m_ryuv;
     1381        if (m_ralpha)
     1382            delete [] m_ralpha;
     1383    }
    11911384
    11921385    LoadImage(m_redname, wmult, hmult, m_scalew, m_scaleh);
    11931386    if (m_isvalid)