summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArno <am@disconnect.de>2010-12-16 19:46:34 +0100
committerArno <am@disconnect.de>2010-12-16 19:46:34 +0100
commit69bdaf5d1cdf2cb6a5da8371658e1c3995a71cfb (patch)
treee307f53d30b4ad59f6ab592c97adcf58008a8c6c
parentc7bffca4cfc626c62c0eae6bc6b06d92cb2a8340 (diff)
downloadSheMov-69bdaf5d1cdf2cb6a5da8371658e1c3995a71cfb.tar.gz
SheMov-69bdaf5d1cdf2cb6a5da8371658e1c3995a71cfb.tar.bz2
SheMov-69bdaf5d1cdf2cb6a5da8371658e1c3995a71cfb.zip
Cache for frame grabbing
Implemetented a cache for hovering over movies, saving the pictures from ffmpeg. For that SmGlobals got a new member *frameCache, handling all the dirty file access. I first tried to implement it as a helper, but that produced too much duplicate code.
-rw-r--r--filestreewidget.cpp2
-rw-r--r--helper.cpp21
-rw-r--r--helper.h1
-rw-r--r--smglobals.cpp99
-rw-r--r--smglobals.h25
5 files changed, 124 insertions, 24 deletions
diff --git a/filestreewidget.cpp b/filestreewidget.cpp
index b6189c5..857b848 100644
--- a/filestreewidget.cpp
+++ b/filestreewidget.cpp
@@ -408,7 +408,7 @@ void FilesTreeView::doHover(const QModelIndex &idx){
bool scale = true;
mCurHover = idx;
if(idx.data(FilesTreeModel::FileTypeRole).toInt() == FilesTreeModel::Movie){
- pm = Helper::grabFrame(idx.data(FilesTreeModel::FullPathRole).toString());
+ pm = SmGlobals::instance()->frameCache()->entry(idx.data(FilesTreeModel::FullPathRole).toString());
if(pm.isNull()){
return;
}
diff --git a/helper.cpp b/helper.cpp
index 126b83d..6cb5cd2 100644
--- a/helper.cpp
+++ b/helper.cpp
@@ -167,27 +167,6 @@ namespace Helper {
return retval;
}
- const QPixmap grabFrame(const QString &file, QString when){
- QSettings s;
- QString ffMpegPath = s.value("paths/ffmpeg").toString();
- if(when.isEmpty()){
- when = s.value("ui/grabframe", "00:00:00").toString();
- }
- QString tmptmp = QString("%1/smhover-XXXXXX.png").arg(QDir::tempPath());
- QTemporaryFile tmpPic(tmptmp);
- if(tmpPic.open()){
- QStringList ffMpegArgs = QStringList() << "-vframes" << "1" << "-ss" << when << "-i" << file << "-y" << tmpPic.fileName();
- QProcess ffmpeg;
- ffmpeg.start(ffMpegPath, ffMpegArgs);
- if(!ffmpeg.waitForStarted()){
- return QPixmap();
- }
- ffmpeg.waitForFinished();
- return QPixmap(tmpPic.fileName());
- }
- return QPixmap();
- }
-
bool SortFileInfoList::operator ()(const QFileInfo &lhs, const QFileInfo &rhs) const {
return lhs.fileName().toLower() < rhs.fileName().toLower();
}
diff --git a/helper.h b/helper.h
index fb6ef1c..c9d1ad3 100644
--- a/helper.h
+++ b/helper.h
@@ -25,7 +25,6 @@ namespace Helper {
const QString createArchivePath(const QString &path, const QString &md5, bool withMd5 = false);
QPair<QString, QStringList> programData(const QString &prefix, const QString &preferred = QString());
const QString durationFromSecs(qint64 secs);
- const QPixmap grabFrame(const QString &file, QString when = QString());
class SortFileInfoList : public std::binary_function<QFileInfo, QFileInfo, bool> {
public:
bool operator()(const QFileInfo &lhs, const QFileInfo &rhs) const;
diff --git a/smglobals.cpp b/smglobals.cpp
index 9b4837c..f163ac1 100644
--- a/smglobals.cpp
+++ b/smglobals.cpp
@@ -10,6 +10,12 @@
#include <QStringList>
#include <QMessageBox>
#include <QSettings>
+#include <QDir>
+#include <QFile>
+#include <QDataStream>
+#include <QFileInfo>
+#include <QTemporaryFile>
+#include <QProcess>
#include <QX11Info>
#include <X11/Xlib.h>
@@ -28,6 +34,7 @@ SmGlobals::~SmGlobals(){
delete model;
}
QSqlDatabase::removeDatabase("treedb");
+ delete mFrameCache;
}
SmGlobals *SmGlobals::instance(){
@@ -84,6 +91,13 @@ PictureViewer *SmGlobals::pictureViewer() {
return mPictureViewer;
}
+SmGlobals::FrameCache *SmGlobals::frameCache() {
+ if(!mFrameCache){
+ mFrameCache = new SmGlobals::FrameCache;
+ }
+ return mFrameCache;
+}
+
QSize SmGlobals::cursorSize() {
if(!mCursorSize.isValid()){
XFixesCursorImage *curImage = XFixesGetCursorImage(QX11Info::display());
@@ -93,4 +107,87 @@ QSize SmGlobals::cursorSize() {
return mCursorSize;
}
-SmGlobals::SmGlobals() : mPictureViewer(0) {}
+SmGlobals::SmGlobals() : mPictureViewer(0), mFrameCache(0) {}
+
+//FrameCache
+SmGlobals::FrameCache::FrameCache(QObject *parent) : QObject(parent), mMagic(0xDEADBEEF), mCacheSubDir(".frameCache"), mCacheFileName("cache") {
+ readConfig();
+ readCache();
+}
+
+SmGlobals::FrameCache::~FrameCache(){
+ QFile outfile(mCacheFile);
+ outfile.open(QIODevice::WriteOnly | QIODevice::Truncate);
+ QDataStream ds(&outfile);
+ ds << (qint32)mMagic;
+ for(QHash<QPair<QString, QString>, QString>::const_iterator it = mFrameCache.constBegin(); it != mFrameCache.constEnd(); ++it){
+ ds << it.key().first << it.key().second << it.value();
+ }
+ outfile.close();
+}
+
+void SmGlobals::FrameCache::readConfig(){
+ QSettings s;
+ QString archive = s.value("paths/archivedir").toString();
+ if(archive.isEmpty()){
+ return;
+ }
+ QDir archiveDir(archive);
+ if(!archiveDir.exists(mCacheSubDir)){
+ archiveDir.mkdir(mCacheSubDir);
+ }
+ mCacheDir = QString("%1/%2").arg(archive).arg(mCacheSubDir);
+ mCacheFile = QString("%1/%2").arg(mCacheDir).arg(mCacheFileName);
+ mWhen = s.value("ui/grabframe", "00:00:00").toString();
+ mFfMpegPath = s.value("paths/ffmpeg").toString();
+}
+
+const QPixmap SmGlobals::FrameCache::entry(const QString &sourcePath, const QString &when){
+ QString realWhen = when;
+ if(realWhen.isEmpty()){
+ realWhen = mWhen;
+ }
+ const QPair<QString, QString> source(sourcePath, realWhen);
+ if(!mFrameCache.contains(source)){
+ grabFrame(sourcePath, realWhen);
+ }
+ return QPixmap(mFrameCache.value(source));
+}
+
+void SmGlobals::FrameCache::grabFrame(const QString &sourceFile, QString when){
+ QFileInfo sourceInfo(sourceFile);
+ if(!sourceInfo.exists()){
+ return;
+ }
+ QString tmpTemplate = QString("%1/%2_%3-XXXXXX.png").arg(mCacheDir).arg(sourceInfo.fileName()).arg(when);
+ QTemporaryFile tempFile(tmpTemplate);
+ tempFile.setAutoRemove(false);
+ if(tempFile.open()){
+ QStringList ffMpegArgs = QStringList() << "-vframes" << "1" << "-ss" << when << "-i" << sourceFile << "-y" << tempFile.fileName();
+ QProcess ffmpeg;
+ ffmpeg.start(mFfMpegPath, ffMpegArgs);
+ if(!ffmpeg.waitForStarted()){
+ return;
+ }
+ ffmpeg.waitForFinished();
+ QPair<QString, QString> pair(sourceFile, when);
+ mFrameCache.insert(pair, tempFile.fileName());
+ }
+}
+
+void SmGlobals::FrameCache::readCache(){
+ QFile cache(mCacheFile);
+ cache.open(QIODevice::ReadOnly);
+ QDataStream ds(&cache);
+ qint32 magic;
+ ds >> magic;
+ if(magic != mMagic){
+ return;
+ }
+ while(!ds.atEnd()){
+ QString source, pos, cacheFile;
+ ds >> source >> pos >> cacheFile;
+ QPair<QString, QString> pair(source, pos);
+ mFrameCache.insert(pair, cacheFile);
+ }
+}
diff --git a/smglobals.h b/smglobals.h
index 06d7b43..b994b53 100644
--- a/smglobals.h
+++ b/smglobals.h
@@ -10,17 +10,41 @@
#include <QHash>
#include <QSize>
+#include <QPair>
class QAbstractItemModel;
class PictureViewer;
+class QPixmap;
class SmGlobals : public QObject {
Q_OBJECT
public:
+ class FrameCache : public QObject {
+ public:
+ FrameCache(QObject *parent = 0);
+ ~FrameCache();
+ void readConfig();
+ const QPixmap entry(const QString &sourcePath, const QString &when = QString());
+
+ private:
+ void readCache();
+ void grabFrame(const QString &sourceFile, QString when);
+ QHash<QPair<QString, QString>, QString> mFrameCache;
+ const qint32 mMagic;
+ const QString mCacheSubDir;
+ const QString mCacheFileName;
+ QString mCacheDir;
+ QString mCacheFile;
+ QString mWhen;
+ QString mFfMpegPath;
+
+ };
+
~SmGlobals();
static SmGlobals *instance();
QAbstractItemModel *model(const QString &which);
PictureViewer *pictureViewer();
+ FrameCache *frameCache();
QSize cursorSize();
private:
@@ -30,6 +54,7 @@ class SmGlobals : public QObject {
static SmGlobals *mInstance;
QHash<QString, QAbstractItemModel*> mModels;
PictureViewer *mPictureViewer;
+ SmGlobals::FrameCache *mFrameCache;
QSize mCursorSize;
};