]> git.sesse.net Git - kdenlive/blob - src/projecttree/proxyclipjob.cpp
Some progress on clip jobs
[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(JOBTYPE type, CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(type, 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(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         return m_jobProcess;
144     }
145 }
146
147 int ProxyJob::processLogInfo()
148 {
149     if (!m_jobProcess) return -1;
150     QString log = m_jobProcess->readAll();
151     int progress;
152     if (m_isFfmpegJob) {
153         // Parse FFmpeg output
154         if (m_jobDuration == 0) {
155             if (log.contains("Duration:")) {
156                 QString data = log.section("Duration:", 1, 1).section(',', 0, 0).simplified();
157                 QStringList numbers = data.split(':');
158                 m_jobDuration = (int) (numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble());
159             }
160         }
161         else if (log.contains("time=")) {
162             QString time = log.section("time=", 1, 1).simplified().section(' ', 0, 0);
163             if (time.contains(':')) {
164                 QStringList numbers = time.split(':');
165                 progress = numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble();
166             }
167             else progress = (int) time.toDouble();
168             return (int) (100.0 * progress / m_jobDuration);
169         }
170     }
171     else {
172         // Parse MLT output
173         if (log.contains("percentage:")) {
174             progress = log.section(':', -1).simplified().toInt();
175             return progress;
176         }
177     }
178     return -1;
179 }
180
181 ProxyJob::~ProxyJob()
182 {
183 }
184
185 const QString ProxyJob::destination() const
186 {
187     return m_dest;
188 }
189
190 stringMap ProxyJob::cancelProperties()
191 {
192     QMap <QString, QString> props;
193     props.insert("proxy", "-");
194     return props;
195 }
196
197