]> git.sesse.net Git - kdenlive/blobdiff - src/projecttree/proxyclipjob.cpp
const'ref. REmove not necessary virtual keyword. Fix indent.
[kdenlive] / src / projecttree / proxyclipjob.cpp
index dd0171a4d071983180c22b5cb2ce5226a6974e7d..1049cfb3ec4627989d0df6107d935b3f9710b6da 100644 (file)
 #include "proxyclipjob.h"
 #include "kdenlivesettings.h"
 #include "kdenlivedoc.h"
+#include <QProcess>
+
 
 #include <KDebug>
 #include <KLocale>
 
-ProxyJob::ProxyJob(JOBTYPE type, CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(type, cType, id, parameters)
+ProxyJob::ProxyJob(CLIPTYPE cType, const QString &id, const QStringList& parameters)
+    : AbstractClipJob(PROXYJOB, cType, id, parameters),
+      m_jobDuration(0),
+      m_isFfmpegJob(true)
 {
+    m_jobStatus = JOBWAITING;
     description = i18n("proxy");
     m_dest = parameters.at(0);
     m_src = parameters.at(1);
@@ -34,49 +40,58 @@ ProxyJob::ProxyJob(JOBTYPE type, CLIPTYPE cType, const QString &id, QStringList
     m_proxyParams = parameters.at(3);
     m_renderWidth = parameters.at(4).toInt();
     m_renderHeight = parameters.at(5).toInt();
+    replaceClip = true;
 }
 
-QProcess *ProxyJob::startJob(bool *ok)
+void ProxyJob::startJob()
 {
     // Special case: playlist clips (.mlt or .kdenlive project files)
+    m_jobDuration = 0;
     if (clipType == PLAYLIST) {
         // change FFmpeg params to MLT format
+        m_isFfmpegJob = false;
         QStringList mltParameters;
-                mltParameters << m_src;
-                mltParameters << "-consumer" << "avformat:" + m_dest;
-                QStringList params = m_proxyParams.split('-', QString::SkipEmptyParts);
-                
-                foreach(QString s, params) {
-                    s = s.simplified();
-                    if (s.count(' ') == 0) {
-                        s.append("=1");
-                    }
-                    else s.replace(' ', '=');
-                    mltParameters << s;
-                }
+        mltParameters << m_src;
+        mltParameters << "-consumer" << "avformat:" + m_dest;
+        QStringList params = m_proxyParams.split('-', QString::SkipEmptyParts);
+
+        foreach(const QString &s, params) {
+            QString t = s.simplified();
+            if (t.count(' ') == 0) {
+                t.append("=1");
+            }
+            else t.replace(' ', '=');
+            mltParameters << t;
+        }
         
-            mltParameters.append(QString("real_time=-%1").arg(KdenliveSettings::mltthreads()));
+        mltParameters.append(QString("real_time=-%1").arg(KdenliveSettings::mltthreads()));
 
-            //TODO: currently, when rendering an xml file through melt, the display ration is lost, so we enforce it manualy
-            double display_ratio = KdenliveDoc::getDisplayRatio(m_src);
-            mltParameters << "aspect=" + QString::number(display_ratio);
+        //TODO: currently, when rendering an xml file through melt, the display ration is lost, so we enforce it manualy
+        double display_ratio;
+        if (m_src.startsWith("consumer:")) display_ratio = KdenliveDoc::getDisplayRatio(m_src.section(":", 1));
+        else display_ratio = KdenliveDoc::getDisplayRatio(m_src);
+        mltParameters << "aspect=" + QLocale().toString(display_ratio);
 
-           QProcess *myProcess = new QProcess;
-            myProcess->setProcessChannelMode(QProcess::MergedChannels);
-            myProcess->start(KdenliveSettings::rendererpath(), mltParameters);
-            myProcess->waitForStarted();
-           return myProcess;
+        // Ask for progress reporting
+        mltParameters << "progress=1";
+
+        m_jobProcess = new QProcess;
+        m_jobProcess->setProcessChannelMode(QProcess::MergedChannels);
+        m_jobProcess->start(KdenliveSettings::rendererpath(), mltParameters);
+        m_jobProcess->waitForStarted();
     }
     else if (clipType == IMAGE) {
+        m_isFfmpegJob = false;
         // Image proxy
         QImage i(m_src);
         if (i.isNull()) {
-           *ok = false;
-           return NULL;
-       }
-       
+            m_errorMessage.append(i18n("Cannot load image %1.", m_src));
+            setStatus(JOBCRASHED);
+            return;
+        }
+
         QImage proxy;
-        // Images are scaled to profile size. 
+        // Images are scaled to profile size.
         //TODO: Make it be configurable?
         if (i.width() > i.height()) proxy = i.scaledToWidth(m_renderWidth);
         else proxy = i.scaledToHeight(m_renderHeight);
@@ -86,52 +101,121 @@ QProcess *ProxyJob::startJob(bool *ok)
             QMatrix matrix;
 
             switch ( m_exif ) {
-                case 2:
-                   matrix.scale( -1, 1 );
-                    break;
-                case 3:
-                   matrix.rotate( 180 );
-                    break;
-                case 4:
-                   matrix.scale( 1, -1 );
-                    break;
-                case 5:
-                   matrix.rotate( 270 );
-                    matrix.scale( -1, 1 );
-                    break;
-                case 6:
-                   matrix.rotate( 90 );
-                    break;
-                case 7:
-                   matrix.rotate( 90 );
-                    matrix.scale( -1, 1 );
-                    break;
-                case 8:
-                   matrix.rotate( 270 );
-                    break;
+            case 2:
+                matrix.scale( -1, 1 );
+                break;
+            case 3:
+                matrix.rotate( 180 );
+                break;
+            case 4:
+                matrix.scale( 1, -1 );
+                break;
+            case 5:
+                matrix.rotate( 270 );
+                matrix.scale( -1, 1 );
+                break;
+            case 6:
+                matrix.rotate( 90 );
+                break;
+            case 7:
+                matrix.rotate( 90 );
+                matrix.scale( -1, 1 );
+                break;
+            case 8:
+                matrix.rotate( 270 );
+                break;
             }
             processed = proxy.transformed( matrix );
             processed.save(m_dest);
+        } else {
+            proxy.save(m_dest);
         }
-        else proxy.save(m_dest);
-       *ok = true;
-       return NULL;
-    }
-    else {
-       QStringList parameters;
+        setStatus(JOBDONE);
+        return;
+    } else {
+        m_isFfmpegJob = true;
+        QStringList parameters;
         parameters << "-i" << m_src;
         QString params = m_proxyParams;
-        foreach(QString s, params.split(' '))
-        parameters << s;
+        foreach(const QString &s, params.split(' '))
+            parameters << s;
 
         // Make sure we don't block when proxy file already exists
         parameters << "-y";
         parameters << m_dest;
-        QProcess *myProcess = new QProcess;
-        myProcess->setProcessChannelMode(QProcess::MergedChannels);
-        myProcess->start("ffmpeg", parameters);
-        myProcess->waitForStarted();
-       return myProcess;
+        m_jobProcess = new QProcess;
+        m_jobProcess->setProcessChannelMode(QProcess::MergedChannels);
+        m_jobProcess->start(KdenliveSettings::ffmpegpath(), parameters, QIODevice::ReadOnly);
+        m_jobProcess->waitForStarted();
+    }
+    while (m_jobProcess->state() != QProcess::NotRunning) {
+        processLogInfo();
+        if (m_jobStatus == JOBABORTED) {
+            emit cancelRunningJob(m_clipId, cancelProperties());
+            m_jobProcess->close();
+            m_jobProcess->waitForFinished();
+            QFile::remove(m_dest);
+        }
+        m_jobProcess->waitForFinished(400);
+    }
+    
+    if (m_jobStatus != JOBABORTED) {
+        int result = m_jobProcess->exitStatus();
+        if (result == QProcess::NormalExit) {
+            if (QFileInfo(m_dest).size() == 0) {
+                // File was not created
+                processLogInfo();
+                m_errorMessage.append(i18n("Failed to create proxy clip."));
+                setStatus(JOBCRASHED);
+            }
+            else setStatus(JOBDONE);
+        }
+        else if (result == QProcess::CrashExit) {
+            // Proxy process crashed
+            QFile::remove(m_dest);
+            setStatus(JOBCRASHED);
+        }
+    }
+    
+    delete m_jobProcess;
+    return;
+}
+
+void ProxyJob::processLogInfo()
+{
+    if (!m_jobProcess || m_jobStatus == JOBABORTED) return;
+    QString log = m_jobProcess->readAll();
+    if (!log.isEmpty())
+        m_logDetails.append(log + '\n');
+    else
+        return;
+
+    int progress;
+    if (m_isFfmpegJob) {
+        // Parse FFmpeg output
+        if (m_jobDuration == 0) {
+            if (log.contains("Duration:")) {
+                QString data = log.section("Duration:", 1, 1).section(',', 0, 0).simplified();
+                QStringList numbers = data.split(':');
+                m_jobDuration = (int) (numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble());
+            }
+        }
+        else if (log.contains("time=")) {
+            QString time = log.section("time=", 1, 1).simplified().section(' ', 0, 0);
+            if (time.contains(':')) {
+                QStringList numbers = time.split(':');
+                progress = numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble();
+            }
+            else progress = (int) time.toDouble();
+            emit jobProgress(m_clipId, (int) (100.0 * progress / m_jobDuration), jobType);
+        }
+    }
+    else {
+        // Parse MLT output
+        if (log.contains("percentage:")) {
+            progress = log.section("percentage:", 1).simplified().section(' ', 0, 0).toInt();
+            emit jobProgress(m_clipId, progress, jobType);
+        }
     }
 }
 
@@ -151,4 +235,21 @@ stringMap ProxyJob::cancelProperties()
     return props;
 }
 
+const QString ProxyJob::statusMessage()
+{
+    QString statusInfo;
+    switch (m_jobStatus) {
+    case JOBWORKING:
+        statusInfo = i18n("Creating proxy");
+        break;
+    case JOBWAITING:
+        statusInfo = i18n("Waiting - proxy");
+        break;
+    default:
+        break;
+    }
+    return statusInfo;
+}
+
 
+#include "proxyclipjob.moc"