Switch to new rendering format (like Shotcut):

Embed rendering parameters inside a consumer element
in the playlist xml
parent 13a4e75c
......@@ -30,3 +30,4 @@ DNxHD 1080p 59.94fps=r=59.94 s=1920x1080 vb=90M threads=0 vcodec=dnxhd;mov
DNxHD 1080p 60fps=r=60 s=1920x1080 vb=90M threads=0 vcodec=dnxhd;mov
MJPEG=f=avi vcodec=mjpeg progressive=1 qscale=1;avi
x264-nvenc=vcodec=h264_nvenc g=1 bf=0 profile=0;mkv
x264-vaapi=vcodec=h264_vaapi g=1 bf=0 profile=0;mkv
set(QT_DONT_USE_QTGUI 1)
set(QT_USE_QTDBUS 1)
include_directories(
${MLT_INCLUDE_DIR}
)
set(kdenlive_render_SRCS
kdenlive_render.cpp
renderjob.cpp
......@@ -9,7 +13,7 @@ set(kdenlive_render_SRCS
add_executable(kdenlive_render ${kdenlive_render_SRCS})
ecm_mark_nongui_executable(kdenlive_render)
target_link_libraries(kdenlive_render Qt5::Core Qt5::DBus)
target_link_libraries(kdenlive_render Qt5::Core Qt5::DBus Qt5::Xml)
install(TARGETS kdenlive_render DESTINATION ${BIN_INSTALL_DIR})
......@@ -23,8 +23,10 @@
#include <QFileInfo>
#include <QString>
#include <QStringList>
#include <QDomDocument>
#include <QUrl>
#include <stdio.h>
#include "framework/mlt_version.h"
int main(int argc, char **argv)
{
......@@ -32,7 +34,40 @@ int main(int argc, char **argv)
QStringList args = app.arguments();
QStringList preargs;
QString locale;
if (args.count() >= 7) {
if (args.count() >= 4) {
// Remove program name
args.removeFirst();
QString render = args.at(0);
args.removeFirst();
QString playlist = args.at(0);
args.removeFirst();
QString target = args.at(0);
args.removeFirst();
int pid = 0;
if (args.count() > 0 && args.at(0).startsWith(QLatin1String("-pid:"))) {
pid = args.at(0).section(QLatin1Char(':'), 1).toInt();
args.removeFirst();
}
int in = -1;
int out = -1;
if (LIBMLT_VERSION_INT < 396544) {
// older MLT version, does not support consumer in/out, so read it manually
QFile f(playlist);
QDomDocument doc;
doc.setContent(&f, false);
f.close();
QDomElement consumer = doc.documentElement().firstChildElement(QStringLiteral("consumer"));
if (!consumer.isNull()) {
in = consumer.attribute("in").toInt();
out = consumer.attribute("out").toInt();
}
}
RenderJob *rJob = new RenderJob(render, playlist, target, pid, in, out);
rJob->start();
app.exec();
}
else if (args.count() >= 7) {
// Deprecated
int pid = 0;
int in = -1;
int out = -1;
......
......@@ -32,6 +32,46 @@ public:
static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
};
RenderJob::RenderJob(const QString &render, const QString &scenelist, const QString &target, int pid, int in, int out)
: QObject()
, m_scenelist(scenelist)
, m_dest(target)
, m_progress(0)
, m_prog(render)
, m_player()
, m_jobUiserver(nullptr)
, m_kdenliveinterface(nullptr)
, m_usekuiserver(true)
, m_logfile(scenelist + QStringLiteral(".txt"))
, m_erase(scenelist.startsWith(QDir::tempPath()))
, m_seconds(0)
, m_frame(0)
, m_pid(pid)
, m_dualpass(false)
{
m_renderProcess = new QProcess;
m_renderProcess->setReadChannel(QProcess::StandardError);
connect(m_renderProcess, &QProcess::stateChanged, this, &RenderJob::slotCheckProcess);
// Disable VDPAU so that rendering will work even if there is a Kdenlive instance using VDPAU
qputenv("MLT_NO_VDPAU", "1");
m_args << "-progress" << scenelist;
if (in != -1) {
m_args << QStringLiteral("in=") + QString::number(in);
}
if (out != -1) {
m_args << QStringLiteral("out=") + QString::number(out);
}
// Create a log of every render process.
if (!m_logfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Unable to log to " << m_logfile.fileName();
} else {
m_logstream.setDevice(&m_logfile);
}
}
RenderJob::RenderJob(bool erase, bool usekuiserver, int pid, const QString &renderer, const QString &profile, const QString &rendermodule,
const QString &player, const QString &scenelist, const QString &dest, const QStringList &preargs, const QStringList &args, int in, int out)
: QObject()
......@@ -207,17 +247,20 @@ void RenderJob::start()
}
}
}
initKdenliveDbusInterface();
if (m_pid > -1) {
initKdenliveDbusInterface();
}
// Make sure the destination directory is writable
QFileInfo checkDestination(QFileInfo(m_dest).absolutePath());
/*QFileInfo checkDestination(QFileInfo(m_dest).absolutePath());
if (!checkDestination.isWritable()) {
slotIsOver(QProcess::NormalExit, false);
}
}*/
// 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(' ')) << endl;
}
......
......@@ -33,7 +33,8 @@ class RenderJob : public QObject
Q_OBJECT
public:
RenderJob(bool erase, bool usekuiserver, int pid, const QString &renderer, const QString &profile, const QString &rendermodule, const QString &player,
RenderJob(const QString &render, const QString &scenelist, const QString &target, int pid = -1, int in = -1, int out = -1);
Q_DECL_DEPRECATED RenderJob(bool erase, bool usekuiserver, int pid, const QString &renderer, const QString &profile, const QString &rendermodule, const QString &player,
const QString &scenelist, const QString &dest, const QStringList &preargs, const QStringList &args, int in = -1, int out = -1);
~RenderJob();
void setLocale(const QString &locale);
......
......@@ -769,6 +769,7 @@ Bin::~Bin()
blockSignals(true);
m_proxyModel->selectionModel()->blockSignals(true);
setEnabled(false);
m_propertiesPanel = nullptr;
abortOperations();
m_itemModel->clean();
}
......
This diff is collapsed.
......@@ -119,13 +119,13 @@ class RenderWidget : public QDialog
Q_OBJECT
public:
explicit RenderWidget(const QString &projectfolder, bool enableProxy, QWidget *parent = nullptr);
explicit RenderWidget(bool enableProxy, QWidget *parent = nullptr);
virtual ~RenderWidget();
void setGuides(const QList<CommentedTime> &guidesList, double duration);
void focusFirstVisibleItem(const QString &profile = QString());
void setRenderJob(const QString &dest, int progress = 0);
void setRenderStatus(const QString &dest, int status, const QString &error);
void setDocumentPath(const QString &path);
void updateDocumentPath();
void reloadProfiles();
void setRenderProfile(const QMap<QString, QString> &props);
int waitingJobsCount() const;
......@@ -151,7 +151,7 @@ protected:
void keyPressEvent(QKeyEvent *e) override;
public slots:
void slotExport(bool scriptExport, int zoneIn, int zoneOut, const QMap<QString, QString> &metadata, const QList<QString> &playlistPaths,
Q_DECL_DEPRECATED void slotExport(bool scriptExport, int zoneIn, int zoneOut, const QMap<QString, QString> &metadata, const QList<QString> &playlistPaths,
const QList<QString> &trackNames, const QString &scriptPath, bool exportAudio);
void slotAbortCurrentJob();
void slotPrepareExport(bool scriptExport = false, const QString &scriptPath = QString());
......@@ -230,6 +230,8 @@ private:
QTreeWidgetItem *loadFromMltPreset(const QString &groupName, const QString &path, const QString &profileName);
void checkCodecs();
int getNewStuff(const QString &configFile);
void prepareRendering(bool delayedRendering, const QString &chapterFile);
void generateRenderFiles(QDomDocument doc, const QString &playlistPath, int in, int out);
signals:
void abortProcess(const QString &url);
......@@ -237,7 +239,6 @@ signals:
/** Send the info about rendering that will be saved in the document:
(profile destination, profile name and url of rendered file */
void selectedRenderProfile(const QMap<QString, QString> &renderProps);
void prepareRenderingData(bool scriptExport, bool zoneOnly, const QString &chapterFile, const QString scriptPath);
void shutdown();
};
......
......@@ -1473,6 +1473,12 @@ void KdenliveDoc::selectPreviewProfile()
setDocumentProperty(QStringLiteral("previewextension"), bestMatch.section(QLatin1Char(';'), 1, 1));
return;
}
if (KdenliveSettings::vaapiEnabled() && values.contains(QStringLiteral("x264-vaapi"))) {
const QString bestMatch = values.value(QStringLiteral("x264-vaapi"));
setDocumentProperty(QStringLiteral("previewparameters"), bestMatch.section(QLatin1Char(';'), 0, 0));
setDocumentProperty(QStringLiteral("previewextension"), bestMatch.section(QLatin1Char(';'), 1, 1));
return;
}
QMapIterator<QString, QString> i(values);
QStringList matchingProfiles;
QStringList fallBackProfiles;
......@@ -1542,8 +1548,8 @@ void KdenliveDoc::initProxySettings()
// Select best proxy profile depending on hw encoder support
if (KdenliveSettings::nvencEnabled() && values.contains(QStringLiteral("x264-nvenc"))) {
params = values.value(QStringLiteral("x264-nvenc"));
} else if (KdenliveSettings::vaapiEnabled() && values.contains(QStringLiteral("MJPEG-vaapi"))) {
params = values.value(QStringLiteral("MJPEG-vaapi"));
} else if (KdenliveSettings::vaapiEnabled() && values.contains(QStringLiteral("x264-vaapi"))) {
params = values.value(QStringLiteral("x264-vaapi"));
} else {
params = values.value(QStringLiteral("MJPEG"));
}
......
......@@ -29,6 +29,7 @@
#include "macros.hpp"
#include <QProcess>
#include <QThread>
#include <QTemporaryFile>
#include <klocalizedstring.h>
......@@ -127,8 +128,14 @@ bool ProxyJob::startJob()
}
mltParameters << t;
}
mltParameters.append(QStringLiteral("real_time=-%1").arg(KdenliveSettings::mltthreads()));
int threadCount = QThread::idealThreadCount();
if (threadCount > 2) {
threadCount = qMin(threadCount - 1, 4);
} else {
threadCount = 1;
}
mltParameters.append(QStringLiteral("real_time=-%1").arg(threadCount));
mltParameters.append(QStringLiteral("threads=%1").arg(threadCount));
// TODO: currently, when rendering an xml file through melt, the display ration is lost, so we enforce it manualy
mltParameters << QStringLiteral("aspect=") + QLocale().toString(display_ratio);
......
This diff is collapsed.
......@@ -404,7 +404,6 @@ private slots:
/** @brief Archive project: creates a copy of the project file with all clips in a new folder. */
void slotArchiveProject();
void slotSetDocumentRenderProfile(const QMap<QString, QString> &props);
void slotPrepareRendering(bool scriptExport, bool zoneOnly, const QString &chapterFile, QString scriptPath = QString());
/** @brief Switches between displaying frames or timecode.
* @param ix 0 = display timecode, 1 = display frames. */
......
......@@ -1448,12 +1448,6 @@ void Monitor::resetConsumer(bool fullReset)
m_glMonitor->resetConsumer(fullReset);
}
/*void Monitor::saveSceneList(const QString &path, const QDomElement &info)
{
if (render == nullptr) return;
render->saveSceneList(path, info);
}*/
const QString Monitor::sceneList(const QString &root, const QString &fullPath)
{
return m_glMonitor->sceneList(root, fullPath);
......
......@@ -28,6 +28,7 @@
#include <KLocalizedString>
#include <QProcess>
#include <QStandardPaths>
#include <QScopedPointer>
#include <QtConcurrent>
PreviewManager::PreviewManager(TimelineController *controller, Mlt::Tractor *tractor)
......@@ -37,7 +38,7 @@ PreviewManager::PreviewManager(TimelineController *controller, Mlt::Tractor *tra
, m_tractor(tractor)
, m_previewTrack(nullptr)
, m_overlayTrack(nullptr)
, m_previewProfile(new Mlt::Profile())
, m_previewProfile(m_tractor->profile())
, m_previewTrackIndex(-1)
, m_initialized(false)
, m_abortPreview(false)
......@@ -45,7 +46,7 @@ PreviewManager::PreviewManager(TimelineController *controller, Mlt::Tractor *tra
m_previewGatherTimer.setSingleShot(true);
m_previewGatherTimer.setInterval(200);
// Scaling doesn't seem to improve speed, needs more testing
double dar = m_tractor->profile()->dar();
/*double dar = m_tractor->profile()->dar();
m_previewProfile->set_width(1024);
int height = 1024 / dar;
height -= height % 4;
......@@ -54,7 +55,7 @@ PreviewManager::PreviewManager(TimelineController *controller, Mlt::Tractor *tra
m_previewProfile->set_display_aspect(m_tractor->profile()->display_aspect_num(), m_tractor->profile()->display_aspect_den());
m_previewProfile->set_frame_rate(m_tractor->profile()->frame_rate_num(), m_tractor->profile()->frame_rate_den());
m_previewProfile->set_colorspace(m_tractor->profile()->colorspace());
m_previewProfile->set_progressive(m_tractor->profile()->progressive());
m_previewProfile->set_progressive(m_tractor->profile()->progressive());*/
m_previewProfile->set_explicit(1);
}
......@@ -74,7 +75,7 @@ PreviewManager::~PreviewManager()
}
delete m_overlayTrack;
delete m_previewTrack;
//m_previewProfile.reset();
m_previewProfile.reset();
}
bool PreviewManager::initialize()
......@@ -129,7 +130,7 @@ bool PreviewManager::buildPreviewTrack()
}
// Create overlay track
qDebug() << "/// BUILDING PREVIEW TRACK\n----------------------\n----------------__";
m_previewTrack = new Mlt::Playlist(*m_tractor->profile());
m_previewTrack = new Mlt::Playlist(*m_previewProfile);
m_tractor->lock();
reconnectTrack();
m_tractor->unlock();
......@@ -496,6 +497,12 @@ void PreviewManager::doPreviewRender(const QString &scene)
}
// Disable audio
sourceProd.set("set.test_audio", 1);
int threadCount = QThread::idealThreadCount();
if (threadCount > 2) {
threadCount = qMin(threadCount - 1, 4);
} else {
threadCount = 1;
}
QMetaObject::Connection connection;
while (!m_dirtyChunks.isEmpty() && !m_abortPreview) {
workingPreview = m_dirtyChunks.takeFirst().toInt();
......@@ -520,8 +527,10 @@ void PreviewManager::doPreviewRender(const QString &scene)
}
}
cons.set("an", 1);
cons.set("threads", threadCount);
cons.set("real_time", -threadCount);
cons.connect(*src);
connection = QObject::connect(this, &PreviewManager::abortPreview, [this, &cons]() {
connection = QObject::connect(this, &PreviewManager::abortPreview, [this, &cons ]() {
cons.purge();
if (!cons.is_stopped()) {
cons.stop();
......@@ -650,7 +659,7 @@ void PreviewManager::reloadChunks(const QVariantList chunks)
if (m_previewTrack->is_blank_at(ix.toInt())) {
QString fileName = m_cacheDir.absoluteFilePath(QStringLiteral("%1.%2").arg(ix.toInt()).arg(m_extension));
fileName.prepend(QStringLiteral("avformat:"));
Mlt::Producer prod(*m_tractor->profile(), fileName.toUtf8().constData());
Mlt::Producer prod(*m_previewProfile, fileName.toUtf8().constData());
if (prod.is_valid()) {
// m_ruler->updatePreview(ix, true);
prod.set("mlt_service", "avformat-novalidate");
......@@ -679,12 +688,12 @@ void PreviewManager::gotPreviewRender(int frame, const QString &file, int progre
}
m_tractor->lock();
if (m_previewTrack->is_blank_at(frame)) {
Mlt::Producer prod(*m_tractor->profile(), QString("avformat:%1").arg(file).toUtf8().constData());
Mlt::Producer prod(*m_previewProfile, QString("avformat:%1").arg(file).toUtf8().constData());
if (prod.is_valid()) {
m_renderedChunks << frame;
m_controller->renderedChunksChanged();
// m_ruler->updatePreview(frame, true, true);
prod.set("mlt_service", "avformat-novalidate");
qDebug()<<"|||| PLUGGING PREVIEW CHUNK AT: "<<frame;
m_previewTrack->insert_at(frame, &prod, 1);
} else {
qCDebug(KDENLIVE_LOG) << "* * * INVALID PROD: " << file;
......
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