/*************************************************************************** Copyright (C) 2006 by Marco Gulino 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 "videopreview.h" #include #include #include #include #include #include #include #include #include #include #include "videopreview.h" #include #include #include #include #include #include #include #include #include "mplayerthumbs.h" #include "config.h" extern "C" { KDE_EXPORT ThumbCreator *new_creator() { return new VideoPreview; } } VideoPreview::VideoPreview() : m_splitter(0), m_data(0), m_dataSize(0) { } VideoPreview::~VideoPreview() { delete m_splitter; delete [] m_data; delete tmpdir; delete rand; delete mplayerprocess; } bool VideoPreview::create(const TQString &path, int width, int height, TQImage &img) { MPlayerThumbsCfg *cfg=new MPlayerThumbsCfg(); TQFileInfo fi(path); kdDebug() << "videopreview: file extension=\"" << fi.extension().stripWhiteSpace() << "\"\n"; if( fi.extension().stripWhiteSpace().length() && !cfg->noextensions().grep(fi.extension().stripWhiteSpace(), false) .isEmpty() ) { delete cfg; kdDebug() << "videopreview: matched extension " << fi.extension().prepend('.') << "; exiting.\n"; return false; } playerBin=cfg->mplayerbin(); customargs=TQStringList::split(" ", cfg->customargs() ); kdDebug() << "videopreview: customargs=" << cfg->customargs() << " ;;;; " << customargs << endl; delete cfg; if(playerBin.length()) kdDebug() << "videopreview: found playerbin from config: " << playerBin << endl; else { playerBin=TDEStandardDirs::findExe("mplayer-bin"); if(!playerBin.length()) playerBin=TDEStandardDirs::findExe("mplayer"); if(!playerBin.length()) { kdDebug() << "videopreview: mplayer not found, exiting. Run mplayerthumbsconfig to setup mplayer path manually.\n"; return false; } kdDebug() << "videopreview: 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() << "videopreview: 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() << "videopreview: find length=" << fileinfo.seconds << ", fps=" << fileinfo.fps << endl; /* } else { flags=frameend; }*/ #define LASTTRY 3 for(int i=0; i<=LASTTRY; i++) { kdDebug() << "videopreview: try " << i << endl; pix=getFrame(path, ((i40 || 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 * */ // TQPixmap pix( createThumbnail( &frame, width, height ) ); #ifdef STRIPS_SUPPORT TQPainter painter( &pix ); TQPixmap sprocket; if (pix.height() < 60) sprocket = TQPixmap(locate( "data", "videopreview/sprocket-small.png" )); else if (pix.height() < 90) sprocket = TQPixmap(locate( "data", "videopreview/sprocket-medium.png" )); else sprocket = TQPixmap(locate( "data", "videopreview/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 VideoPreview::getFrame(const TQString &path, int flags) { TQStringList args; kdDebug() << "videopreview: 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() << "videopreview: framerandom\n"; unsigned long start=(unsigned long)(START+(rand->getDouble() * (END - START) ) ); args << "-ss" << TQString::number( start ) << "-frames" << "4"; } else if (flags & frameend ) { kdDebug() << "videopreview: frameend\n"; args << "-ss" << TQString::number( fileinfo.seconds - 10 ) << "-frames" << "4"; } else if (flags & framestart) { kdDebug() << "videopreview: 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() << "videopreview: 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() << "videopreview: LastFrame==" << lastframe << endl; TQPixmap retpix(tmpdir->name().append( lastframe )); return retpix; } ThumbCreator::Flags VideoPreview::flags() const { return (Flags)(DrawFrame); } uint VideoPreview::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