This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Ajout des pochettes mkv dans mplayerthumbs

Tags: None
(comma "," separated)
pamputt
Registered Member
Posts
154
Karma
0
OS
Bonjour, dans certains films au format mkv, il y a des pochettes du DVD qui sont inclus dans le conteneur. Je suis en train de regarder si je peux récupérer ces pochettes et les afficher en icone pour ce film dans Dolphin par exemple. Pour cela, j'ai récupérer le code source de mpllayerthumbs et je tente de le modifier pour ajouter cela. Le principal problème c'est que j'ai uniquement quelques bases en c++ mais absolument aucune en qt, ni en ce qui concerne les bibliothèques KDE. Mais je me suis lancé. Grosso modo, pour le moment j'ai ajouté une méthode GetMkvCover à côté de la méthode GetFrame dans le fichier videopreview.cpp. Voici le code
Code: Select all
/***************************************************************************
   Copyright (C) 2006-2008
   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 "videopreview.h"

#include <qfile.h>
#include <qpixmap.h>
#include <qimage.h>
#include <QtCore/QVarLengthArray>

#include <kstandarddirs.h>
#include <kmimetype.h>
#include <QDir>
#include <QString>
#include <qpainter.h>
#include <krandomsequence.h>
#include <qdatetime.h>
#include <qregexp.h>
#include "videopreview.h"
#include <QProcess>
#include <kdebug.h>
#include <ktempdir.h>
#include <kurl.h>
#include <math.h>
#include <qfileinfo.h>
#include <kcodecs.h>

#include "mplayerthumbs.h"

#include <iostream>
#include <unistd.h>

#define DBG_AREA

//#include "config.h"
extern "C"
{
    KDE_EXPORT ThumbCreator *new_creator()
    {
        return new VideoPreview;
    }
}

VideoPreview::VideoPreview()
    : m_data(0),
      m_dataSize(0)
{
}

VideoPreview::~VideoPreview()
{
    delete [] m_data;
    delete tmpdir;
    delete rand;
    delete mplayerprocess;
}

bool VideoPreview::startAndWaitProcess(const QStringList &args) {
    kDebug(DBG_AREA) << "videopreview: starting process with args: " << args << endl;
    mplayerprocess->start( args.join(" ") );
    if(! mplayerprocess->waitForStarted() ) {
        kDebug(DBG_AREA) << "videopreview: PROCESS NOT STARTED!!! exiting\n";
        return false;
    }
    if(! mplayerprocess->waitForFinished() ) {
        kDebug(DBG_AREA) << "videopreview: PROCESS DIDN'T FINISH!! exiting\n";
        mplayerprocess->close();
        return false;
    }
  kDebug() << "videopreview: process started and ended correctly\n";
  return true;
}

bool VideoPreview::create(const QString &path, int width, int height, QImage &img)
{
    MPlayerThumbsCfg *cfg=MPlayerThumbsCfg::self();
    QFileInfo fi(path);
        kDebug(DBG_AREA) << "videopreview: file extension=\"" << fi.suffix().trimmed() << "\"\n";
        if( fi.suffix().trimmed().length() && !cfg->noextensions().filter(fi.suffix().trimmed(), Qt::CaseInsensitive)
         .isEmpty() )
    {
        delete cfg;
        kDebug(DBG_AREA) << "videopreview: matched extension " << fi.suffix().prepend('.') << "; exiting.\n";
        return false;
    }
    playerBin=cfg->mplayerbin();
    customargs=cfg->customargs().split(" ");
    kDebug(DBG_AREA) << "videopreview: customargs=" << cfg->customargs() << " ;;;; " << customargs << endl;
    delete cfg;
    if(playerBin.length()) kDebug(DBG_AREA) << "videopreview: found playerbin from config: " << playerBin << endl;
    else
    {
        playerBin=KStandardDirs::findExe("mplayer-bin");
        if(!playerBin.length()) playerBin=KStandardDirs::findExe("mplayer");
        if(!playerBin.length())
        {
            kDebug(DBG_AREA) << "videopreview: mplayer not found, exiting. Run mplayerthumbsconfig to setup mplayer path manually.\n";
            return false;
        }
        kDebug(DBG_AREA) << "videopreview: found playerbin from path: " << playerBin << endl;   
    }

    mkvextractBin=KStandardDirs::findExe("mkvextract");
    if(!mkvextractBin.length())
      {
   kDebug(DBG_AREA) << "mkvcreator: mkvextract not found, exiting.\n";
   return false;
      }
    kDebug(DBG_AREA) << "mkvcreator: found mkvextractbin from path: " << mkvextractBin << endl;

    fileinfo.seconds=0;
    fileinfo.fps=0;
    tmpdir=new KTempDir();
    if(tmpdir->name().isNull() ) return false;
    kDebug(DBG_AREA) << "videopreview: using temp directory " << tmpdir->name() << endl;

    rand=new KRandomSequence(QDateTime::currentDateTime().toTime_t());
    mplayerprocess=new QProcess();
    int flags=0;
    KUrl furl(path);
    kDebug(DBG_AREA) << "videopreview: url=" << furl << "; local:" << furl.isLocalFile() << endl;
    fileinfo.towidth=width;
    fileinfo.toheight=height;
    QPixmap pix;
//    if(furl.isLocalFile())
//    {
    flags=framerandom;
    QStringList args;
    args << playerBin << QString("\"" + path + "\"") << "-nocache" << "-identify" << "-vo" << "null" << "-frames" << "0"/* << "-nosound" */<< "-ao" << "null";
    args+= customargs;

    kDebug(DBG_AREA) << "videopreview: starting process: --_" << " " << args.join(" ") << "_--\n";
    if (! startAndWaitProcess(args) ) return NULL;

    QString information=QString(mplayerprocess->readAllStandardOutput() );
//     kDebug(DBG_AREA) << "videopreview: output from process: " << information << endl;
    QRegExp findInfos("ID_VIDEO_FPS=([\\d]*).*ID_LENGTH=([\\d]*).*");
    if(findInfos.indexIn( information) == -1 )
    {
        kDebug(DBG_AREA) << "videopreview: No information found, exiting\n";
        return NULL;
    }
    fileinfo.seconds =findInfos.cap(2).toInt();
    fileinfo.fps=findInfos.cap(1).toInt();
   
    kDebug(DBG_AREA) << "videopreview: find length=" << fileinfo.seconds << ", fps=" << fileinfo.fps << endl;
/*    } else
    {
        flags=frameend;
    }*/
#define LASTTRY 3
    for(int i=0; i<=LASTTRY; i++)
    {
        kDebug(DBG_AREA) << "videopreview: try " << i << endl;
        pix=getFrame(path, ((i<LASTTRY) ? flags : framestart ) );
        if(!pix.isNull()) {
            uint variance=imageVariance(pix.toImage()/*.bits(),( (width+ 7) & ~0x7), width, height, 1 */);
            kDebug(DBG_AREA) << "videopreview: " << QFileInfo(path).fileName() << " frame variance: " << variance << "; " <<
                    ((variance<=40 && ( i!=LASTTRY-1))? "!!!DROPPING!!!" : "GOOD :-)" ) << endl;
            if(variance>40 || i==LASTTRY-1 ) break;
        }
    }
    if(pix.isNull() )
    {
        tryUnlink(tmpdir);
        return false;
    }
    /** From videocreator.cpp - xine_artsplugin
    Copyright (C) 2002 Simon MacMullen
    Copyright (C) 2003 Ewald Snel <ewald@rambo.its.tudelft.nl>
     * */
//     QPixmap pix( createThumbnail( &frame, width, height ) );
//#ifdef STRIPS_SUPPORT
    if(cfg->createStrips() ) {
        QPainter painter( &pix );
        QPixmap sprocket;

        kDebug(DBG_AREA) << "videopreview: using strip image sprocket: " << KStandardDirs::locate( "data", "videothumbnail/sprocket-small.png" ) << endl;
        if (pix.height() < 60)
            sprocket = QPixmap(KStandardDirs::locate( "data", "videothumbnail/sprocket-small.png" ));
        else if (pix.height() < 90)
            sprocket = QPixmap(KStandardDirs::locate( "data", "videothumbnail/sprocket-medium.png" ));
        else
            sprocket = QPixmap(KStandardDirs::locate( "data", "videothumbnail/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

    if(cfg->useMkvCover() && fi.suffix().trimmed().length() && !cfg->noextensions().filter(fi.suffix().trimmed(), Qt::CaseInsensitive).isEmpty() ) {
     
      QPixmap mkvpix;
      QStringList args;
      args << mkvextractBin << "attachments" << QString("\"" + path + "\"") << "4:cover.jpg";
     
      kDebug(DBG_AREA) << "mkvcreator: starting process: --_" << " " << args.join(" ") << "_--\n";
      if (! startAndWaitProcess(args) ) return NULL;
     
      mkvpix=getMkvCover(path);
      if(!mkvpix.isNull() )
   pix = mkvpix;
      else {
   tryUnlink(tmpdir);
   return false;
      }
    }
    img = pix.toImage();
   
    tryUnlink(tmpdir);
    return true;
}

void VideoPreview::tryUnlink(KTempDir *dir) {
    if(dir) dir->unlink();
}

QPixmap VideoPreview::getFrame(const QString &path, int flags)
{
    QStringList args;
    kDebug(DBG_AREA) << "videopreview: using flags " << flags << endl;
#define START ((fileinfo.seconds*15)/100)
#define END ((fileinfo.seconds*70)/100)
    args.clear();
    args << playerBin << "\"" + path + "\"";
    if(fileinfo.towidth>fileinfo.toheight) fileinfo.toheight=-2; else fileinfo.towidth=-2;
//     switch( flags ){
//         case random
//     }
    if( flags & framerandom )
    {
        kDebug(DBG_AREA) << "videopreview: framerandom\n";
        unsigned long start=(unsigned long)(START+(rand->getDouble() * (END - START) ) );
        args << "-ss" << QString::number( start )
                << "-frames" << "4";
    } else if (flags & frameend )
    {
        kDebug(DBG_AREA) << "videopreview: frameend\n";
        args << "-ss" << QString::number( fileinfo.seconds - 10 )
                << "-frames" << "4";
    } else if (flags & framestart)
    {
        kDebug(DBG_AREA) << "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" << QString::number( fileinfo.fps*10 );
    }
    KMD5 md5builder(path.toLatin1() );
    QString md5file=md5builder.hexDigest().data();
    QString tmpDirPath = tmpdir->name() + md5file + QDir::separator();
    args << "-nocache" << "-idx" /*@TODO check if it's too slow..*/ << "-ao" << "null"/*"-nosound" << */<< "-speed" << "99"  /*<< "-sstep" << "5"*/
            << "-vo" << QString("jpeg:outdir=%1").arg(tmpDirPath ) << "-vf" << QString("scale=%1:%2").arg(fileinfo.towidth).arg(fileinfo.toheight);
    args+=customargs;

    if (! startAndWaitProcess(args) ) return NULL;

    kDebug(DBG_AREA) << "videopreview: temp dir '" << tmpDirPath << "'\n";

    if (QDir(tmpDirPath ).entryList( QStringList("*.jpg") ).isEmpty() ) return false;

    QString lastframe=QDir(tmpDirPath ).entryList( QStringList("*.jpg") ).last();
    kDebug(DBG_AREA) << "videopreview: LastFrame==" << lastframe << endl;
    QPixmap retpix(tmpDirPath.append( lastframe ));
    return retpix;
}

QPixmap VideoPreview::getMkvCover(const QString &path)
{
  QStringList args;
  args.clear();
  args << mkvextractBin << "attachments" << "\"" + path + "\"";
 
  KMD5 md5builder(path.toLatin1() );
  QString md5file=md5builder.hexDigest().data();
  QString tmpDirPath = tmpdir->name() + md5file + QDir::separator();
  //    mkvextract attachments "Le convoyeur.mkv" 4:cover.jpg;
  args << QString("4:%1/cover.jpg").arg(tmpDirPath);
 
  if (! startAndWaitProcess(args) ) return NULL;
 
  kDebug(DBG_AREA) << "mkvcreator: temp dir '" << tmpDirPath << "'\n";
 
  if (QDir(tmpDirPath ).entryList( QStringList("*.jpg") ).isEmpty() ) return false;
 
  QString lastcover=QDir(tmpDirPath ).entryList( QStringList("*.jpg") ).last();
  kDebug(DBG_AREA) << "mkvcreator: LastCover==" << lastcover << endl;
  //  std::cout << "mkvcreator: LastCover==" << lastcover.toAscii().data() << std::endl;
  QPixmap retpix(tmpDirPath.append( lastcover ));
  return retpix;
}

ThumbCreator::Flags VideoPreview::flags() const
{
    return (Flags)(DrawFrame);
}


uint VideoPreview::imageVariance(QImage image )
{
    uint delta=0;
    uint avg=0;
    uint bytes=image.numBytes();
    uint STEPS=bytes/2;
    QVarLengthArray<uchar> pivot(STEPS);
    kDebug(DBG_AREA) << "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 "videopreview.moc"


J'ai également ajouté un peu de chose dans la méthode create à la fin pour prendre en compte cette nouvelle possibilité de récupérer l'image à l'intérieur du mkv. Et puis quelques petites modifications dans l'interface graphique pour rajouter un bouton pour activer ou non cette option. Mon problème, c'est que le code actuel ne fonctionne pas et que je ne sais pas pourquoi. Donc pour commencer je voudrais pouvoir débugguer mon code en vérifiant étape par étape et je fais ça habituellement en mettant des cout un peu partout. Ici, il semble qu'on utilise des kdebug mais je n'ai absolument pas compris comment ça fonctionne. Est ce que vous pourriez m'expliquer tout ceci ? Merci d'avance.
User avatar
morice.net
Registered Member
Posts
66
Karma
1
OS
Salut,

Dans VideoPreview::getMkvCover, tu fais un appel à VideoPreview::startAndWaitProcess. Or, dans cette fonction il y a cette ligne :
Code: Select all
mplayerprocess->start( args.join(" ") );

Je n’ai pas vérifié, mais je supposes que ça appelle mplayer avec les arguments fournis en paramètres. Donc dans ton cas tu appelles mplayer avec les arguments de mkvextract, ce qui doit moyennement plaire à mplayer qui doit renvoyer un code d’erreur.
Du coup, VideoPreview::startAndWaitProcess renvoie false et ta fonction VideoPreview::getMkvCover renvoie NULL car tu as cette ligne là :
Code: Select all
if (! startAndWaitProcess(args) ) return NULL;

Last edited by morice.net on Sun Aug 14, 2011 1:34 pm, edited 1 time in total.
pamputt
Registered Member
Posts
154
Karma
0
OS
En fait, tout le code relatif à mplayerprocess est présent dans la partie au-dessus. D'après ce que je comprends mplayerprocess est juste un objet QProcess et n'est pas directement lié à mplayer. Il s'appelle ainsi parce que dans le code initial de mplayerthumbs, il est utilisé pour traité mplayer. Mais d'après ce que je comprends c'est un process générique. Je vais peut-être aller demander de l'aide sur la partie anglophone de ce forum.
User avatar
morice.net
Registered Member
Posts
66
Karma
1
OS
Désolé, c'est un anonymous qui a répondu à ma place à cause d'une erreur de ma part. Bref, contrairement à sa réponse, je connais plutot bien les qDebug ou kDebug.

Il te suffit de faire un include de l'un ou l'autre :
Code: Select all
#include <QDebug>


Puis tu l'utilises de la manière suivante :
Code: Select all
qDebug() << "Ma variable =" << variable << "et tout ce que je veux";


Fais attention aux majuscules, même si elles respectent le format standard, au début on se trompe tout le temps :-)
pamputt
Registered Member
Posts
154
Karma
0
OS
Ok, mais mon problème c'est que je ne sais pas quoi faire après avec c'est qdebug. Comment est ce qu'on récupère techniquement les messages d'erreur ? Merci d'avance.
User avatar
morice.net
Registered Member
Posts
66
Karma
1
OS
Et bien, tu mets le message que tu veux genre "Message d'erreur" et tu lis dans le terminal ce qu'il écrit. Au moment où le programme execute la ligne du qDebug, ben le message s'affiche... ce ne sont pas simplement des messages d'erreurs d'ailleurs, tu peux mettre ce que tu veux !
pamputt
Registered Member
Posts
154
Karma
0
OS
En fait j'ai eu une réponse sur le forum anglophone, j'ai utilisé kdebugdialog pour voir quelques messages en console. Le problème c'est que je ne vois que les messages de mplayerthumbsconfig (quand je coche/décoche une case par exemple) mais absolument pas ceux relatifs à la génération des vignettes des icônes. Est ce que vous avez une idée sur la manière d'y accéder ?


Bookmarks



Who is online

Registered users: bancha, Bing [Bot], Evergrowing, Google [Bot], lockheed, mesutakcan