diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 70a26bcad..24f7d9116 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -30,6 +30,7 @@ if (WIN32)
endif()
add_subdirectory(audio)
+add_subdirectory(cli)
add_subdirectory(codec)
add_subdirectory(common)
add_subdirectory(config)
diff --git a/app/cli/CMakeLists.txt b/app/cli/CMakeLists.txt
new file mode 100644
index 000000000..6fe09bdc8
--- /dev/null
+++ b/app/cli/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Olive - Non-Linear Video Editor
+# Copyright (C) 2019 Olive Team
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+add_subdirectory(cliprogress)
+add_subdirectory(clitask)
+
+set(OLIVE_SOURCES
+ ${OLIVE_SOURCES}
+ PARENT_SCOPE
+)
diff --git a/app/cli/cliprogress/CMakeLists.txt b/app/cli/cliprogress/CMakeLists.txt
new file mode 100644
index 000000000..27a57775c
--- /dev/null
+++ b/app/cli/cliprogress/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Olive - Non-Linear Video Editor
+# Copyright (C) 2019 Olive Team
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+set(OLIVE_SOURCES
+ ${OLIVE_SOURCES}
+ cli/cliprogress/cliprogressdialog.h
+ cli/cliprogress/cliprogressdialog.cpp
+ PARENT_SCOPE
+)
diff --git a/app/cli/cliprogress/cliprogressdialog.cpp b/app/cli/cliprogress/cliprogressdialog.cpp
new file mode 100644
index 000000000..fa846c1ff
--- /dev/null
+++ b/app/cli/cliprogress/cliprogressdialog.cpp
@@ -0,0 +1,105 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#include "cliprogressdialog.h"
+
+#include
+
+OLIVE_NAMESPACE_ENTER
+
+CLIProgressDialog::CLIProgressDialog(const QString& title, QObject *parent) :
+ QObject(parent),
+ title_(title),
+ progress_(0),
+ drawn_(false)
+{
+}
+
+void CLIProgressDialog::Update()
+{
+ if (drawn_) {
+ // We've been here before, do a carriage return back to the start of the terminal line
+ std::cout << "\r";
+ } else {
+ drawn_ = true;
+ }
+
+ // FIXME: Get real column count
+ int columns = 80;
+
+ int title_columns = columns / 2 - 1;
+
+ // Print "title" text
+ QString sized_title = title_;
+
+ if (title_.size() > title_columns) {
+ sized_title = title_.left(title_columns - 3).append(QStringLiteral("..."));
+ } else {
+ sized_title = title_;
+ }
+
+ std::cout << sized_title.toUtf8().constData();
+
+ // Pad out the rest of the title area if necessary
+ for (int i=sized_title.size(); i.
+
+***/
+
+#ifndef CLIPROGRESSDIALOG_H
+#define CLIPROGRESSDIALOG_H
+
+#include
+#include
+
+#include "common/define.h"
+
+OLIVE_NAMESPACE_ENTER
+
+class CLIProgressDialog : public QObject
+{
+public:
+ CLIProgressDialog(const QString &title, QObject* parent = nullptr);
+
+public slots:
+ void SetProgress(int p);
+
+private:
+ void Update();
+
+ QString title_;
+
+ int progress_;
+
+ bool drawn_;
+
+};
+
+OLIVE_NAMESPACE_EXIT
+
+#endif // CLIPROGRESSDIALOG_H
diff --git a/app/cli/clitask/CMakeLists.txt b/app/cli/clitask/CMakeLists.txt
new file mode 100644
index 000000000..d3a84091d
--- /dev/null
+++ b/app/cli/clitask/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Olive - Non-Linear Video Editor
+# Copyright (C) 2019 Olive Team
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+set(OLIVE_SOURCES
+ ${OLIVE_SOURCES}
+ cli/clitask/clitaskdialog.h
+ cli/clitask/clitaskdialog.cpp
+ PARENT_SCOPE
+)
diff --git a/app/cli/clitask/clitaskdialog.cpp b/app/cli/clitask/clitaskdialog.cpp
new file mode 100644
index 000000000..e68ac0cd7
--- /dev/null
+++ b/app/cli/clitask/clitaskdialog.cpp
@@ -0,0 +1,33 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#include "clitaskdialog.h"
+
+OLIVE_NAMESPACE_ENTER
+
+CLITaskDialog::CLITaskDialog(Task *task, QObject* parent) :
+ CLIProgressDialog(task->GetTitle(), parent)
+{
+ //connect(task, &Task::ProgressChanged, this, &CLITaskDialog::SetProgress);
+
+ task->Start();
+}
+
+OLIVE_NAMESPACE_EXIT
diff --git a/app/cli/clitask/clitaskdialog.h b/app/cli/clitask/clitaskdialog.h
new file mode 100644
index 000000000..313e3aadc
--- /dev/null
+++ b/app/cli/clitask/clitaskdialog.h
@@ -0,0 +1,41 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#ifndef CLITASKDIALOG_H
+#define CLITASKDIALOG_H
+
+#include "cli/cliprogress/cliprogressdialog.h"
+#include "task/task.h"
+
+OLIVE_NAMESPACE_ENTER
+
+class CLITaskDialog : public CLIProgressDialog
+{
+public:
+ CLITaskDialog(Task *task, QObject* parent = nullptr);
+
+private:
+ Task* task_;
+
+};
+
+OLIVE_NAMESPACE_EXIT
+
+#endif // CLITASKDIALOG_H
diff --git a/app/core.cpp b/app/core.cpp
index cf3479eb9..f41294ff4 100644
--- a/app/core.cpp
+++ b/app/core.cpp
@@ -31,6 +31,7 @@
#include
#include "audio/audiomanager.h"
+#include "cli/clitask/clitaskdialog.h"
#include "common/filefunctions.h"
#include "common/xmlutils.h"
#include "config/config.h"
@@ -67,7 +68,8 @@ Core::Core() :
main_window_(nullptr),
tool_(Tool::kPointer),
addable_object_(Tool::kAddableEmpty),
- snapping_(true)
+ snapping_(true),
+ gui_active_(false)
{
}
@@ -76,7 +78,7 @@ Core *Core::instance()
return &instance_;
}
-void Core::Start()
+bool Core::Start()
{
//
// Parse command line arguments
@@ -97,6 +99,10 @@ void Core::Start()
QCommandLineOption fullscreen_option({"f", "fullscreen"}, tr("Start in full screen mode"));
parser.addOption(fullscreen_option);
+ // Create headless export option
+ QCommandLineOption headless_export_option({"x", "export"}, tr("Export project from command line"));
+ parser.addOption(headless_export_option);
+
// Parse options
parser.process(*app);
@@ -119,6 +125,12 @@ void Core::Start()
// Set up color manager's default config
ColorManager::SetUpDefaultConfig();
+ // Initialize disk service
+ DiskManager::CreateInstance();
+
+ // Initialize task manager
+ TaskManager::CreateInstance();
+
// Reset config (Config sets to default on construction already, but we do it again here as a workaround that fixes
// the fact that some of the config paths set by default rely on the app name having been set (in main())
Config::Current().SetDefaults();
@@ -128,26 +140,56 @@ void Core::Start()
//
- // Start GUI (FIXME CLI mode)
+ // Start application
//
- StartGUI(parser.isSet(fullscreen_option));
+ qInfo() << "Using Qt version:" << qVersion();
- // Load startup project
- if (!startup_project_.isEmpty() && !QFileInfo::exists(startup_project_)) {
- QMessageBox::warning(main_window(),
- tr("Failed to open startup file"),
- tr("The project \"%1\" doesn't exist. A new project will be started instead.").arg(startup_project_),
- QMessageBox::Ok);
+ gui_active_ = !parser.isSet(headless_export_option);
- startup_project_.clear();
- }
+ if (gui_active_) {
+
+ // Start GUI
+ StartGUI(parser.isSet(fullscreen_option));
+
+ // Load startup project
+ if (!startup_project_.isEmpty() && !QFileInfo::exists(startup_project_)) {
+ QMessageBox::warning(main_window(),
+ tr("Failed to open startup file"),
+ tr("The project \"%1\" doesn't exist. A new project will be started instead.").arg(startup_project_),
+ QMessageBox::Ok);
+
+ startup_project_.clear();
+ }
+
+ if (startup_project_.isEmpty()) {
+ // If no load project is set, create a new one on open
+ CreateNewProject();
+ } else {
+ OpenProjectInternal(startup_project_);
+ }
+
+ return true;
- if (startup_project_.isEmpty()) {
- // If no load project is set, create a new one on open
- CreateNewProject();
} else {
- OpenProjectInternal(startup_project_);
+
+ if (parser.isSet(headless_export_option)) {
+
+ if (startup_project_.isEmpty()) {
+ qCritical().noquote() << tr("You must specify a project file to export");
+ } else {
+ OpenProjectInternal(startup_project_);
+
+ qDebug() << "Ready for exporting!";
+
+ return true;
+ }
+
+ }
+
+ // Error fallback
+ return false;
+
}
}
@@ -514,12 +556,6 @@ void Core::StartGUI(bool full_screen)
// Initialize audio service
AudioManager::CreateInstance();
- // Initialize disk service
- DiskManager::CreateInstance();
-
- // Initialize task manager
- TaskManager::CreateInstance();
-
// Initialize pixel service
PixelFormat::CreateInstance();
@@ -846,12 +882,22 @@ void Core::OpenProjectInternal(const QString &filename)
ProjectLoadManager* plm = new ProjectLoadManager(filename);
- // We use a blocking queued connection here because we want to ensure we have this project instance before the
- // ProjectLoadManager is destroyed
- connect(plm, &ProjectLoadManager::ProjectLoaded, this, &Core::AddOpenProject, Qt::BlockingQueuedConnection);
+ if (gui_active_) {
- TaskDialog* task_dialog = new TaskDialog(plm, tr("Load Project"), main_window());
- task_dialog->open();
+ // We use a blocking queued connection here because we want to ensure we have this project instance before the
+ // ProjectLoadManager is destroyed
+ connect(plm, &ProjectLoadManager::ProjectLoaded, this, &Core::AddOpenProject, Qt::BlockingQueuedConnection);
+
+ TaskDialog* task_dialog = new TaskDialog(plm, tr("Load Project"), main_window());
+ task_dialog->open();
+
+ } else {
+
+ connect(plm, &ProjectLoadManager::ProjectLoaded, this, &Core::AddOpenProject);
+
+ CLITaskDialog task_dialog(plm);
+
+ }
}
int Core::CountFilesInFileList(const QFileInfoList &filenames)
diff --git a/app/core.h b/app/core.h
index 8c5f8985d..20ef0a4ea 100644
--- a/app/core.h
+++ b/app/core.h
@@ -71,7 +71,7 @@ public:
*
* Main application launcher. Parses command line arguments and constructs main window (if entering a GUI mode).
*/
- void Start();
+ bool Start();
/**
* @brief Stop Olive Core
@@ -464,6 +464,11 @@ private:
*/
QStringList recent_projects_;
+ /**
+ * @brief Internal variable for whether the GUI is active
+ */
+ bool gui_active_;
+
/**
* @brief Static singleton core instance
*/
diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp
index 220b0f919..16fef2ee6 100644
--- a/app/dialog/export/export.cpp
+++ b/app/dialog/export/export.cpp
@@ -33,6 +33,7 @@
#include "core.h"
#include "project/item/sequence/sequence.h"
#include "project/project.h"
+#include "render/backend/exportparams.h"
#include "render/pixelformat.h"
#include "ui/icons/icons.h"
#include "window/mainwindow/mainwindow.h"
@@ -238,9 +239,9 @@ void ExportDialog::accept()
{
if (!video_enabled_->isChecked() && !audio_enabled_->isChecked()) {
QMessageBox::critical(this,
- tr("Invalid parameters"),
- tr("Both video and audio are disabled. There's nothing to export."),
- QMessageBox::Ok);
+ tr("Invalid parameters"),
+ tr("Both video and audio are disabled. There's nothing to export."),
+ QMessageBox::Ok);
return;
}
@@ -282,68 +283,8 @@ void ExportDialog::accept()
return;
}
- QMatrix4x4 transform;
-
- int dest_width = static_cast(video_tab_->width_slider()->GetValue());
- int dest_height = static_cast(video_tab_->height_slider()->GetValue());
-
- if (video_tab_->scaling_method_combobox()->isEnabled()) {
- int source_width = viewer_node_->video_params().width();
- int source_height = viewer_node_->video_params().height();
-
- transform = GenerateMatrix(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt()),
- source_width,
- source_height,
- dest_width,
- dest_height);
- }
-
- RenderMode::Mode render_mode = RenderMode::kOnline;
-
- VideoRenderingParams video_render_params(dest_width,
- dest_height,
- video_tab_->frame_rate().flipped(),
- PixelFormat::instance()->GetConfiguredFormatForMode(render_mode),
- render_mode);
-
- AudioRenderingParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(),
- audio_tab_->channel_layout_combobox()->currentData().toULongLong(),
- SampleFormat::kInternalFormat);
-
- ColorProcessorPtr color_processor = ColorProcessor::Create(color_manager_,
- color_manager_->GetReferenceColorSpace(),
- video_tab_->CurrentOCIOColorSpace());
-
- // Set up encoder
- EncodingParams encoding_params;
- encoding_params.SetFilename(filename_edit_->text());
- encoding_params.SetExportLength(viewer_node_->Length());
-
- if (video_enabled_->isChecked()) {
- const ExportCodec& video_codec = codecs_.at(video_tab_->codec_combobox()->currentData().toInt());
- encoding_params.EnableVideo(video_render_params,
- video_codec.id());
-
- video_tab_->GetCodecSection()->AddOpts(&encoding_params);
- }
-
- if (audio_enabled_->isChecked()) {
- const ExportCodec& audio_codec = codecs_.at(audio_tab_->codec_combobox()->currentData().toInt());
- encoding_params.EnableAudio(audio_render_params,
- audio_codec.id());
- }
-
- Encoder* encoder = Encoder::CreateFromID("ffmpeg", encoding_params);
-
- exporter_ = new Exporter(viewer_node_, encoder);
-
- if (video_enabled_->isChecked()) {
- exporter_->EnableVideo(video_render_params, transform, color_processor);
- }
-
- if (audio_enabled_->isChecked()) {
- exporter_->EnableAudio(audio_render_params);
- }
+ // Set up export parameters
+ exporter_ = new Exporter(viewer_node_, color_manager_, GenerateParams());
connect(exporter_, &Exporter::ExportEnded, this, &ExportDialog::ExporterIsDone);
connect(exporter_, &Exporter::ProgressChanged, this, &ExportDialog::ProgressUpdated);
@@ -554,30 +495,6 @@ void ExportDialog::SetDefaultFilename()
filename_edit_->setText(file_location);
}
-QMatrix4x4 ExportDialog::GenerateMatrix(ExportVideoTab::ScalingMethod method, int source_width, int source_height, int dest_width, int dest_height)
-{
- QMatrix4x4 preview_matrix;
-
- if (method == ExportVideoTab::kStretch) {
- return preview_matrix;
- }
-
- float export_ar = static_cast(dest_width) / static_cast(dest_height);
- float source_ar = static_cast(source_width) / static_cast(source_height);
-
- if (qFuzzyCompare(export_ar, source_ar)) {
- return preview_matrix;
- }
-
- if ((export_ar > source_ar) == (method == ExportVideoTab::kFit)) {
- preview_matrix.scale(source_ar / export_ar, 1.0F);
- } else {
- preview_matrix.scale(1.0F, export_ar / source_ar);
- }
-
- return preview_matrix;
-}
-
void ExportDialog::SetUIElementsEnabled(bool enabled)
{
preferences_area_->setEnabled(enabled);
@@ -587,6 +504,49 @@ void ExportDialog::SetUIElementsEnabled(bool enabled)
elapsed_label_->setEnabled(!enabled);
}
+ExportParams ExportDialog::GenerateParams() const
+{
+ RenderMode::Mode render_mode = RenderMode::kOnline;
+
+ VideoRenderingParams video_render_params(static_cast(video_tab_->width_slider()->GetValue()),
+ static_cast(video_tab_->height_slider()->GetValue()),
+ video_tab_->frame_rate().flipped(),
+ PixelFormat::instance()->GetConfiguredFormatForMode(render_mode),
+ render_mode);
+
+ AudioRenderingParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(),
+ audio_tab_->channel_layout_combobox()->currentData().toULongLong(),
+ SampleFormat::GetConfiguredFormatForMode(render_mode));
+
+ ExportParams params;
+ params.SetFilename(filename_edit_->text());
+ params.SetExportLength(viewer_node_->Length());
+
+ if (video_tab_->scaling_method_combobox()->isEnabled()) {
+ params.set_video_scaling_method(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt()));
+ }
+
+ if (video_enabled_->isChecked()) {
+ const ExportCodec& video_codec = codecs_.at(video_tab_->codec_combobox()->currentData().toInt());
+ params.EnableVideo(video_render_params,
+ video_codec.id());
+
+ video_tab_->GetCodecSection()->AddOpts(¶ms);
+
+ params.set_ocio_output(video_tab_->CurrentOCIODisplay(),
+ video_tab_->CurrentOCIOView(),
+ video_tab_->CurrentOCIOLook());
+ }
+
+ if (audio_enabled_->isChecked()) {
+ const ExportCodec& audio_codec = codecs_.at(audio_tab_->codec_combobox()->currentData().toInt());
+ params.EnableAudio(audio_render_params,
+ audio_codec.id());
+ }
+
+ return params;
+}
+
void ExportDialog::UpdateTimeLabels()
{
qint64 elapsed, remaining;
@@ -639,11 +599,11 @@ void ExportDialog::UpdateViewerDimensions()
preview_viewer_->SetOverrideSize(static_cast(video_tab_->width_slider()->GetValue()),
static_cast(video_tab_->height_slider()->GetValue()));
- preview_viewer_->SetMatrix(GenerateMatrix(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt()),
- viewer_node_->video_params().width(),
- viewer_node_->video_params().height(),
- static_cast(video_tab_->width_slider()->GetValue()),
- static_cast(video_tab_->height_slider()->GetValue())));
+ preview_viewer_->SetMatrix(Exporter::GenerateMatrix(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt()),
+ viewer_node_->video_params().width(),
+ viewer_node_->video_params().height(),
+ static_cast(video_tab_->width_slider()->GetValue()),
+ static_cast(video_tab_->height_slider()->GetValue())));
}
void ExportDialog::ExporterIsDone()
diff --git a/app/dialog/export/export.h b/app/dialog/export/export.h
index 23fe741c8..82d610ced 100644
--- a/app/dialog/export/export.h
+++ b/app/dialog/export/export.h
@@ -53,10 +53,10 @@ private:
void LoadPresets();
void SetDefaultFilename();
- QMatrix4x4 GenerateMatrix(ExportVideoTab::ScalingMethod method, int source_width, int source_height, int dest_width, int height);
-
void SetUIElementsEnabled(bool enabled);
+ ExportParams GenerateParams() const;
+
static QString TimeToString(int64_t ms);
ViewerOutput* viewer_node_;
diff --git a/app/dialog/export/exportvideotab.cpp b/app/dialog/export/exportvideotab.cpp
index 03818d9d9..352d86910 100644
--- a/app/dialog/export/exportvideotab.cpp
+++ b/app/dialog/export/exportvideotab.cpp
@@ -26,6 +26,7 @@
#include
#include "core.h"
+#include "render/backend/exportparams.h"
#include "render/colormanager.h"
OLIVE_NAMESPACE_ENTER
@@ -140,9 +141,9 @@ QWidget* ExportVideoTab::SetupResolutionSection()
scaling_method_combobox_ = new QComboBox();
scaling_method_combobox_->setEnabled(false);
- scaling_method_combobox_->addItem(tr("Fit"), kFit);
- scaling_method_combobox_->addItem(tr("Stretch"), kStretch);
- scaling_method_combobox_->addItem(tr("Crop"), kCrop);
+ scaling_method_combobox_->addItem(tr("Fit"), ExportParams::kFit);
+ scaling_method_combobox_->addItem(tr("Stretch"), ExportParams::kStretch);
+ scaling_method_combobox_->addItem(tr("Crop"), ExportParams::kCrop);
layout->addWidget(scaling_method_combobox_, row, 1);
// Automatically enable/disable the scaling method depending on maintain aspect ratio
diff --git a/app/dialog/export/exportvideotab.h b/app/dialog/export/exportvideotab.h
index 23e1de6bd..1332f14a5 100644
--- a/app/dialog/export/exportvideotab.h
+++ b/app/dialog/export/exportvideotab.h
@@ -40,12 +40,6 @@ class ExportVideoTab : public QWidget
public:
ExportVideoTab(ColorManager* color_manager, QWidget* parent = nullptr);
- enum ScalingMethod {
- kFit,
- kStretch,
- kCrop
- };
-
QComboBox* codec_combobox() const;
IntegerSlider* width_slider() const;
diff --git a/app/main.cpp b/app/main.cpp
index 020f594e0..4a8996f9d 100644
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -69,8 +69,6 @@ int main(int argc, char *argv[]) {
app_version.append(GITHASH);
#endif
- qInfo() << "Using Qt version:" << qVersion();
-
QCoreApplication::setApplicationVersion(app_version);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0))
@@ -88,11 +86,20 @@ int main(int argc, char *argv[]) {
avfilter_register_all();
#endif
- // Start core
- OLIVE_NAMESPACE::Core::instance()->Start();
+ int exit_code;
- // Run application loop and receive exit code
- int exit_code = a.exec();
+ // Start core
+ if (OLIVE_NAMESPACE::Core::instance()->Start()) {
+
+ // Run application loop and receive exit code
+ exit_code = a.exec();
+
+ } else {
+
+ // Core failed to start, exit now
+ exit_code = 1;
+
+ }
// Clear core memory
OLIVE_NAMESPACE::Core::instance()->Stop();
diff --git a/app/render/backend/CMakeLists.txt b/app/render/backend/CMakeLists.txt
index 7309a482c..515f1b1e9 100644
--- a/app/render/backend/CMakeLists.txt
+++ b/app/render/backend/CMakeLists.txt
@@ -22,6 +22,8 @@ set(OLIVE_SOURCES
render/backend/exporter.h
render/backend/exporter.cpp
+ render/backend/exportparams.h
+ render/backend/exportparams.cpp
render/backend/renderbackend.h
render/backend/renderbackend.cpp
diff --git a/app/render/backend/exporter.cpp b/app/render/backend/exporter.cpp
index 75510b5e5..18917b39d 100644
--- a/app/render/backend/exporter.cpp
+++ b/app/render/backend/exporter.cpp
@@ -27,46 +27,52 @@
OLIVE_NAMESPACE_ENTER
-Exporter::Exporter(ViewerOutput* viewer,
- Encoder *encoder,
+Exporter::Exporter(ViewerOutput *viewer_node,
+ ColorManager *color_manager,
+ const ExportParams& params,
QObject* parent) :
QObject(parent),
+ viewer_node_(viewer_node),
+ params_(params),
video_backend_(nullptr),
audio_backend_(nullptr),
- viewer_node_(viewer),
- video_done_(true),
- audio_done_(true),
- encoder_(encoder),
export_status_(false),
export_msg_(tr("Export hasn't started yet"))
{
+ encoder_ = Encoder::CreateFromID(params_.encoder(), params_);
+
+ video_done_ = !params_.video_enabled();
+ audio_done_ = !params_.audio_enabled();
+
debug_timer_.setInterval(5000);
connect(&debug_timer_, &QTimer::timeout, this, &Exporter::DebugTimerMessage);
connect(this, &Exporter::ExportEnded, this, &Exporter::deleteLater);
- export_range_ = TimeRange(0, viewer_node_->Length());
-}
+ if (params_.has_custom_range()) {
+ export_range_ = params_.custom_range();
+ } else {
+ export_range_ = TimeRange(0, viewer_node_->Length());
+ }
-void Exporter::EnableVideo(const VideoRenderingParams &video_params, const QMatrix4x4 &transform, ColorProcessorPtr color_processor)
-{
- video_params_ = video_params;
- transform_ = transform;
- color_processor_ = color_processor;
+ if (params_.video_enabled()) {
- video_done_ = false;
-}
+ // If a transformation matrix is applied to this video, create it here
+ if (params_.video_scaling_method() != ExportParams::kStretch) {
+ transform_ = GenerateMatrix(params_.video_scaling_method(),
+ viewer_node_->video_params().width(),
+ viewer_node_->video_params().height(),
+ params_.video_params().width(),
+ params_.video_params().height());
+ }
-void Exporter::EnableAudio(const AudioRenderingParams &audio_params)
-{
- audio_params_ = audio_params;
-
- audio_done_ = false;
-}
-
-void Exporter::OverrideExportRange(const TimeRange &range)
-{
- export_range_ = range;
+ // Create color processor
+ color_processor_ = ColorProcessor::Create(color_manager,
+ color_manager->GetReferenceColorSpace(),
+ params.ocio_display(),
+ params.ocio_view(),
+ params.ocio_look());
+ }
}
bool Exporter::GetExportStatus() const
@@ -110,9 +116,9 @@ void Exporter::StartExporting()
video_backend_->SetViewerNode(viewer_node_);
video_backend_->SetParameters(VideoRenderingParams(viewer_node_->video_params().width(),
viewer_node_->video_params().height(),
- video_params_.time_base(),
- video_params_.format(),
- video_params_.mode()));
+ params_.video_params().time_base(),
+ params_.video_params().format(),
+ params_.video_params().mode()));
waiting_for_frame_ = 0;
}
@@ -121,7 +127,7 @@ void Exporter::StartExporting()
audio_backend_ = new AudioBackend();
audio_backend_->SetViewerNode(viewer_node_);
- audio_backend_->SetParameters(audio_params_);
+ audio_backend_->SetParameters(params_.audio_params());
}
// Open encoder and wait for result
@@ -190,7 +196,7 @@ void Exporter::EncodeFrame()
Qt::QueuedConnection,
OLIVE_NS_ARG(FramePtr, frame));
- waiting_for_frame_ += video_params_.time_base();
+ waiting_for_frame_ += params_.video_params().time_base();
// Calculate progress
emit ProgressChanged(waiting_for_frame_.toDouble() / viewer_node_->Length().toDouble());
@@ -204,6 +210,30 @@ void Exporter::EncodeFrame()
}
}
+QMatrix4x4 Exporter::GenerateMatrix(ExportParams::VideoScalingMethod method, int source_width, int source_height, int dest_width, int dest_height)
+{
+ QMatrix4x4 preview_matrix;
+
+ if (method == ExportParams::kStretch) {
+ return preview_matrix;
+ }
+
+ float export_ar = static_cast(dest_width) / static_cast(dest_height);
+ float source_ar = static_cast(source_width) / static_cast(source_height);
+
+ if (qFuzzyCompare(export_ar, source_ar)) {
+ return preview_matrix;
+ }
+
+ if ((export_ar > source_ar) == (method == ExportParams::kFit)) {
+ preview_matrix.scale(source_ar / export_ar, 1.0F);
+ } else {
+ preview_matrix.scale(1.0F, export_ar / source_ar);
+ }
+
+ return preview_matrix;
+}
+
void Exporter::FrameRendered(const rational &time, FramePtr value)
{
debug_timer_.stop();
@@ -261,14 +291,14 @@ void Exporter::EncoderOpenedSuccessfully()
video_backend_->SetOperatingMode(VideoRenderWorker::kHashOnly);
connect(video_backend_, &VideoRenderBackend::QueueComplete, this, &Exporter::VideoHashesComplete);
- video_backend_->InvalidateCache(TimeRange(0, viewer_node_->Length()));
+ video_backend_->InvalidateCache(export_range_);
}
if (!audio_done_) {
// We set the audio backend to render the full sequence to the disk
connect(audio_backend_, &AudioRenderBackend::AudioComplete, this, &Exporter::AudioRendered);
- audio_backend_->InvalidateCache(TimeRange(0, viewer_node_->Length()));
+ audio_backend_->InvalidateCache(export_range_);
}
}
@@ -297,7 +327,6 @@ void Exporter::VideoHashesComplete()
video_backend_->SetOperatingMode(VideoRenderWorker::kRenderOnly);
video_backend_->SetOnlySignalLastFrameRequested(false);
- // FIXME: Exporting is now broken because of this
connect(video_backend_, &VideoRenderBackend::GeneratedFrame, this, &Exporter::FrameRendered);
foreach (const TimeRange& range, ranges) {
diff --git a/app/render/backend/exporter.h b/app/render/backend/exporter.h
index 581e42f5d..3aaec6986 100644
--- a/app/render/backend/exporter.h
+++ b/app/render/backend/exporter.h
@@ -29,6 +29,7 @@
#include "codec/encoder.h"
#include "node/output/viewer/viewer.h"
#include "render/backend/audiorenderbackend.h"
+#include "render/backend/exportparams.h"
#include "render/backend/videorenderbackend.h"
#include "render/colorprocessor.h"
@@ -38,20 +39,18 @@ class Exporter : public QObject
{
Q_OBJECT
public:
- Exporter(ViewerOutput* viewer,
- Encoder* encoder,
+ Exporter(ViewerOutput* viewer_node,
+ ColorManager* color_manager,
+ const ExportParams& params,
QObject* parent = nullptr);
- void EnableVideo(const VideoRenderingParams& video_params, const QMatrix4x4& transform, ColorProcessorPtr color_processor);
- void EnableAudio(const AudioRenderingParams& audio_params);
-
- void OverrideExportRange(const TimeRange& range);
-
bool GetExportStatus() const;
const QString& GetExportError() const;
void Cancel();
+ static QMatrix4x4 GenerateMatrix(ExportParams::VideoScalingMethod method, int source_width, int source_height, int dest_width, int dest_height);
+
public slots:
void StartExporting();
@@ -63,17 +62,23 @@ signals:
protected:
void SetExportMessage(const QString& s);
+private:
+ void ExportSucceeded();
+
+ void ExportStopped();
+
+ void EncodeFrame();
+
+ ViewerOutput* viewer_node_;
+
+ ColorProcessorPtr color_processor_;
+
+ ExportParams params_;
+
// Renderers
VideoRenderBackend* video_backend_;
AudioRenderBackend* audio_backend_;
- // Viewer node
- ViewerOutput* viewer_node_;
-
- // Export parameters
- VideoRenderingParams video_params_;
- AudioRenderingParams audio_params_;
-
// Export transform
QMatrix4x4 transform_;
@@ -81,23 +86,14 @@ protected:
bool audio_done_;
- TimeRange export_range_;
-
-private:
- void ExportSucceeded();
-
- void ExportStopped();
-
- void EncodeFrame();
-
- ColorProcessorPtr color_processor_;
-
Encoder* encoder_;
bool export_status_;
QString export_msg_;
+ TimeRange export_range_;
+
rational waiting_for_frame_;
QHash cached_frames_;
diff --git a/app/render/backend/exportparams.cpp b/app/render/backend/exportparams.cpp
new file mode 100644
index 000000000..671247ada
--- /dev/null
+++ b/app/render/backend/exportparams.cpp
@@ -0,0 +1,89 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#include "exportparams.h"
+
+OLIVE_NAMESPACE_ENTER
+
+ExportParams::ExportParams() :
+ video_scaling_method_(kStretch),
+ has_custom_range_(false)
+{
+}
+
+const QString &ExportParams::encoder() const
+{
+ return encoder_id_;
+}
+
+void ExportParams::set_encoder(const QString &id)
+{
+ encoder_id_ = id;
+}
+
+bool ExportParams::has_custom_range() const
+{
+ return has_custom_range_;
+}
+
+const TimeRange &ExportParams::custom_range() const
+{
+ return custom_range_;
+}
+
+void ExportParams::set_custom_range(const TimeRange &custom_range)
+{
+ has_custom_range_ = true;
+ custom_range_ = custom_range;
+}
+
+const ExportParams::VideoScalingMethod &ExportParams::video_scaling_method() const
+{
+ return video_scaling_method_;
+}
+
+void ExportParams::set_video_scaling_method(const ExportParams::VideoScalingMethod &video_scaling_method)
+{
+ video_scaling_method_ = video_scaling_method;
+}
+
+void ExportParams::set_ocio_output(const QString &display, const QString &view, const QString &look)
+{
+ ocio_display_ = display;
+ ocio_view_ = view;
+ ocio_look_ = look;
+}
+
+const QString &ExportParams::ocio_display() const
+{
+ return ocio_display_;
+}
+
+const QString &ExportParams::ocio_view() const
+{
+ return ocio_view_;
+}
+
+const QString &ExportParams::ocio_look() const
+{
+ return ocio_look_;
+}
+
+OLIVE_NAMESPACE_EXIT
diff --git a/app/render/backend/exportparams.h b/app/render/backend/exportparams.h
new file mode 100644
index 000000000..87b9204c0
--- /dev/null
+++ b/app/render/backend/exportparams.h
@@ -0,0 +1,70 @@
+/***
+
+ Olive - Non-Linear Video Editor
+ Copyright (C) 2019 Olive Team
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+***/
+
+#ifndef EXPORTPARAMS_H
+#define EXPORTPARAMS_H
+
+#include "codec/encoder.h"
+#include "node/output/viewer/viewer.h"
+
+OLIVE_NAMESPACE_ENTER
+
+class ExportParams : public EncodingParams {
+public:
+ enum VideoScalingMethod {
+ kFit,
+ kStretch,
+ kCrop
+ };
+
+ ExportParams();
+
+ const QString& encoder() const;
+ void set_encoder(const QString& id);
+
+ bool has_custom_range() const;
+ const TimeRange& custom_range() const;
+ void set_custom_range(const TimeRange& custom_range);
+
+ const VideoScalingMethod& video_scaling_method() const;
+ void set_video_scaling_method(const VideoScalingMethod& video_scaling_method);
+
+ const QString& ocio_display() const;
+ const QString& ocio_view() const;
+ const QString& ocio_look() const;
+ void set_ocio_output(const QString& display, const QString& view, const QString& look);
+
+private:
+ QString encoder_id_;
+
+ VideoScalingMethod video_scaling_method_;
+
+ bool has_custom_range_;
+ TimeRange custom_range_;
+
+ QString ocio_display_;
+ QString ocio_view_;
+ QString ocio_look_;
+
+};
+
+OLIVE_NAMESPACE_EXIT
+
+#endif // EXPORTPARAMS_H