]> git.sesse.net Git - kdenlive/blob - thumbnailer/westleypreview.cpp
* new: thumbnailer for preview of kdenlive/westley files in KDE4 apps
[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 <qpixmap.h>
23 #include <qimage.h>
24 #include <QtCore/QVarLengthArray>
25
26 #include <kstandarddirs.h>
27 #include <kmimetype.h>
28 #include <QDir>
29 #include <qpainter.h>
30 #include <krandomsequence.h>
31 #include <qdatetime.h>
32 #include <qregexp.h>
33 #include <QProcess>
34 #include <kdebug.h>
35 #include <ktempdir.h>
36 #include <kurl.h>
37 #include <math.h>
38 #include <qfileinfo.h>
39 #include <kcodecs.h>
40 #include <KTemporaryFile>
41
42 #include <unistd.h>
43
44 #include "westleypreview.h"
45
46 #define DBG_AREA
47
48 //#include "config.h"
49 extern "C"
50 {
51     KDE_EXPORT ThumbCreator *new_creator()
52     {
53         return new WestleyPreview;
54     }
55 }
56
57 WestleyPreview::WestleyPreview()
58 {
59 }
60
61 WestleyPreview::~WestleyPreview()
62 {
63     delete rand;
64     delete inigoprocess;
65 }
66
67 bool WestleyPreview::startAndWaitProcess(const QStringList &args) {
68     kDebug(DBG_AREA) << "westleypreview: starting process with args: " << args << endl;
69     inigoprocess->start( args.join(" ") );
70     if(! inigoprocess->waitForStarted() ) {
71         kDebug(DBG_AREA) << "westleypreview: PROCESS NOT STARTED!!! exiting\n";
72         return false;
73     }
74     if(! inigoprocess->waitForFinished() ) {
75         kDebug(DBG_AREA) << "westleypreview: PROCESS DIDN'T FINISH!! exiting\n";
76         inigoprocess->close();
77         return false;
78     }
79   kDebug() << "westleypreview: process started and ended correctly\n";
80   return true;
81 }
82
83 bool WestleyPreview::create(const QString &path, int width, int height, QImage &img)
84 {
85     QFileInfo fi(path);
86     /*if (fi.suffix().trimmed() != "westley" && fi.suffix().trimmed() != "kdenlive")
87     {
88         kDebug(DBG_AREA) << "westleypreview: matched extension " << fi.suffix().prepend('.') << "; exiting.\n";
89         return false;
90     }*/
91     playerBin=KStandardDirs::findExe("inigo");
92     if(playerBin.isEmpty())
93     {
94         kDebug(DBG_AREA) << "westleypreview: inigo not found, exiting.\n";
95         return false;
96     }
97
98     fileinfo.seconds=0;
99     fileinfo.fps=0;
100
101     rand=new KRandomSequence(QDateTime::currentDateTime().toTime_t());
102     inigoprocess=new QProcess();
103     KUrl furl(path);
104     kDebug(DBG_AREA) << "videopreview: url=" << furl << "; local:" << furl.isLocalFile() << endl;
105     fileinfo.towidth=width;
106     fileinfo.toheight=height;
107     QPixmap pix;
108 //    if(furl.isLocalFile())
109 //    {
110     QStringList args;
111     //TODO: modify inigo so that it can return some infos about a westley clip (duration, track number,fps,...) 
112     // without actually playing the file
113 /*
114     args << playerBin << QString("\"" + path + "\"") << "-file-info";
115
116     kDebug(DBG_AREA) << "videopreview: starting process: --_" << " " << args.join(" ") << "_--\n";
117     if (! startAndWaitProcess(args) ) return NULL;
118
119     QString information=QString(inigoprocess->readAllStandardOutput() );
120     QRegExp findInfos("ID_VIDEO_FPS=([\\d]*).*ID_LENGTH=([\\d]*).*");
121     if(findInfos.indexIn( information) == -1 )
122     {
123         kDebug(DBG_AREA) << "videopreview: No information found, exiting\n";
124         return NULL;
125     }
126     fileinfo.seconds =findInfos.cap(2).toInt();
127     fileinfo.fps=findInfos.cap(1).toInt();
128     */
129     fileinfo.seconds = 250;
130     fileinfo.fps = 25;
131     
132     //kDebug(DBG_AREA) << "videopreview: find length=" << fileinfo.seconds << ", fps=" << fileinfo.fps << endl;
133
134     const int LASTTRY = 3;
135     for(int i=0; i<=LASTTRY; i++)
136     {
137         pix=getFrame(path);
138         if(!pix.isNull()) {
139             uint variance=imageVariance(pix.toImage()/*.bits(),( (width+ 7) & ~0x7), width, height, 1 */);
140             kDebug(DBG_AREA) << "videopreview: " << QFileInfo(path).fileName() << " frame variance: " << variance << "; " << 
141                     ((variance<=40 && ( i!=LASTTRY-1))? "!!!DROPPING!!!" : "GOOD :-)" ) << endl;
142             if(variance>40 || i==LASTTRY-1 ) break;
143         }
144     }
145     if(pix.isNull() )
146     {
147         return false;
148     }
149     img = pix.toImage();
150     return true;
151 }
152
153 QPixmap WestleyPreview::getFrame(const QString &path)
154 {
155     QStringList args;
156     #define START ((fileinfo.seconds*15)/100)
157     #define END ((fileinfo.seconds*70)/100)
158     args.clear();
159     args << playerBin << "\"" + path + "\"";
160     if(fileinfo.towidth>fileinfo.toheight) fileinfo.toheight=-2; else fileinfo.towidth=-2;
161 //     switch( flags ){
162 //         case random
163 //     }
164     unsigned long start=(unsigned long)(START+(rand->getDouble() * (END - START) ) );
165     args << QString("in=%1").arg(start)<< QString("out=%1").arg(start)<<"-consumer";
166
167     KTemporaryFile temp;
168     temp.setSuffix(".png");
169     temp.open();
170     args << QString("avformat:%1").arg(temp.fileName()) << "vframes=1"<< "f=rawvideo"<< "vcodec=png"<< QString("s=%1x%2").arg(fileinfo.towidth).arg(fileinfo.toheight);
171     if (! startAndWaitProcess(args) ) return NULL;
172     QPixmap retpix(temp.fileName());
173     temp.close();
174     return retpix;
175 }
176
177
178 uint WestleyPreview::imageVariance(QImage image )
179 {
180     uint delta=0;
181     uint avg=0;
182     uint bytes=image.numBytes();
183     uint STEPS=bytes/2;
184     QVarLengthArray<uchar> pivot(STEPS);
185     kDebug(DBG_AREA) << "Using " << STEPS << " steps\n";
186     uchar *bits=image.bits();
187     // First pass: get pivots and taking average
188     for( uint i=0; i<STEPS ; i++ ){
189         pivot[i]=bits[i*(bytes/STEPS)];
190         avg+=pivot[i];
191     }
192     avg=avg/STEPS;
193     // Second Step: calculate delta (average?)
194     for (uint i=0; i<STEPS; i++)
195     {
196         int curdelta=abs(int(avg-pivot[i]));
197         delta+=curdelta;
198     }
199     return delta/STEPS;
200 }
201 #include "westleypreview.moc"
202