]> git.sesse.net Git - kdenlive/blob - src/projecttree/proxyclipjob.cpp
Display job status in clip tooltip
[kdenlive] / src / projecttree / proxyclipjob.cpp
1 /***************************************************************************
2  *                                                                         *
3  *   Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.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.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
19  ***************************************************************************/
20
21 #include "proxyclipjob.h"
22 #include "kdenlivesettings.h"
23 #include "kdenlivedoc.h"
24
25 #include <KDebug>
26 #include <KLocale>
27
28 ProxyJob::ProxyJob(CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(PROXYJOB, cType, id, parameters),
29     m_jobDuration(0),
30     m_isFfmpegJob(true)
31 {
32     description = i18n("proxy");
33     m_dest = parameters.at(0);
34     m_src = parameters.at(1);
35     m_exif = parameters.at(2).toInt();
36     m_proxyParams = parameters.at(3);
37     m_renderWidth = parameters.at(4).toInt();
38     m_renderHeight = parameters.at(5).toInt();
39 }
40
41 QProcess *ProxyJob::startJob(bool *ok)
42 {
43     // Special case: playlist clips (.mlt or .kdenlive project files)
44     m_jobDuration = 0;
45     if (clipType == PLAYLIST) {
46         // change FFmpeg params to MLT format
47         m_isFfmpegJob = false;
48         QStringList mltParameters;
49                 mltParameters << m_src;
50                 mltParameters << "-consumer" << "avformat:" + m_dest;
51                 QStringList params = m_proxyParams.split('-', QString::SkipEmptyParts);
52                 
53                 foreach(QString s, params) {
54                     s = s.simplified();
55                     if (s.count(' ') == 0) {
56                         s.append("=1");
57                     }
58                     else s.replace(' ', '=');
59                     mltParameters << s;
60                 }
61         
62             mltParameters.append(QString("real_time=-%1").arg(KdenliveSettings::mltthreads()));
63
64             //TODO: currently, when rendering an xml file through melt, the display ration is lost, so we enforce it manualy
65             double display_ratio = KdenliveDoc::getDisplayRatio(m_src);
66             mltParameters << "aspect=" + QString::number(display_ratio);
67             
68             // Ask for progress reporting
69             mltParameters << "progress=1";
70
71             m_jobProcess = new QProcess;
72             m_jobProcess->setProcessChannelMode(QProcess::MergedChannels);
73             m_jobProcess->start(KdenliveSettings::rendererpath(), mltParameters);
74             m_jobProcess->waitForStarted();
75             return m_jobProcess;
76     }
77     else if (clipType == IMAGE) {
78         m_isFfmpegJob = false;
79         // Image proxy
80         QImage i(m_src);
81         if (i.isNull()) {
82             *ok = false;
83             return NULL;
84         }
85         
86         QImage proxy;
87         // Images are scaled to profile size. 
88         //TODO: Make it be configurable?
89         if (i.width() > i.height()) proxy = i.scaledToWidth(m_renderWidth);
90         else proxy = i.scaledToHeight(m_renderHeight);
91         if (m_exif > 1) {
92             // Rotate image according to exif data
93             QImage processed;
94             QMatrix matrix;
95
96             switch ( m_exif ) {
97                 case 2:
98                     matrix.scale( -1, 1 );
99                     break;
100                 case 3:
101                     matrix.rotate( 180 );
102                     break;
103                 case 4:
104                     matrix.scale( 1, -1 );
105                     break;
106                 case 5:
107                     matrix.rotate( 270 );
108                     matrix.scale( -1, 1 );
109                     break;
110                 case 6:
111                     matrix.rotate( 90 );
112                     break;
113                 case 7:
114                     matrix.rotate( 90 );
115                     matrix.scale( -1, 1 );
116                     break;
117                 case 8:
118                     matrix.rotate( 270 );
119                     break;
120             }
121             processed = proxy.transformed( matrix );
122             processed.save(m_dest);
123         }
124         else proxy.save(m_dest);
125         *ok = true;
126         return NULL;
127     }
128     else {
129         m_isFfmpegJob = true;
130         QStringList parameters;
131         parameters << "-i" << m_src;
132         QString params = m_proxyParams;
133         foreach(const QString &s, params.split(' '))
134             parameters << s;
135
136         // Make sure we don't block when proxy file already exists
137         parameters << "-y";
138         parameters << m_dest;
139         m_jobProcess = new QProcess;
140         m_jobProcess->setProcessChannelMode(QProcess::MergedChannels);
141         m_jobProcess->start("ffmpeg", parameters);
142         m_jobProcess->waitForStarted();
143         QString log = m_jobProcess->readAll();
144         if (!log.isEmpty()) m_errorMessage.append(log + '\n');
145         return m_jobProcess;
146     }
147 }
148
149 int ProxyJob::processLogInfo()
150 {
151     if (!m_jobProcess) return -1;
152     QString log = m_jobProcess->readAll();
153     if (!log.isEmpty()) m_errorMessage.append(log + '\n');
154     int progress;
155     if (m_isFfmpegJob) {
156         // Parse FFmpeg output
157         if (m_jobDuration == 0) {
158             if (log.contains("Duration:")) {
159                 QString data = log.section("Duration:", 1, 1).section(',', 0, 0).simplified();
160                 QStringList numbers = data.split(':');
161                 m_jobDuration = (int) (numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble());
162             }
163         }
164         else if (log.contains("time=")) {
165             QString time = log.section("time=", 1, 1).simplified().section(' ', 0, 0);
166             if (time.contains(':')) {
167                 QStringList numbers = time.split(':');
168                 progress = numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble();
169             }
170             else progress = (int) time.toDouble();
171             return (int) (100.0 * progress / m_jobDuration);
172         }
173     }
174     else {
175         // Parse MLT output
176         if (log.contains("percentage:")) {
177             progress = log.section(':', -1).simplified().toInt();
178             return progress;
179         }
180     }
181     return -1;
182 }
183
184 ProxyJob::~ProxyJob()
185 {
186 }
187
188 const QString ProxyJob::destination() const
189 {
190     return m_dest;
191 }
192
193 stringMap ProxyJob::cancelProperties()
194 {
195     QMap <QString, QString> props;
196     props.insert("proxy", "-");
197     return props;
198 }
199
200 const QString ProxyJob::statusMessage(CLIPJOBSTATUS status)
201 {
202     QString statusInfo;
203     switch (status) {
204         case CREATINGJOB:
205             statusInfo = i18n("Creating proxy");
206             break;
207         case JOBWAITING:
208             statusInfo = i18n("Waiting - proxy");
209             break;
210         default:
211             break;
212     }
213     return statusInfo;
214 }
215