1 /*
2 * Cantata
3 *
4 * Copyright (c) 2011-2020 Craig Drummond <craig.p.drummond@gmail.com>
5 *
6 * ----
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 */
22
23 #include "transcodingjob.h"
24 #include "device.h"
25 #include <QStringList>
26
TranscodingJob(const Encoders::Encoder & enc,int val,const QString & src,const QString & dest,const DeviceOptions & d,int co,const Song & s)27 TranscodingJob::TranscodingJob(const Encoders::Encoder &enc, int val, const QString &src, const QString &dest, const DeviceOptions &d, int co, const Song &s)
28 : CopyJob(src, dest, d, co, s)
29 , encoder(enc)
30 , value(val)
31 , process(nullptr)
32 , duration(-1)
33 {
34 }
35
~TranscodingJob()36 TranscodingJob::~TranscodingJob()
37 {
38 delete process;
39 }
40
run()41 void TranscodingJob::run()
42 {
43 QString src(updateTagsLocal());
44 if (src.isEmpty()) {
45 return;
46 }
47
48 if (stopRequested) {
49 emit result(Device::Cancelled);
50 } else {
51 QStringList parameters=encoder.params(value, src, destFile);
52 process = new QProcess;
53 process->setProcessChannelMode(QProcess::MergedChannels);
54 process->setReadChannel(QProcess::StandardOutput);
55 connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
56 connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
57 QString cmd=parameters.takeFirst();
58 process->start(cmd, parameters);
59 }
60 }
61
stop()62 void TranscodingJob::stop()
63 {
64 if (process) {
65 process->close();
66 process->deleteLater();
67 process=nullptr;
68 emit result(Device::Cancelled);
69 }
70 }
71
finished(int exitCode,QProcess::ExitStatus exitStatus)72 void TranscodingJob::finished(int exitCode, QProcess::ExitStatus exitStatus)
73 {
74 Q_UNUSED(exitStatus)
75 if (!process) {
76 return;
77 }
78 if (stopRequested) {
79 emit result(Device::Cancelled);
80 return;
81 }
82 if (0==exitCode) {
83 updateTagsDest();
84 copyCover(srcFile);
85 }
86 emit result(0==exitCode ? Device::Ok : Device::TranscodeFailed);
87 }
88
processOutput()89 void TranscodingJob::processOutput()
90 {
91 if (stopRequested) {
92 emit result(Device::Cancelled);
93 return;
94 }
95 QString output = process->readAllStandardOutput().data();
96 if(output.simplified().isEmpty()) {
97 return;
98 }
99
100 if (!data.isEmpty()) {
101 output=data+output;
102 }
103 if (-1==duration) {
104 duration = computeDuration(output);
105 }
106
107 if (duration>0) {
108 qint64 prog = computeProgress(output);
109 if (prog>-1) {
110 setPercent((prog*100)/duration);
111 }
112 }
113
114 if (!output.endsWith('\n') && !output.endsWith('\r')) {
115 int last=output.lastIndexOf('\n');
116 if (-1==last) {
117 last=output.lastIndexOf('\r');
118 }
119 if (last>-1) {
120 data=output.mid(last+1);
121 } else {
122 data=output;
123 }
124 }
125 }
126
computeDuration(const QString & output)127 inline qint64 TranscodingJob::computeDuration(const QString &output)
128 {
129 //We match something like "Duration: 00:04:33.60"
130 QRegExp matchDuration("Duration: (\\d{2,}):(\\d{2}):(\\d{2})\\.(\\d{2})");
131
132 if(output.contains(matchDuration)) {
133 //duration is in csec
134 return matchDuration.cap(1).toLong() * 60 * 60 * 100 +
135 matchDuration.cap(2).toInt() * 60 * 100 +
136 matchDuration.cap(3).toInt() * 100 +
137 matchDuration.cap(4).toInt();
138 } else {
139 return -1;
140 }
141 }
142
computeProgress(const QString & output)143 inline qint64 TranscodingJob::computeProgress(const QString &output)
144 {
145 //Output is like size= 323kB time=18.10 bitrate= 146.0kbits/s
146 //We're going to use the "time" column, which counts the elapsed time in seconds.
147 QRegExp matchTime("time=(\\d+)\\.(\\d{2})");
148
149 if(output.contains(matchTime)) {
150 return matchTime.cap(1).toLong() * 100 +
151 matchTime.cap(2).toInt();
152 } else {
153 return -1;
154 }
155 }
156
157 #include "moc_transcodingjob.cpp"
158