-
Notifications
You must be signed in to change notification settings - Fork 0
/
thumbnailprovider.cpp
124 lines (95 loc) · 3.46 KB
/
thumbnailprovider.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "thumbnailprovider.h"
#include "photomodel.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QImageReader>
#include <QProcess>
#include <QSettings>
#include <QStandardPaths>
#include <algorithm>
#include <memory>
ThumbnailProvider::ThumbnailProvider(QAbstractItemModel* photoListModel)
: QQuickImageProvider(QQmlImageProviderBase::Image), photoListModel(dynamic_cast<PhotoModel*>(photoListModel))
{
auto cachePaths = QStandardPaths::standardLocations(QStandardPaths::CacheLocation);
if (cachePaths.length()) {
cachePath = cachePaths.first();
QDir cacheDir(cachePath);
cacheDir.mkpath(cachePath + "/thumbs360");
cacheDir.mkpath(cachePath + "/thumbs128");
cacheDir.mkpath(cachePath + "/videoframes");
}
ffmpegCmd = QSettings().value("ffmpegpath").toString();
}
ThumbnailProvider::~ThumbnailProvider()
{
}
QImage ThumbnailProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
{
if (requestedSize == QSize(-1, -1))
return QImage();
int thumbSize = std::max(requestedSize.width(), requestedSize.height()) > 128 ? 360 : 128;
QString thumbPath = QString("%1/thumbs%2/%3.jpg").arg(cachePath, QString::number(thumbSize), id);
QString videoFramePath = QString("%1/videoframes/%2.jpg").arg(cachePath, id);
if (QFile::exists(thumbPath))
return QImage(thumbPath);
QString filename;
QString type;
auto matches = photoListModel->match(photoListModel->index(0, 0), PhotoModel::ThumbnailRole, id);
QModelIndex match;
if (matches.size())
match = matches.first();
else
return generateFallback(requestedSize);
filename = photoListModel->data(match, PhotoModel::MappedFilenameRole).toString();
type = photoListModel->data(match, PhotoModel::TypeRole).toString();
QImage image;
if (type == "photo")
image = generateThumbnail(thumbSize, thumbPath, filename);
else {
if (!QFile::exists(videoFramePath))
grabVideoFrame(videoFramePath, filename);
image = generateThumbnail(thumbSize, thumbPath, videoFramePath);
}
if (image.isNull())
image = generateFallback(requestedSize);
if (size)
*size = image.size();
return image;
}
QImage ThumbnailProvider::generateFallback(QSize size)
{
QImage image(size, QImage::Format_RGB32);
image.fill("steelblue");
return image;
}
QImage ThumbnailProvider::generateThumbnail(int thumbSize, const QString& thumbPath, const QString& filename)
{
QImageReader reader(filename);
reader.setAutoTransform(true);
if (!reader.canRead())
return QImage();
auto image = reader.read();
auto smallRough = image.scaled(thumbSize * 2, thumbSize * 2, Qt::KeepAspectRatio, Qt::FastTransformation);
auto thumbnail = smallRough.scaled(thumbSize, thumbSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
thumbnail.save(thumbPath);
return thumbnail;
}
QImage ThumbnailProvider::grabVideoFrame(const QString& thumbPath, const QString& filename)
{
auto ffmpeg = std::make_unique<QProcess>();
QStringList arguments = {
"-loglevel", "panic", "-i", filename, "-ss", "0.5", "-q:v", "2", "-vframes", "1", thumbPath};
ffmpeg->start(ffmpegCmd, arguments);
ffmpeg->waitForFinished(20000);
if (!ffmpeg->exitCode()) {
return QImage(thumbPath);
}
else
return QImage();
}
void ThumbnailProvider::setFfmpegCmd(const QString& value)
{
ffmpegCmd = value;
}