Commit fc6c822f authored by Vincent Pinon's avatar Vincent Pinon
Browse files

more progress info during render

parent 48b183a2
Pipeline #31386 passed with stage
in 37 minutes and 5 seconds
......@@ -43,10 +43,12 @@ RenderJob::RenderJob(const QString &render, const QString &scenelist, const QStr
, m_jobUiserver(nullptr)
, m_kdenliveinterface(nullptr)
, m_usekuiserver(true)
, m_logfile(scenelist.startsWith(QStringLiteral("xml:")) ? scenelist.section(QLatin1Char(':'), 1).section(QLatin1Char('?'), 0, -2) + QStringLiteral(".txt") : scenelist + QStringLiteral(".txt"))
, m_logfile(target + QStringLiteral(".log"))
, m_erase(scenelist.startsWith(QDir::tempPath()) || scenelist.startsWith(QString("xml:%2").arg(QDir::tempPath())))
, m_seconds(0)
, m_frame(0)
, m_frame(in)
, m_framein(in)
, m_frameout(out)
, m_pid(pid)
, m_dualpass(false)
{
......@@ -93,9 +95,7 @@ void RenderJob::slotAbort()
m_renderProcess->kill();
if (m_kdenliveinterface) {
m_dbusargs[1] = -3;
m_dbusargs.append(QString());
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingFinished"), m_dbusargs);
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingFinished"), {m_dest, -3, QString()});
}
if (m_jobUiserver) {
m_jobUiserver->call(QStringLiteral("terminate"), QString());
......@@ -115,41 +115,46 @@ void RenderJob::receivedStderr()
QString result = QString::fromLocal8Bit(m_renderProcess->readAllStandardError()).simplified();
if (!result.startsWith(QLatin1String("Current Frame"))) {
m_errorMessage.append(result + QStringLiteral("<br>"));
m_logstream << result;
} else {
m_logstream << "melt: " << result << "\n";
int pro = result.section(QLatin1Char(' '), -1).toInt();
if (pro <= m_progress || pro <= 0 || pro > 100) {
int progress = result.section(QLatin1Char(' '), -1).toInt();
int frame = result.section(QLatin1Char(','), 1).section(QLatin1Char(' '), -1).toInt();
if (progress <= m_progress || progress <= 0 || progress > 100) {
return;
}
m_progress = pro;
m_progress = progress;
if (m_args.contains(QStringLiteral("pass=1"))) {
m_progress /= 2.0;
} else if (m_args.contains(QStringLiteral("pass=2"))) {
m_progress = 50 + m_progress / 2.0;
}
int frame = result.section(QLatin1Char(','), 1).section(QLatin1Char(' '), -1).toInt();
if ((m_kdenliveinterface != nullptr) && m_kdenliveinterface->isValid()) {
m_dbusargs[1] = m_progress;
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingProgress"), m_dbusargs);
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingProgress"), {m_dest, m_progress, frame});
}
qint64 elapsedTime = m_startTime.secsTo(QDateTime::currentDateTime());
if (elapsedTime == m_seconds) {
return;
}
int speed = (frame - m_frame) / (elapsedTime - m_seconds);
if (m_jobUiserver) {
m_jobUiserver->call(QStringLiteral("setPercent"), (uint)m_progress);
int seconds = m_startTime.secsTo(QTime::currentTime());
if (seconds < 0) {
// 1 day offset, add seconds in a day
seconds += 86400;
qint64 remaining = elapsedTime * (100 - progress) / progress;
int days = int(remaining / 86400);
int remainingSecs = int(remaining % 86400);
QTime when = QTime(0, 0, 0, 0).addSecs(remainingSecs);
QString est = tr("Remaining time ");
if (days > 0) {
est.append(tr("%n day(s) ", "", days));
}
seconds = (int)(seconds * (100 - m_progress) / m_progress);
if (seconds == m_seconds) {
return;
}
m_jobUiserver->call(QStringLiteral("setDescriptionField"), (uint)0, QString(),
tr("Remaining time: ") + QTime(0, 0, 0).addSecs(seconds).toString(QStringLiteral("hh:mm:ss")));
// m_jobUiserver->call(QStringLiteral("setSpeed"), (frame - m_frame) / (seconds - m_seconds));
// m_jobUiserver->call("setSpeed", (frame - m_frame) / (seconds - m_seconds));
m_frame = frame;
m_seconds = seconds;
est.append(when.toString(QStringLiteral("hh:mm:ss")));
m_jobUiserver->call(QStringLiteral("setPercent"), uint(m_progress));
m_jobUiserver->call(QStringLiteral("setDescriptionField"), 0, QString(), est);
m_jobUiserver->call(QStringLiteral("setProcessedAmount"), qulonglong(frame - m_framein), tr("frames"));
m_jobUiserver->call(QStringLiteral("setSpeed"), qulonglong(speed));
}
m_seconds = elapsedTime;
m_frame = frame;
m_logstream << QStringLiteral("%1\t%2\t%3\t%4\n").arg(m_seconds).arg(m_frame).arg(m_progress).arg(speed);
}
}
......@@ -181,12 +186,13 @@ void RenderJob::start()
QString dbusView = QStringLiteral("org.kde.JobViewV2");
m_jobUiserver = new QDBusInterface(QStringLiteral("org.kde.JobViewServer"), reply, dbusView);
if ((m_jobUiserver != nullptr) && m_jobUiserver->isValid()) {
m_startTime = QTime::currentTime();
m_startTime = QDateTime::currentDateTime();
if (!m_args.contains(QStringLiteral("pass=2"))) {
m_jobUiserver->call(QStringLiteral("setPercent"), (uint)0);
}
m_jobUiserver->call(QStringLiteral("setInfoMessage"), tr("Rendering %1").arg(QFileInfo(m_dest).fileName()));
m_jobUiserver->call(QStringLiteral("setTotalAmount"), m_frameout);
QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.JobViewServer"), reply, dbusView, QStringLiteral("cancelRequested"), this,
SLOT(slotAbort()));
}
......@@ -205,7 +211,6 @@ void RenderJob::start()
// Because of the logging, we connect to stderr in all cases.
connect(m_renderProcess, &QProcess::readyReadStandardError, this, &RenderJob::receivedStderr);
m_renderProcess->start(m_prog, m_args);
qDebug() << "Started render process: " << m_prog << ' ' << m_args.join(QLatin1Char(' '));
m_logstream << "Started render process: " << m_prog << ' ' << m_args.join(QLatin1Char(' ')) << "\n";
m_logstream.flush();
}
......@@ -227,7 +232,6 @@ void RenderJob::initKdenliveDbusInterface()
break;
}
}
m_dbusargs.clear();
if (kdenliveId.isEmpty()) {
return;
}
......@@ -235,10 +239,8 @@ void RenderJob::initKdenliveDbusInterface()
new QDBusInterface(kdenliveId, QStringLiteral("/kdenlive/MainWindow_1"), QStringLiteral("org.kde.kdenlive.rendering"), connection, this);
if (m_kdenliveinterface) {
m_dbusargs.append(m_dest);
m_dbusargs.append((int)0);
if (!m_args.contains(QStringLiteral("pass=2"))) {
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingProgress"), m_dbusargs);
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingProgress"), {m_dest, 0, 0});
}
connect(m_kdenliveinterface, SIGNAL(abortRenderJob(QString)), this, SLOT(slotAbort(QString)));
}
......@@ -260,9 +262,7 @@ void RenderJob::slotIsOver(QProcess::ExitStatus status, bool isWritable)
if (!isWritable) {
QString error = tr("Cannot write to %1, check permissions.").arg(m_dest);
if (m_kdenliveinterface) {
m_dbusargs[1] = (int)-2;
m_dbusargs.append(error);
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingFinished"), m_dbusargs);
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingFinished"), {m_dest, -2, error});
}
QProcess::startDetached(QStringLiteral("kdialog"), {QStringLiteral("--error"), error});
m_logstream << error << "\n";
......@@ -275,21 +275,20 @@ void RenderJob::slotIsOver(QProcess::ExitStatus status, bool isWritable)
if (status == QProcess::CrashExit || m_renderProcess->error() != QProcess::UnknownError || m_renderProcess->exitCode() != 0) {
// rendering crashed
if (m_kdenliveinterface) {
m_dbusargs[1] = (int)-2;
m_dbusargs.append(m_errorMessage);
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingFinished"), m_dbusargs);
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingFinished"), {m_dest, -2, m_errorMessage});
}
QStringList args;
QString error = tr("Rendering of %1 aborted, resulting video will probably be corrupted.").arg(m_dest);
if (m_frame > 0) {
error += QLatin1Char('\n') + tr("Frame: ") + m_frame;
}
args << QStringLiteral("--error") << error;
m_logstream << error << "\n";
QProcess::startDetached(QStringLiteral("kdialog"), args);
emit renderingFinished();
} else {
if (!m_dualpass && (m_kdenliveinterface != nullptr)) {
m_dbusargs[1] = (int)-1;
m_dbusargs.append(QString());
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingFinished"), m_dbusargs);
m_kdenliveinterface->callWithArgumentList(QDBus::NoBlock, QStringLiteral("setRenderingFinished"), {m_dest, -1, QString()});
}
m_logstream << "Rendering of " << m_dest << " finished" << "\n";
if (!m_dualpass && m_player.length() > 3 && m_player.contains(QLatin1Char(' '))) {
......
......@@ -23,7 +23,7 @@
#include <QDBusInterface>
#include <QObject>
#include <QProcess>
#include <QTime>
#include <QDateTime>
#include <QFile>
// Testing
#include <QTextStream>
......@@ -60,13 +60,15 @@ private:
bool m_erase;
int m_seconds;
int m_frame;
int m_framein;
int m_frameout;
/** @brief The process id of the Kdenlive instance, used to get the dbus service. */
int m_pid;
bool m_dualpass;
QProcess *m_renderProcess;
QString m_errorMessage;
QList<QVariant> m_dbusargs;
QTime m_startTime;
QDateTime m_startTime;
QStringList m_args;
/** @brief Used to write to the log file. */
QTextStream m_logstream;
......
......@@ -91,10 +91,14 @@ enum {
};
// Render job roles
const int ParametersRole = Qt::UserRole + 1;
const int TimeRole = Qt::UserRole + 2;
const int ProgressRole = Qt::UserRole + 3;
const int ExtraInfoRole = Qt::UserRole + 5;
enum {
ParametersRole = Qt::UserRole + 1,
StartTimeRole,
ProgressRole,
ExtraInfoRole = ProgressRole + 2, // vpinon: don't understand why, else spurious message displayed
LastTimeRole,
LastFrameRole
};
// Running job status
enum JOBSTATUS { WAITINGJOB = 0, STARTINGJOB, RUNNINGJOB, FINISHEDJOB, FAILEDJOB, ABORTEDJOB };
......@@ -1073,7 +1077,7 @@ void RenderWidget::focusFirstVisibleItem(const QString &profile)
}
}
}
if (item) {
if (item && item->parent()) {
m_view.formats->setCurrentItem(item);
item->parent()->setExpanded(true);
refreshParams();
......@@ -1624,7 +1628,10 @@ void RenderWidget::generateRenderFiles(QDomDocument doc, const QString &playlist
QStringList argsJob = {KdenliveSettings::rendererpath(), playlistPath, renderedFile,
QStringLiteral("-pid:%1").arg(QCoreApplication::applicationPid())};
renderItem->setData(1, ParametersRole, argsJob);
renderItem->setData(1, TimeRole, QDateTime::currentDateTime());
QDateTime t = QDateTime::currentDateTime();
renderItem->setData(1, StartTimeRole, t);
renderItem->setData(1, LastTimeRole, t);
renderItem->setData(1, LastFrameRole, in);
if (!exportAudio) {
renderItem->setData(1, ExtraInfoRole, i18n("Video without audio track"));
} else {
......@@ -1643,7 +1650,10 @@ void RenderWidget::generateRenderFiles(QDomDocument doc, const QString &playlist
QList<RenderJobItem *> jobList;
for (const QString &pl : qAsConst(playlists)) {
renderItem = new RenderJobItem(m_view.running_jobs, QStringList() << QString() << renderedFile);
renderItem->setData(1, TimeRole, QDateTime::currentDateTime());
QDateTime t = QDateTime::currentDateTime();
renderItem->setData(1, StartTimeRole, t);
renderItem->setData(1, LastTimeRole, t);
renderItem->setData(1, LastFrameRole, in);
QStringList argsJob = {KdenliveSettings::rendererpath(), pl, renderedFile, QStringLiteral("-pid:%1").arg(QCoreApplication::applicationPid())};
renderItem->setData(1, ParametersRole, argsJob);
qDebug() << "* CREATED JOB WITH ARGS: " << argsJob;
......@@ -1718,7 +1728,9 @@ void RenderWidget::checkRenderStatus()
// Find first waiting job
while (item != nullptr) {
if (item->status() == WAITINGJOB) {
item->setData(1, TimeRole, QDateTime::currentDateTime());
QDateTime t = QDateTime::currentDateTime();
item->setData(1, StartTimeRole, t);
item->setData(1, LastTimeRole, t);
waitingJob = true;
startRendering(item);
// Check for 2 pass encoding
......@@ -2479,7 +2491,7 @@ void RenderWidget::parseFile(const QString &exportFile, bool editable)
}
}
void RenderWidget::setRenderJob(const QString &dest, int progress)
void RenderWidget::setRenderJob(const QString &dest, int progress, int frame)
{
RenderJobItem *item;
QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1);
......@@ -2495,20 +2507,28 @@ void RenderWidget::setRenderJob(const QString &dest, int progress)
item->setStatus(RUNNINGJOB);
if (progress == 0) {
item->setIcon(0, QIcon::fromTheme(QStringLiteral("media-record")));
item->setData(1, TimeRole, QDateTime::currentDateTime());
slotCheckJob();
} else {
QDateTime startTime = item->data(1, TimeRole).toDateTime();
QDateTime startTime = item->data(1, StartTimeRole).toDateTime();
qint64 elapsedTime = startTime.secsTo(QDateTime::currentDateTime());
int dt = elapsedTime - item->data(1, LastTimeRole).toInt();
if (dt == 0) {
return;
}
qint64 remaining = elapsedTime * (100 - progress) / progress;
int days = static_cast<int>(remaining / 86400);
int remainingSecs = static_cast<int>(remaining % 86400);
QTime when = QTime(0, 0, 0, 0);
when = when.addSecs(remainingSecs);
QString est = (days > 0) ? i18np("%1 day ", "%1 days ", days) : QString();
int days = int(remaining / 86400);
int remainingSecs = int(remaining % 86400);
QTime when = QTime(0, 0, 0, 0).addSecs(remainingSecs);
QString est = i18n("Remaining time ");
if (days > 0) {
est.append(i18np("%1 day ", "%1 days ", days));
}
est.append(when.toString(QStringLiteral("hh:mm:ss")));
QString t = i18n("Remaining time %1", est);
item->setData(1, Qt::UserRole, t);
int speed = (frame - item->data(1, LastFrameRole).toInt()) / dt;
est.append(i18n(" (frame %1 @ %2 fps)", frame, speed));
item->setData(1, Qt::UserRole, est);
item->setData(1, LastTimeRole, elapsedTime);
item->setData(1, LastFrameRole, frame);
}
}
......@@ -2527,7 +2547,7 @@ void RenderWidget::setRenderStatus(const QString &dest, int status, const QStrin
if (status == -1) {
// Job finished successfully
item->setStatus(FINISHEDJOB);
QDateTime startTime = item->data(1, TimeRole).toDateTime();
QDateTime startTime = item->data(1, StartTimeRole).toDateTime();
qint64 elapsedTime = startTime.secsTo(QDateTime::currentDateTime());
int days = static_cast<int>(elapsedTime / 86400);
int secs = static_cast<int>(elapsedTime % 86400);
......@@ -2738,7 +2758,9 @@ void RenderWidget::slotStartScript()
renderItem->setStatus(WAITINGJOB);
renderItem->setIcon(0, QIcon::fromTheme(QStringLiteral("media-playback-pause")));
renderItem->setData(1, Qt::UserRole, i18n("Waiting..."));
renderItem->setData(1, TimeRole, QDateTime::currentDateTime());
QDateTime t = QDateTime::currentDateTime();
renderItem->setData(1, StartTimeRole, t);
renderItem->setData(1, LastTimeRole, t);
QStringList argsJob = {KdenliveSettings::rendererpath(), path, destination, QStringLiteral("-pid:%1").arg(QCoreApplication::applicationPid())};
renderItem->setData(1, ParametersRole, argsJob);
checkRenderStatus();
......@@ -2884,7 +2906,7 @@ bool RenderWidget::startWaitingRenderJobs()
QTextStream outStream(&file);
#ifndef Q_OS_WIN
outStream << "#! /bin/sh" << '\n' << '\n';
outStream << "#!/bin/sh\n\n";
#endif
auto *item = static_cast<RenderJobItem *>(m_view.running_jobs->topLevelItem(0));
while (item != nullptr) {
......
......@@ -123,7 +123,7 @@ public:
~RenderWidget() override;
void setGuides(std::weak_ptr<MarkerListModel> guidesModel);
void focusFirstVisibleItem(const QString &profile = QString());
void setRenderJob(const QString &dest, int progress = 0);
void setRenderJob(const QString &dest, int progress = 0, int frame = 0);
void setRenderStatus(const QString &dest, int status, const QString &error);
void updateDocumentPath();
void reloadProfiles();
......
......@@ -2044,11 +2044,11 @@ void MainWindow::slotCheckRenderStatus()
m_renderWidget->missingClips(pCore->bin()->hasMissingClips());*/
}
void MainWindow::setRenderingProgress(const QString &url, int progress)
void MainWindow::setRenderingProgress(const QString &url, int progress, int frame)
{
emit setRenderProgress(progress);
if (m_renderWidget) {
m_renderWidget->setRenderJob(url, progress);
m_renderWidget->setRenderJob(url, progress, frame);
}
}
......
......@@ -260,7 +260,7 @@ private:
public slots:
void slotReloadEffects(const QStringList &paths);
Q_SCRIPTABLE void setRenderingProgress(const QString &url, int progress);
Q_SCRIPTABLE void setRenderingProgress(const QString &url, int progress, int frame);
Q_SCRIPTABLE void setRenderingFinished(const QString &url, int status, const QString &error);
Q_SCRIPTABLE void addProjectClip(const QString &url);
Q_SCRIPTABLE void addTimelineClip(const QString &url);
......
......@@ -7,6 +7,7 @@
<method name="setRenderingProgress">
<arg name="url" type="s" direction="in"/>
<arg name="progress" type="i" direction="in"/>
<arg name="frame" type="i" direction="in"/>
</method>
<method name="setRenderingFinished">
<arg name="url" type="s" direction="in"/>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment