]> git.sesse.net Git - kdenlive/blob - thumbnailer/westleypreview.cpp
remove useless header
[kdenlive] / thumbnailer / westleypreview.cpp
1 /***************************************************************************
2    Copyright (C) 2006-2008
3    by Marco Gulino <marco@kmobiletools.org>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the
17    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18     Boston, MA 02110-1301, USA.
19  ***************************************************************************/
20
21 #include <qfile.h>
22 #include <qimage.h>
23 #include <QtCore/QVarLengthArray>
24
25 #include <kstandarddirs.h>
26 #include <krandomsequence.h>
27 #include <qdatetime.h>
28 #include <QProcess>
29 #include <kdebug.h>
30 #include <ktempdir.h>
31 #include <kurl.h>
32 #include <qfileinfo.h>
33 #include <KTemporaryFile>
34
35 #include <unistd.h>
36
37 #include "westleypreview.h"
38
39 #define DBG_AREA
40
41 //#include "config.h"
42 extern "C" {
43     KDE_EXPORT ThumbCreator *new_creator() {
44         return new WestleyPreview;
45     }
46 }
47
48 WestleyPreview::WestleyPreview()
49         : m_rand(0), m_inigoprocess(0) {
50 }
51
52 WestleyPreview::~WestleyPreview() {
53     delete m_rand;
54     delete m_inigoprocess;
55 }
56
57 bool WestleyPreview::startAndWaitProcess(const QStringList &args) {
58     kDebug(DBG_AREA) << "westleypreview: starting process with args: " << args << endl;
59     m_inigoprocess->start(args.join(" "));
60     if (! m_inigoprocess->waitForStarted()) {
61         kDebug(DBG_AREA) << "westleypreview: PROCESS NOT STARTED!!! exiting\n";
62         return false;
63     }
64     if (! m_inigoprocess->waitForFinished()) {
65         kDebug(DBG_AREA) << "westleypreview: PROCESS DIDN'T FINISH!! exiting\n";
66         m_inigoprocess->close();
67         return false;
68     }
69     kDebug() << "westleypreview: process started and ended correctly\n";
70     return true;
71 }
72
73 bool WestleyPreview::create(const QString &path, int width, int height, QImage &img) {
74     QFileInfo fi(path);
75     /*if (fi.suffix().trimmed() != "westley" && fi.suffix().trimmed() != "kdenlive")
76     {
77         kDebug(DBG_AREA) << "westleypreview: matched extension " << fi.suffix().prepend('.') << "; exiting.\n";
78         return false;
79     }*/
80     playerBin = KStandardDirs::findExe("inigo");
81     if (playerBin.isEmpty()) {
82         kDebug(DBG_AREA) << "westleypreview: inigo not found, exiting.\n";
83         return false;
84     }
85
86     fileinfo.seconds = 0;
87     fileinfo.fps = 0;
88
89     m_rand = new KRandomSequence(QDateTime::currentDateTime().toTime_t());
90     m_inigoprocess = new QProcess();
91     KUrl furl(path);
92     kDebug(DBG_AREA) << "videopreview: url=" << furl << "; local:" << furl.isLocalFile() << endl;
93     fileinfo.towidth = width;
94     fileinfo.toheight = height;
95     QPixmap pix;
96 //    if(furl.isLocalFile())
97 //    {
98     QStringList args;
99     //TODO: modify inigo so that it can return some infos about a westley clip (duration, track number,fps,...)
100     // without actually playing the file
101     /*
102         args << playerBin << QString("\"" + path + "\"") << "-file-info";
103
104         kDebug(DBG_AREA) << "videopreview: starting process: --_" << " " << args.join(" ") << "_--\n";
105         if (! startAndWaitProcess(args) ) return NULL;
106
107         QString information=QString(inigoprocess->readAllStandardOutput() );
108         QRegExp findInfos("ID_VIDEO_FPS=([\\d]*).*ID_LENGTH=([\\d]*).*");
109         if(findInfos.indexIn( information) == -1 )
110         {
111             kDebug(DBG_AREA) << "videopreview: No information found, exiting\n";
112             return NULL;
113         }
114         fileinfo.seconds =findInfos.cap(2).toInt();
115         fileinfo.fps=findInfos.cap(1).toInt();
116         */
117     fileinfo.seconds = 250;
118     fileinfo.fps = 25;
119
120     //kDebug(DBG_AREA) << "videopreview: find length=" << fileinfo.seconds << ", fps=" << fileinfo.fps << endl;
121
122     const int LASTTRY = 3;
123     for (int i = 0; i <= LASTTRY; i++) {
124         pix = getFrame(path);
125         if (!pix.isNull()) {
126             uint variance = imageVariance(pix.toImage()/*.bits(),( (width+ 7) & ~0x7), width, height, 1 */);
127             kDebug(DBG_AREA) << "videopreview: " << QFileInfo(path).fileName() << " frame variance: " << variance << "; " <<
128             ((variance <= 40 && (i != LASTTRY - 1)) ? "!!!DROPPING!!!" : "GOOD :-)") << endl;
129             if (variance > 40 || i == LASTTRY - 1) break;
130         }
131     }
132     if (pix.isNull()) {
133         return false;
134     }
135     img = pix.toImage();
136     return true;
137 }
138
139 QPixmap WestleyPreview::getFrame(const QString &path) {
140     QStringList args;
141 #define START ((fileinfo.seconds*15)/100)
142 #define END ((fileinfo.seconds*70)/100)
143     args.clear();
144     args << playerBin << "\"" + path + "\"";
145     if (fileinfo.towidth > fileinfo.toheight) fileinfo.toheight = -2;
146     else fileinfo.towidth = -2;
147 //     switch( flags ){
148 //         case random
149 //     }
150     unsigned long start = (unsigned long)(START + (m_rand->getDouble() * (END - START)));
151     args << QString("in=%1").arg(start) << QString("out=%1").arg(start) << "-consumer";
152
153     KTemporaryFile temp;
154     temp.setSuffix(".png");
155     temp.open();
156     args << QString("avformat:%1").arg(temp.fileName()) << "vframes=1" << "f=rawvideo" << "vcodec=png" << QString("s=%1x%2").arg(fileinfo.towidth).arg(fileinfo.toheight);
157     if (! startAndWaitProcess(args)) return NULL;
158     QPixmap retpix(temp.fileName());
159     temp.close();
160     return retpix;
161 }
162
163
164 uint WestleyPreview::imageVariance(QImage image) {
165     uint delta = 0;
166     uint avg = 0;
167     uint bytes = image.numBytes();
168     uint STEPS = bytes / 2;
169     QVarLengthArray<uchar> pivot(STEPS);
170     kDebug(DBG_AREA) << "Using " << STEPS << " steps\n";
171     uchar *bits = image.bits();
172     // First pass: get pivots and taking average
173     for (uint i = 0; i < STEPS ; i++) {
174         pivot[i] = bits[i*(bytes/STEPS)];
175         avg += pivot[i];
176     }
177     avg = avg / STEPS;
178     // Second Step: calculate delta (average?)
179     for (uint i = 0; i < STEPS; i++) {
180         int curdelta = abs(int(avg - pivot[i]));
181         delta += curdelta;
182     }
183     return delta / STEPS;
184 }
185
186 ThumbCreator::Flags WestleyPreview::flags() const {
187     return DrawFrame;
188 }
189
190 #include "westleypreview.moc"
191