summaryrefslogtreecommitdiffstats
path: root/src/mplayer-thumbnailer.cpp
diff options
context:
space:
mode:
authorSlávek Banko <slavek.banko@axis.cz>2021-09-02 16:50:11 +0200
committerSlávek Banko <slavek.banko@axis.cz>2021-09-02 18:26:16 +0200
commit16167444904ab5b0382e3aff98b3de749161ebe3 (patch)
tree596a287d06a1e0b2021ce0b9f25335a0c0cecc1b /src/mplayer-thumbnailer.cpp
parent6d4b0b255a970005d74fcc1e4144418bbc11bfe8 (diff)
downloadmplayerthumbs-16167444904ab5b0382e3aff98b3de749161ebe3.tar.gz
mplayerthumbs-16167444904ab5b0382e3aff98b3de749161ebe3.zip
Renamed from videopreview and mplayerthumbs to mplayer-thumbnailer.
Signed-off-by: Slávek Banko <slavek.banko@axis.cz>
Diffstat (limited to 'src/mplayer-thumbnailer.cpp')
-rw-r--r--src/mplayer-thumbnailer.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/mplayer-thumbnailer.cpp b/src/mplayer-thumbnailer.cpp
new file mode 100644
index 0000000..ae2e720
--- /dev/null
+++ b/src/mplayer-thumbnailer.cpp
@@ -0,0 +1,262 @@
+/***************************************************************************
+ Copyright (C) 2006
+ by Marco Gulino <marco@kmobiletools.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#include "mplayer-thumbnailer.h"
+
+#include <tqfile.h>
+#include <tqpixmap.h>
+#include <tqimage.h>
+
+#include <kstandarddirs.h>
+#include <kpixmapsplitter.h>
+#include <kmimetype.h>
+#include <tqpainter.h>
+#include <krandomsequence.h>
+#include <tqdatetime.h>
+#include <tqregexp.h>
+
+#include <tqprocess.h>
+#include <kdebug.h>
+#include <ktempdir.h>
+#include <kurl.h>
+#include <math.h>
+#include <tqfileinfo.h>
+
+#include <cstdlib>
+#include <unistd.h>
+
+#include "mplayer-thumbnailer-cfg.h"
+#include "config.h"
+
+extern "C"
+{
+ KDE_EXPORT ThumbCreator *new_creator()
+ {
+ return new MPlayerThumbnailer;
+ }
+}
+
+MPlayerThumbnailer::MPlayerThumbnailer()
+ : m_splitter(0),
+ m_data(0),
+ m_dataSize(0)
+{
+}
+
+MPlayerThumbnailer::~MPlayerThumbnailer()
+{
+ delete m_splitter;
+ delete [] m_data;
+ delete tmpdir;
+ delete rand;
+ delete mplayerprocess;
+}
+
+bool MPlayerThumbnailer::create(const TQString &path, int width, int height, TQImage &img)
+{
+ MPlayerThumbnailerCfg *cfg=new MPlayerThumbnailerCfg();
+ TQFileInfo fi(path);
+ kdDebug() << "mplayer-thumbnailer: file extension=\"" << fi.extension().stripWhiteSpace() << "\"\n";
+ if( fi.extension().stripWhiteSpace().length() && !cfg->noextensions().grep(fi.extension().stripWhiteSpace(), false)
+ .isEmpty() )
+ {
+ delete cfg;
+ kdDebug() << "mplayer-thumbnailer: matched extension " << fi.extension().prepend('.') << "; exiting.\n";
+ return false;
+ }
+ playerBin=cfg->mplayerbin();
+ customargs=TQStringList::split(" ", cfg->customargs() );
+ kdDebug() << "mplayer-thumbnailer: customargs=" << cfg->customargs() << " ;;;; " << customargs << endl;
+ delete cfg;
+ if(playerBin.length()) kdDebug() << "mplayer-thumbnailer: found playerbin from config: " << playerBin << endl;
+ else
+ {
+ playerBin=TDEStandardDirs::findExe("mplayer-bin");
+ if(!playerBin.length()) playerBin=TDEStandardDirs::findExe("mplayer");
+ if(!playerBin.length())
+ {
+ kdDebug() << "mplayer-thumbnailer: mplayer not found, exiting. Run mplayer-thumbnailer-config to setup mplayer path manually.\n";
+ return false;
+ }
+ kdDebug() << "mplayer-thumbnailer: found playerbin from path: " << playerBin << endl;
+ }
+ fileinfo.seconds=0;
+ fileinfo.fps=0;
+ tmpdir=new KTempDir();
+ if(tmpdir->name().isNull() ) return false;
+
+ rand=new KRandomSequence(TQDateTime::currentDateTime().toTime_t());
+ mplayerprocess=new TQProcess();
+ int flags=0;
+ KURL furl(path);
+ kdDebug() << "mplayer-thumbnailer: url=" << furl << "; local:" << furl.isLocalFile() << endl;
+ fileinfo.towidth=width;
+ fileinfo.toheight=height;
+ TQPixmap pix;
+// if(furl.isLocalFile())
+// {
+ flags=framerandom;
+ TQStringList args;
+ args << playerBin << path << "-nocache" << "-identify" << "-vo" << "null" << "-frames" << "0"/* << "-nosound" */<< "-ao" << "null";
+ args+= customargs;
+ mplayerprocess->setArguments(args);
+ mplayerprocess->setCommunication( TQProcess::Stdout );
+ mplayerprocess->start();
+ TQString lineout;
+ TQRegExp findsecs("^ID_LENGTH=([\\d]*)");
+ TQRegExp findfps("^ID_VIDEO_FPS=([\\d]*)");
+ while (mplayerprocess->isRunning() ) usleep (10);
+ do {
+ lineout=mplayerprocess->readLineStdout();
+ if(findsecs.search( lineout) != -1)
+ fileinfo.seconds =findsecs.cap(1).toInt();
+ if(findfps.search( lineout) != -1)
+ fileinfo.fps=findfps.cap(1).toInt();
+ if( fileinfo.fps!=0 && fileinfo.seconds!=0 ) break;
+ } while (lineout != TQString::null );
+ kdDebug() << "mplayer-thumbnailer: find length=" << fileinfo.seconds << ", fps=" << fileinfo.fps << endl;
+/* } else
+ {
+ flags=frameend;
+ }*/
+#define LASTTRY 3
+ for(int i=0; i<=LASTTRY; i++)
+ {
+ kdDebug() << "mplayer-thumbnailer: try " << i << endl;
+ pix=getFrame(path, ((i<LASTTRY) ? flags : framestart ) );
+ if(!pix.isNull()) {
+ uint variance=imageVariance(pix.convertToImage()/*.bits(),( (width+ 7) & ~0x7), width, height, 1 */);
+ kdDebug() << "mplayer-thumbnailer: " << TQFileInfo(path).fileName() << " frame variance: " << variance << "; " <<
+ ((variance<=40 && ( i!=LASTTRY-1))? "!!!DROPPING!!!" : "GOOD :-)" ) << endl;
+ if(variance>40 || i==LASTTRY-1 ) break;
+ }
+ }
+ if(pix.isNull() )
+ {
+ if(tmpdir) tmpdir->unlink();
+ return false;
+ }
+ /** From videocreator.cpp - xine_artsplugin
+ Copyright (C) 2002 Simon MacMullen
+ Copyright (C) 2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
+ * */
+// TQPixmap pix( createThumbnail( &frame, width, height ) );
+#ifdef STRIPS_SUPPORT
+ TQPainter painter( &pix );
+ TQPixmap sprocket;
+
+ if (pix.height() < 60)
+ sprocket = TQPixmap(locate( "data", "mplayer-thumbnailer/sprocket-small.png" ));
+ else if (pix.height() < 90)
+ sprocket = TQPixmap(locate( "data", "mplayer-thumbnailer/sprocket-medium.png" ));
+ else
+ sprocket = TQPixmap(locate( "data", "mplayer-thumbnailer/sprocket-large.png" ));
+
+ for (int y = 0; y < pix.height() + sprocket.height(); y += sprocket.height()) {
+ painter.drawPixmap( 0, y, sprocket );
+ }
+
+ // End of xine-artsplugin code
+#endif
+ img = pix.convertToImage();
+
+ if(tmpdir) tmpdir->unlink();
+ return true;
+}
+
+TQPixmap MPlayerThumbnailer::getFrame(const TQString &path, int flags)
+{
+ TQStringList args;
+ kdDebug() << "mplayer-thumbnailer: using flags " << flags << endl;
+#define START ((fileinfo.seconds*15)/100)
+#define END ((fileinfo.seconds*70)/100)
+ mplayerprocess->setCommunication( 0 );
+ mplayerprocess->clearArguments();
+ args.clear();
+ args << playerBin << path;
+ if(fileinfo.towidth>fileinfo.toheight) fileinfo.toheight=-2; else fileinfo.towidth=-2;
+// switch( flags ){
+// case random
+// }
+ if( flags & framerandom )
+ {
+ kdDebug() << "mplayer-thumbnailer: framerandom\n";
+ unsigned long start=(unsigned long)(START+(rand->getDouble() * (END - START) ) );
+ args << "-ss" << TQString::number( start )
+ << "-frames" << "4";
+ } else if (flags & frameend )
+ {
+ kdDebug() << "mplayer-thumbnailer: frameend\n";
+ args << "-ss" << TQString::number( fileinfo.seconds - 10 )
+ << "-frames" << "4";
+ } else if (flags & framestart)
+ {
+ kdDebug() << "mplayer-thumbnailer: framestart\n";
+ if(!fileinfo.fps) fileinfo.fps=25; // if we've not autodetected a fps rate, let's assume 25fps.. even if it's wrong it shouldn't hurt.
+ // If we can't skip to a random frame, let's try playing 10 seconds.
+ args << "-frames" << TQString::number( fileinfo.fps*10 );
+ }
+ args << "-nocache" << "-idx" /*@TODO check if it's too slow..*/ << "-ao" << "null"/*"-nosound" << */<< "-speed" << "99" /*<< "-sstep" << "5"*/
+ << "-vo" << TQString("jpeg:outdir=%1").arg(tmpdir->name() ) << "-vf" << TQString("scale=%1:%2").arg(fileinfo.towidth).arg(fileinfo.toheight);
+ args+=customargs;
+ kdDebug() << "mplayer-thumbnailer: Starting MPlayer with" << args.join( " ") << endl;
+// return false;
+ mplayerprocess->setArguments( args);
+ mplayerprocess->start();
+ while (mplayerprocess->isRunning() ) usleep (10);
+ if (tmpdir->qDir()->entryList( "*.jpg" ).isEmpty() ) return 0;
+
+ TQString lastframe=tmpdir->qDir()->entryList( "*.jpg" ).last();
+ kdDebug() << "mplayer-thumbnailer: LastFrame==" << lastframe << endl;
+ TQPixmap retpix(tmpdir->name().append( lastframe ));
+ return retpix;
+}
+
+ThumbCreator::Flags MPlayerThumbnailer::flags() const
+{
+ return (Flags)(DrawFrame);
+}
+
+
+uint MPlayerThumbnailer::imageVariance(TQImage image )
+{
+ uint delta=0;
+ uint avg=0;
+ uint bytes=image.numBytes();
+ uint STEPS=bytes/2;
+ uchar pivot[STEPS];
+ kdDebug() << "Using " << STEPS << " steps\n";
+ uchar *bits=image.bits();
+ // First pass: get pivots and taking average
+ for( uint i=0; i<STEPS ; i++ ){
+ pivot[i]=bits[i*(bytes/STEPS)];
+ avg+=pivot[i];
+ }
+ avg=avg/STEPS;
+ // Second Step: calculate delta (average?)
+ for (uint i=0; i<STEPS; i++)
+ {
+ int curdelta=abs(int(avg-pivot[i]));
+ delta+=curdelta;
+ }
+ return delta/STEPS;
+}
+
+#include "mplayer-thumbnailer.moc"