giant rendering overhaul and many small fixes

This commit is contained in:
itsmattkc
2019-02-25 13:47:18 -08:00
parent b9d7efa0bc
commit c3373524b1
1429 changed files with 10234 additions and 194593 deletions
+587 -587
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -28,7 +28,6 @@
#include "panels/panels.h"
#include "playback/playback.h"
#include "ui/sourcetable.h"
#include "mainwindow.h"
+1 -2
View File
@@ -26,9 +26,8 @@
#include "project/undo.h"
#include "project/clip.h"
#include "panels/timeline.h"
#include "playback/playback.h"
#include "project/media.h"
#include "playback/audio.h"
#include "rendering/audio.h"
#include <QVariant>
#include <QVBoxLayout>
+1 -1
View File
@@ -23,7 +23,7 @@
#include "oliveglobal.h"
#include "io/config.h"
#include "io/path.h"
#include "playback/audio.h"
#include "rendering/audio.h"
#include "mainwindow.h"
#include <QMenuBar>
+116 -106
View File
@@ -32,142 +32,152 @@
#include "project/footage.h"
#include "mainwindow.h"
ProxyDialog::ProxyDialog(QWidget *parent, const QVector<FootagePtr> &footage) :
QDialog(parent),
selected_footage(footage)
ProxyDialog::ProxyDialog(QWidget *parent, const QVector<Media*> &media) :
QDialog(parent),
selected_media(media)
{
// set dialog title
setWindowTitle(tr("Create Proxy"));
// set dialog title
setWindowTitle(tr("Create Proxy"));
// set proxy folder name to "Proxy", depending on the user's language
proxy_folder_name = tr("Proxy");
// set proxy folder name to "Proxy", depending on the user's language
proxy_folder_name = tr("Proxy");
// set up dialog's layout
QGridLayout* layout = new QGridLayout(this);
// set up dialog's layout
QGridLayout* layout = new QGridLayout(this);
// set the video dimensions of the proxy
layout->addWidget(new QLabel(tr("Dimensions:"), this), 0, 0);
// set the video dimensions of the proxy
layout->addWidget(new QLabel(tr("Dimensions:"), this), 0, 0);
size_combobox = new QComboBox(this);
size_combobox->addItem(tr("Same Size as Source"), 1.0);
size_combobox->addItem(tr("Half Resolution (1/2)"), 0.5);
size_combobox->addItem(tr("Quarter Resolution (1/4)"), 0.25);
size_combobox->addItem(tr("Eighth Resolution (1/8)"), 0.125);
size_combobox->addItem(tr("Sixteenth Resolution (1/16)"), 0.0625);
layout->addWidget(size_combobox, 0, 1);
size_combobox = new QComboBox(this);
size_combobox->addItem(tr("Same Size as Source"), 1.0);
size_combobox->addItem(tr("Half Resolution (1/2)"), 0.5);
size_combobox->addItem(tr("Quarter Resolution (1/4)"), 0.25);
size_combobox->addItem(tr("Eighth Resolution (1/8)"), 0.125);
size_combobox->addItem(tr("Sixteenth Resolution (1/16)"), 0.0625);
layout->addWidget(size_combobox, 0, 1);
// set the desired format of the proxy to create
layout->addWidget(new QLabel(tr("Format:"), this), 1, 0);
// set the desired format of the proxy to create
layout->addWidget(new QLabel(tr("Format:"), this), 1, 0);
format_combobox = new QComboBox(this);
format_combobox->addItem(tr("ProRes HQ"));
// format_combobox->addItem(tr("ProRes SQ"));
// format_combobox->addItem(tr("ProRes LT"));
// format_combobox->addItem(tr("DNxHD"));
// format_combobox->addItem(tr("H.264"));
layout->addWidget(format_combobox, 1, 1);
format_combobox = new QComboBox(this);
format_combobox->addItem(tr("ProRes HQ"));
// format_combobox->addItem(tr("ProRes SQ"));
// format_combobox->addItem(tr("ProRes LT"));
// format_combobox->addItem(tr("DNxHD"));
// format_combobox->addItem(tr("H.264"));
layout->addWidget(format_combobox, 1, 1);
// set the location to place the proxies
layout->addWidget(new QLabel(tr("Location:"), this), 2, 0);
// set the location to place the proxies
layout->addWidget(new QLabel(tr("Location:"), this), 2, 0);
location_combobox = new QComboBox(this);
location_combobox->addItem(tr("Same as Source (in \"%1\" folder)").arg(proxy_folder_name));
location_combobox->addItem("");
connect(location_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(location_changed(int)));
layout->addWidget(location_combobox, 2, 1);
location_combobox = new QComboBox(this);
location_combobox->addItem(tr("Same as Source (in \"%1\" folder)").arg(proxy_folder_name));
location_combobox->addItem("");
connect(location_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(location_changed(int)));
layout->addWidget(location_combobox, 2, 1);
// location_changed will set the default "location" items
location_changed(0);
// location_changed will set the default "location" items
location_changed(0);
// set up dialog buttons
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttons->setCenterButtons(true);
layout->addWidget(buttons, 3, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
// set up dialog buttons
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttons->setCenterButtons(true);
layout->addWidget(buttons, 3, 0, 1, 2);
connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttons, SIGNAL(rejected()), this, SLOT(reject()));
}
void ProxyDialog::accept() {
QVector<ProxyInfo> info_list;
QVector<ProxyInfo> info_list;
// set to TRUE if any existing proxies exist and the user chooses to overwrite all of them
bool overwrite_all_existing = false;
// set to TRUE if any existing proxies exist and the user chooses to overwrite all of them
bool overwrite_all_existing = false;
for (int i=0;i<selected_footage.size();i++) {
// loop through selected footage and send info to the proxy queue
for (int i=0;i<selected_media.size();i++) {
// loop through selected footage and send info to the proxy queue
ProxyInfo info;
ProxyInfo info;
// fill info struct based on user input
info.footage = selected_footage.at(i);
info.codec_type = 0;
info.size_multiplier = size_combobox->currentData().toDouble();
// fill info struct based on user input
info.media = selected_media.at(i);
info.codec_type = 0;
info.size_multiplier = size_combobox->currentData().toDouble();
QString base_footage_fn = QFileInfo(selected_footage.at(i)->url).baseName();
FootagePtr footage = selected_media.at(i)->to_footage();
// TEMPORARILY hardcoded proxy format
base_footage_fn.append(".mov");
QString base_footage_fn = QFileInfo(footage->url).baseName();
// determine path from input
if (custom_location.isEmpty()) {
// use same as source (proxy subfolder)
// TEMPORARILY hardcoded proxy format
base_footage_fn.append(".mov");
// generate full path from footage path and proxy_folder_name's translated "Proxy"
info.path = QDir(QFileInfo(selected_footage.at(i)->url).dir().filePath(proxy_folder_name)).filePath(base_footage_fn);
} else {
// use existing location
info.path = QDir(custom_location).filePath(base_footage_fn);
}
// determine path from input
if (custom_location.isEmpty()) {
// use same as source (proxy subfolder)
// if the proposed proxy file already exists & user didn't select YesToAll box
if (QFileInfo::exists(info.path) && !overwrite_all_existing){
int rtn = QMessageBox::warning( this,
tr("Proxy file exists"),
tr("The file \"%1\" already exists. Do you wish to replace it?").arg(info.path),
QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No);
// generate full path from footage path and proxy_folder_name's translated "Proxy"
info.path = QDir(QFileInfo(footage->url).dir().filePath(proxy_folder_name)).filePath(base_footage_fn);
} else {
// use existing location
info.path = QDir(custom_location).filePath(base_footage_fn);
}
switch (rtn){
case QMessageBox::Yes:
// continue as normal, proxy generator will automatically overwrite this file
break;
case QMessageBox::YesToAll:
// continue as normal, also set variable so that above messagebox is not shown again
overwrite_all_existing = true;
break;
case QMessageBox::No:
// return to dialog without closing or starting any proxy generation
return;
}
}
// if the proposed proxy file already exists & user didn't select YesToAll box
if (QFileInfo::exists(info.path) && !overwrite_all_existing){
int rtn = QMessageBox::warning( this,
tr("Proxy file exists"),
tr("The file \"%1\" already exists. Do you wish to replace it?").arg(info.path),
QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No);
// send to proxy generator thread
info_list.append(info);
}
switch (rtn){
case QMessageBox::Yes:
// continue as normal, proxy generator will automatically overwrite this file
break;
case QMessageBox::YesToAll:
// continue as normal, also set variable so that above messagebox is not shown again
overwrite_all_existing = true;
break;
case QMessageBox::No:
// return to dialog without closing or starting any proxy generation
return;
}
}
// all proxy info checks out, queue it with the proxy generator
for (int i=0;i<info_list.size();i++) {
info_list.at(i).footage->proxy = true;
info_list.at(i).footage->proxy_path.clear();
// send to proxy generator thread
info_list.append(info);
}
proxy_generator.queue(info_list.at(i));
}
// all proxy info checks out, queue it with the proxy generator
for (int i=0;i<info_list.size();i++) {
FootagePtr footage = info_list.at(i).media->to_footage();
footage->proxy = true;
footage->proxy_path.clear();
olive::MainWindow->setWindowModified(true);
olive::proxy_generator.queue(info_list.at(i));
}
QDialog::accept();
olive::MainWindow->setWindowModified(true);
QDialog::accept();
}
void ProxyDialog::location_changed(int i) {
custom_location.clear();
if (i == 1) {
QString s = QFileDialog::getExistingDirectory(this);
if (s.isEmpty()) {
location_combobox->setCurrentIndex(0);
} else {
location_combobox->setItemText(1, s);
custom_location = s;
}
} else {
location_combobox->setItemText(1, tr("Custom Location"));
}
// clear any custom location - either the user picked a new one or chose not a custom location
custom_location.clear();
if (i == 1) {
// if the user picked a custom location, ask which directory
QString s = QFileDialog::getExistingDirectory(this);
if (s.isEmpty()) {
// if the user didn't input anything, set the combobox back to default
location_combobox->setCurrentIndex(0);
} else {
// if the user chose a custom location, set the combobox text to it and custom_location for future usage
location_combobox->setItemText(1, s);
custom_location = s;
}
} else {
// if the user doesn't picks something other than custom location, set this string back to default for clearer UX
location_combobox->setItemText(1, tr("Custom Location"));
}
}
+65 -19
View File
@@ -25,36 +25,82 @@
#include <QVector>
#include <QComboBox>
#include "project/footage.h"
#include "project/media.h"
/**
* @brief The ProxyDialog class
*
* Dialog to set up proxy generation of footage
*/
class ProxyDialog : public QDialog {
Q_OBJECT
Q_OBJECT
public:
ProxyDialog(QWidget* parent, const QVector<FootagePtr>& footage);
/**
* @brief ProxyDialog Constructor
* @param parent
*
* Parent widget to become modal to.
*
* @param footage
*
* List of Footage items to process.
*/
ProxyDialog(QWidget* parent, const QVector<Media *> &media);
public slots:
// called if user clicks "OK" on the dialog
virtual void accept() override;
/**
* @brief Accept changes
*
* Called when the user clicks OK on the dialog. Verifies all proxies, asking the user whether they want to overwrite
* existing proxies if necessary, and if everything is valid, queues the footage with ProxyGenerator.
*/
virtual void accept() override;
private:
// user's desired dimensions
QComboBox* size_combobox;
/**
* @brief User's desired dimensions
*
* Always a fraction of the original video size (e.g. 1/2, 1/4, 1/8, etc.)
*/
QComboBox* size_combobox;
// user's desired proxy format
QComboBox* format_combobox;
/**
* @brief User's desired proxy format
*
* e.g. ProRes, DNxHD, etc.
*/
QComboBox* format_combobox;
// allows users to set the location to store proxies
QComboBox* location_combobox;
/**
* @brief Allows users to set the directory to store proxies in
*/
QComboBox* location_combobox;
// stores the custom location to store proxies if the user sets a custom location
QString custom_location;
/**
* @brief Stores the custom location to store proxies if the user sets a custom location
*/
QString custom_location;
// stores the subdirectory to be made next to the source (dependent on the user's language)
QString proxy_folder_name;
/**
* @brief Stores the default subdirectory to be made next to the source (dependent on the user's language)
*
* "Proxy" in en-US.
*/
QString proxy_folder_name;
// list of footage to make proxies for
QVector<FootagePtr> selected_footage;
/**
* @brief Stored list of footage to make proxies for
*/
QVector<Media*> selected_media;
private slots:
// triggered when the user changes the index in the location combobox
void location_changed(int i);
/**
* @brief Slot when the user changes the location
*
* Triggered when the user changes the index in the location combobox.
*
* @param i
*
* location_combobox's new selected index
*/
void location_changed(int i);
};
#endif // PROXYDIALOG_H
+2 -3
View File
@@ -22,8 +22,7 @@
#include "panels/panels.h"
#include "playback/playback.h"
#include "playback/cacher.h"
#include "rendering/cacher.h"
#include "project/undo.h"
#include <QVBoxLayout>
@@ -112,7 +111,7 @@ void ReplaceClipMediaDialog::replace() {
for (int i=0;i<olive::ActiveSequence->clips.size();i++) {
ClipPtr c = olive::ActiveSequence->clips.at(i);
if (c != nullptr && c->media == media) {
if (c != nullptr && c->media() == media) {
rcmc->clips.append(c);
}
}
+339 -318
View File
@@ -28,7 +28,7 @@
#include "project/sequence.h"
#include "project/footage.h"
#include "playback/playback.h"
#include "rendering/renderfunctions.h"
#include "panels/panels.h"
#include "panels/timeline.h"
#include "project/undo.h"
@@ -36,394 +36,415 @@
#include "project/media.h"
SpeedDialog::SpeedDialog(QWidget *parent) : QDialog(parent) {
setWindowTitle(tr("Speed/Duration"));
setWindowTitle(tr("Speed/Duration"));
QVBoxLayout* main_layout = new QVBoxLayout(this);
QVBoxLayout* main_layout = new QVBoxLayout(this);
QGridLayout* grid = new QGridLayout();
grid->setSpacing(6);
QGridLayout* grid = new QGridLayout();
grid->setSpacing(6);
grid->addWidget(new QLabel(tr("Speed:"), this), 0, 0);
percent = new LabelSlider(this);
percent->decimal_places = 2;
percent->set_display_type(LABELSLIDER_PERCENT);
percent->set_default_value(1);
grid->addWidget(percent, 0, 1);
grid->addWidget(new QLabel(tr("Speed:"), this), 0, 0);
percent = new LabelSlider(this);
percent->decimal_places = 2;
percent->set_display_type(LABELSLIDER_PERCENT);
percent->set_default_value(1);
grid->addWidget(percent, 0, 1);
grid->addWidget(new QLabel(tr("Frame Rate:"), this), 1, 0);
frame_rate = new LabelSlider(this);
frame_rate->decimal_places = 3;
grid->addWidget(frame_rate, 1, 1);
grid->addWidget(new QLabel(tr("Frame Rate:"), this), 1, 0);
frame_rate = new LabelSlider(this);
frame_rate->decimal_places = 3;
grid->addWidget(frame_rate, 1, 1);
grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0);
duration = new LabelSlider(this);
duration->set_display_type(LABELSLIDER_FRAMENUMBER);
duration->set_frame_rate(olive::ActiveSequence->frame_rate);
grid->addWidget(duration, 2, 1);
grid->addWidget(new QLabel(tr("Duration:"), this), 2, 0);
duration = new LabelSlider(this);
duration->set_display_type(LABELSLIDER_FRAMENUMBER);
duration->set_frame_rate(olive::ActiveSequence->frame_rate);
grid->addWidget(duration, 2, 1);
main_layout->addLayout(grid);
main_layout->addLayout(grid);
reverse = new QCheckBox(tr("Reverse"), this);
maintain_pitch = new QCheckBox(tr("Maintain Audio Pitch"), this);
ripple = new QCheckBox(tr("Ripple Changes"), this);
reverse = new QCheckBox(tr("Reverse"), this);
maintain_pitch = new QCheckBox(tr("Maintain Audio Pitch"), this);
ripple = new QCheckBox(tr("Ripple Changes"), this);
main_layout->addWidget(reverse);
main_layout->addWidget(maintain_pitch);
main_layout->addWidget(ripple);
main_layout->addWidget(reverse);
main_layout->addWidget(maintain_pitch);
main_layout->addWidget(ripple);
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttonBox->setCenterButtons(true);
main_layout->addWidget(buttonBox);
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
buttonBox->setCenterButtons(true);
main_layout->addWidget(buttonBox);
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(percent, SIGNAL(valueChanged()), this, SLOT(percent_update()));
connect(frame_rate, SIGNAL(valueChanged()), this, SLOT(frame_rate_update()));
connect(duration, SIGNAL(valueChanged()), this, SLOT(duration_update()));
connect(percent, SIGNAL(valueChanged()), this, SLOT(percent_update()));
connect(frame_rate, SIGNAL(valueChanged()), this, SLOT(frame_rate_update()));
connect(duration, SIGNAL(valueChanged()), this, SLOT(duration_update()));
}
void SpeedDialog::run() {
bool enable_frame_rate = false;
bool multiple_audio = false;
maintain_pitch->setEnabled(false);
bool enable_frame_rate = false;
bool multiple_audio = false;
maintain_pitch->setEnabled(false);
default_frame_rate = qSNaN();
current_frame_rate = qSNaN();
current_percent = qSNaN();
default_length = -1;
current_length = -1;
default_frame_rate = qSNaN();
current_frame_rate = qSNaN();
current_percent = qSNaN();
default_length = -1;
current_length = -1;
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
double clip_percent;
double clip_percent;
// get default frame rate/percentage
clip_percent = c->speed;
if (c->track < 0) {
bool process_video = true;
if (c->media != nullptr && c->media->get_type() == MEDIA_TYPE_FOOTAGE) {
FootagePtr m = c->media->to_footage();
FootageStream* ms = m->get_stream_from_file_index(true, c->media_stream);
if (ms != nullptr && ms->infinite_length) {
process_video = false;
}
}
// get default frame rate/percentage
clip_percent = c->speed().value;
if (c->track() < 0) {
bool process_video = true;
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
FootageStream* ms = c->media_stream();
if (ms != nullptr && ms->infinite_length) {
process_video = false;
}
}
if (process_video) {
double media_frame_rate = c->getMediaFrameRate();
if (process_video) {
double media_frame_rate = c->media_frame_rate();
// get "default" frame rate"
if (enable_frame_rate) {
// check if frame rate is equal to default
if (!qIsNaN(default_frame_rate) && !qFuzzyCompare(media_frame_rate, default_frame_rate)) {
default_frame_rate = qSNaN();
}
if (!qIsNaN(current_frame_rate) && !qFuzzyCompare(media_frame_rate*c->speed, current_frame_rate)) {
current_frame_rate = qSNaN();
}
} else {
default_frame_rate = media_frame_rate;
current_frame_rate = media_frame_rate*c->speed;
}
// get "default" frame rate"
if (enable_frame_rate) {
// check if frame rate is equal to default
if (!qIsNaN(default_frame_rate) && !qFuzzyCompare(media_frame_rate, default_frame_rate)) {
default_frame_rate = qSNaN();
}
if (!qIsNaN(current_frame_rate) && !qFuzzyCompare(media_frame_rate*c->speed().value, current_frame_rate)) {
current_frame_rate = qSNaN();
}
} else {
default_frame_rate = media_frame_rate;
current_frame_rate = media_frame_rate*c->speed().value;
}
enable_frame_rate = true;
}
} else {
maintain_pitch->setEnabled(true);
enable_frame_rate = true;
}
} else {
maintain_pitch->setEnabled(true);
if (!multiple_audio) {
maintain_pitch->setChecked(c->maintain_audio_pitch);
multiple_audio = true;
} else if (!maintain_pitch->isTristate() && maintain_pitch->isChecked() != c->maintain_audio_pitch) {
maintain_pitch->setCheckState(Qt::PartiallyChecked);
maintain_pitch->setTristate(true);
}
}
if (!multiple_audio) {
maintain_pitch->setChecked(c->speed().maintain_audio_pitch);
multiple_audio = true;
} else if (!maintain_pitch->isTristate() && maintain_pitch->isChecked() != c->speed().maintain_audio_pitch) {
maintain_pitch->setCheckState(Qt::PartiallyChecked);
maintain_pitch->setTristate(true);
}
}
if (i == 0) {
reverse->setChecked(c->reverse);
} else if (c->reverse != reverse->isChecked()) {
reverse->setTristate(true);
reverse->setCheckState(Qt::PartiallyChecked);
}
if (i == 0) {
reverse->setChecked(c->reversed());
} else if (c->reversed() != reverse->isChecked()) {
reverse->setTristate(true);
reverse->setCheckState(Qt::PartiallyChecked);
}
// get default length
long clip_default_length = qRound(c->getLength() * clip_percent);
if (i == 0) {
current_length = c->getLength();
default_length = clip_default_length;
current_percent = clip_percent;
} else {
if (current_length != -1 && c->getLength() != current_length) {
current_length = -1;
}
if (default_length != -1 && clip_default_length != default_length) {
default_length = -1;
}
if (!qIsNaN(current_percent) && !qFuzzyCompare(clip_percent, current_percent)) {
current_percent = qSNaN();
}
}
}
// get default length
long clip_default_length = qRound(c->length() * clip_percent);
if (i == 0) {
current_length = c->length();
default_length = clip_default_length;
current_percent = clip_percent;
} else {
if (current_length != -1 && c->length() != current_length) {
current_length = -1;
}
if (default_length != -1 && clip_default_length != default_length) {
default_length = -1;
}
if (!qIsNaN(current_percent) && !qFuzzyCompare(clip_percent, current_percent)) {
current_percent = qSNaN();
}
}
}
frame_rate->set_minimum_value(1);
percent->set_minimum_value(0.0001);
duration->set_minimum_value(1);
frame_rate->set_minimum_value(1);
percent->set_minimum_value(0.0001);
duration->set_minimum_value(1);
frame_rate->setEnabled(enable_frame_rate);
frame_rate->set_default_value(default_frame_rate);
frame_rate->set_value(current_frame_rate, false);
percent->set_value(current_percent, false);
duration->set_default_value(default_length);
duration->set_value((current_length == -1) ? qSNaN() : current_length, false);
frame_rate->setEnabled(enable_frame_rate);
frame_rate->set_default_value(default_frame_rate);
frame_rate->set_value(current_frame_rate, false);
percent->set_value(current_percent, false);
duration->set_default_value(default_length);
duration->set_value((current_length == -1) ? qSNaN() : current_length, false);
exec();
exec();
}
void SpeedDialog::percent_update() {
bool got_fr = false;
double fr_val = qSNaN();
long len_val = -1;
bool got_fr = false;
double fr_val = qSNaN();
long len_val = -1;
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
// get frame rate
if (frame_rate->isEnabled() && c->track < 0) {
double clip_fr = c->getMediaFrameRate() * percent->value();
if (got_fr) {
if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) {
fr_val = qSNaN();
}
} else {
fr_val = clip_fr;
got_fr = true;
}
}
// get frame rate
if (frame_rate->isEnabled() && c->track() < 0) {
double clip_fr = c->media_frame_rate() * percent->value();
if (got_fr) {
if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) {
fr_val = qSNaN();
}
} else {
fr_val = clip_fr;
got_fr = true;
}
}
// get duration
long clip_default_length = qRound(c->getLength() * c->speed);
long new_clip_length = qRound(clip_default_length / percent->value());
if (i == 0) {
len_val = new_clip_length;
} else if (len_val > -1 && len_val != new_clip_length) {
len_val = -1;
}
}
// get duration
long clip_default_length = qRound(c->length() * c->speed().value);
long new_clip_length = qRound(clip_default_length / percent->value());
if (i == 0) {
len_val = new_clip_length;
} else if (len_val > -1 && len_val != new_clip_length) {
len_val = -1;
}
}
frame_rate->set_value(fr_val, false);
duration->set_value((len_val == -1) ? qSNaN() : len_val, false);
frame_rate->set_value(fr_val, false);
duration->set_value((len_val == -1) ? qSNaN() : len_val, false);
}
void SpeedDialog::duration_update() {
double pc_val = qSNaN();
bool got_fr = false;
double fr_val = qSNaN();
double pc_val = qSNaN();
bool got_fr = false;
double fr_val = qSNaN();
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
// get percent
long clip_default_length = qRound(c->getLength() * c->speed);
double clip_pc = clip_default_length / duration->value();
if (i == 0) {
pc_val = clip_pc;
} else if (!qIsNaN(pc_val) && !qFuzzyCompare(clip_pc, pc_val)) {
pc_val = qSNaN();
}
// get percent
long clip_default_length = qRound(c->length() * c->speed().value);
double clip_pc = clip_default_length / duration->value();
if (i == 0) {
pc_val = clip_pc;
} else if (!qIsNaN(pc_val) && !qFuzzyCompare(clip_pc, pc_val)) {
pc_val = qSNaN();
}
// get frame rate
if (frame_rate->isEnabled() && c->track < 0) {
double clip_fr = c->getMediaFrameRate() * clip_pc;
if (got_fr) {
if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) {
fr_val = qSNaN();
}
} else {
fr_val = clip_fr;
got_fr = true;
}
}
}
// get frame rate
if (frame_rate->isEnabled() && c->track() < 0) {
double clip_fr = c->media_frame_rate() * clip_pc;
if (got_fr) {
if (!qIsNaN(fr_val) && !qFuzzyCompare(fr_val, clip_fr)) {
fr_val = qSNaN();
}
} else {
fr_val = clip_fr;
got_fr = true;
}
}
}
frame_rate->set_value(fr_val, false);
percent->set_value(pc_val, false);
frame_rate->set_value(fr_val, false);
percent->set_value(pc_val, false);
}
void SpeedDialog::frame_rate_update() {
/*double fr = (frame_rate->value());
double pc = (fr / default_frame_rate);
percent->set_value(pc, false);
duration->set_value(default_length / pc, false);*/
/*double fr = (frame_rate->value());
double pc = (fr / default_frame_rate);
percent->set_value(pc, false);
duration->set_value(default_length / pc, false);*/
double old_pc_val = qSNaN();
bool got_pc_val = false;
double pc_val = qSNaN();
bool got_len_val = false;
long len_val = -1;
double old_pc_val = qSNaN();
bool got_pc_val = false;
double pc_val = qSNaN();
bool got_len_val = false;
long len_val = -1;
// analyze video clips
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
// analyze video clips
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
// check if all selected clips are currently the same speed
if (i == 0) {
old_pc_val = c->speed;
} else if (!qIsNaN(old_pc_val) && !qFuzzyCompare(c->speed, old_pc_val)) {
old_pc_val = qSNaN();
}
// check if all selected clips are currently the same speed
if (i == 0) {
old_pc_val = c->speed().value;
} else if (!qIsNaN(old_pc_val) && !qFuzzyCompare(c->speed().value, old_pc_val)) {
old_pc_val = qSNaN();
}
if (c->track < 0) {
// what would the new speed be based on this frame rate
double new_clip_speed = frame_rate->value() / c->getMediaFrameRate();
if (!got_pc_val) {
pc_val = new_clip_speed;
got_pc_val = true;
} else if (!qIsNaN(pc_val) && !qFuzzyCompare(pc_val, new_clip_speed)) {
pc_val = qSNaN();
}
if (c->track() < 0) {
// what would the new speed be based on this frame rate
double new_clip_speed = frame_rate->value() / c->media_frame_rate();
if (!got_pc_val) {
pc_val = new_clip_speed;
got_pc_val = true;
} else if (!qIsNaN(pc_val) && !qFuzzyCompare(pc_val, new_clip_speed)) {
pc_val = qSNaN();
}
// what would be the new length based on this speed
long new_clip_len = (c->getLength() * c->speed) / new_clip_speed;
if (!got_len_val) {
len_val = new_clip_len;
got_len_val = true;
} else if (len_val > -1 && new_clip_len != len_val) {
len_val = -1;
}
}
}
// what would be the new length based on this speed
long new_clip_len = (c->length() * c->speed().value) / new_clip_speed;
if (!got_len_val) {
len_val = new_clip_len;
got_len_val = true;
} else if (len_val > -1 && new_clip_len != len_val) {
len_val = -1;
}
}
}
// analyze audio clips
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
// analyze audio clips
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
if (c->track >= 0) {
long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ? c->getLength() : ((c->getLength() * c->speed) / pc_val);
if (len_val > -1 && new_clip_len != len_val) {
len_val = -1;
break;
}
}
}
if (c->track() >= 0) {
long new_clip_len = (qIsNaN(old_pc_val) || qIsNaN(pc_val)) ? c->length() : ((c->length() * c->speed().value) / pc_val);
if (len_val > -1 && new_clip_len != len_val) {
len_val = -1;
break;
}
}
}
percent->set_value(pc_val, false);
duration->set_value((len_val == -1) ? qSNaN() : len_val, false);
percent->set_value(pc_val, false);
duration->set_value((len_val == -1) ? qSNaN() : len_val, false);
}
void set_speed(ComboAction* ca, ClipPtr c, double speed, bool ripple, long& ep, long& lr) {
panel_timeline->deselect_area(c->timeline_in, c->timeline_out, c->track);
panel_timeline->deselect_area(c->timeline_in(), c->timeline_out(), c->track());
long proposed_out = c->timeline_out;
double multiplier = (c->speed / speed);
proposed_out = c->timeline_in + (c->getLength() * multiplier);
ca->append(new SetSpeedAction(c, speed));
if (!ripple && proposed_out > c->timeline_out) {
for (int i=0;i<c->sequence->clips.size();i++) {
long proposed_out = c->timeline_out();
double multiplier = (c->speed().value / speed);
proposed_out = c->timeline_in() + (c->length() * multiplier);
ca->append(new SetSpeedAction(c, speed));
if (!ripple && proposed_out > c->timeline_out()) {
for (int i=0;i<c->sequence->clips.size();i++) {
ClipPtr compare = c->sequence->clips.at(i);
if (compare != nullptr
&& compare->track == c->track
&& compare->timeline_in >= c->timeline_out && compare->timeline_in < proposed_out) {
proposed_out = compare->timeline_in;
}
}
}
ep = qMin(ep, c->timeline_out);
lr = qMax(lr, proposed_out - c->timeline_out);
move_clip(ca, c, c->timeline_in, proposed_out, c->clip_in * multiplier, c->track);
if (compare != nullptr
&& compare->track() == c->track()
&& compare->timeline_in() >= c->timeline_out() && compare->timeline_in() < proposed_out) {
proposed_out = compare->timeline_in();
}
}
}
ep = qMin(ep, c->timeline_out());
lr = qMax(lr, proposed_out - c->timeline_out());
move_clip(ca, c, c->timeline_in(), proposed_out, qRound(c->clip_in() * multiplier), c->track());
c->refactor_frame_rate(ca, multiplier, false);
c->refactor_frame_rate(ca, multiplier, false);
Selection sel;
sel.in = c->timeline_in;
sel.out = proposed_out;
sel.track = c->track;
olive::ActiveSequence->selections.append(sel);
Selection sel;
sel.in = c->timeline_in();
sel.out = proposed_out;
sel.track = c->track();
olive::ActiveSequence->selections.append(sel);
}
void SpeedDialog::accept() {
ComboAction* ca = new ComboAction();
ComboAction* ca = new ComboAction();
SetSelectionsCommand* sel_command = new SetSelectionsCommand(olive::ActiveSequence);
sel_command->old_data = olive::ActiveSequence->selections;
// undoable action for setting "maintain audio pitch"
SetClipProperty* audio_pitch_action = new SetClipProperty(kSetClipPropertyMaintainAudioPitch);
long earliest_point = LONG_MAX;
long longest_ripple = LONG_MIN;
// undoable action for setting "reversed"
SetClipProperty* reversed_action = new SetClipProperty(kSetClipPropertyReversed);
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
if (c->open) close_clip(c, true);
// undoable action for restoring clip selections
SetSelectionsCommand* sel_command = new SetSelectionsCommand(olive::ActiveSequence);
sel_command->old_data = olive::ActiveSequence->selections;
if (c->track >= 0
&& maintain_pitch->checkState() != Qt::PartiallyChecked
&& c->maintain_audio_pitch != maintain_pitch->isChecked()) {
ca->append(new SetBool(&c->maintain_audio_pitch, maintain_pitch->isChecked()));
}
// variables used to calculate ripples
long earliest_point = LONG_MAX;
long longest_ripple = LONG_MIN;
if (reverse->checkState() != Qt::PartiallyChecked && c->reverse != reverse->isChecked()) {
long new_clip_in = (c->getMaximumLength() - (c->getLength() + c->clip_in));
move_clip(ca, c, c->timeline_in, c->timeline_out, new_clip_in, c->track);
c->clip_in = new_clip_in;
ca->append(new SetBool(&c->reverse, reverse->isChecked()));
}
}
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
if (!qIsNaN(percent->value())) {
// simply set speed
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
set_speed(ca, c, percent->value(), ripple->isChecked(), earliest_point, longest_ripple);
}
} else if (!qIsNaN(frame_rate->value())) {
bool can_change_all = true;
double cached_speed;
double cached_fr = qSNaN();
// make sure the clip is closed while we're making changes
if (c->IsOpen()) {
c->Close(true);
}
// see if we can use the frame rate to change all the speeds
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
if (i == 0) {
cached_speed = c->speed;
} else if (!qFuzzyCompare(cached_speed, c->speed)) {
can_change_all = false;
}
if (c->track < 0) {
if (qIsNaN(cached_fr)) {
cached_fr = c->getMediaFrameRate();
} else if (!qFuzzyCompare(cached_fr, c->getMediaFrameRate())) {
can_change_all = false;
break;
}
}
}
// set maintain audio pitch if the user made a selection
if (c->track() >= 0
&& maintain_pitch->checkState() != Qt::PartiallyChecked
&& c->speed().maintain_audio_pitch != maintain_pitch->isChecked()) {
audio_pitch_action->AddSetting(c, maintain_pitch->isChecked());
}
// make changes
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
if (c->track < 0) {
set_speed(ca, c, frame_rate->value() / c->getMediaFrameRate(), ripple->isChecked(), earliest_point, longest_ripple);
} else if (can_change_all) {
set_speed(ca, c, frame_rate->value() / cached_fr, ripple->isChecked(), earliest_point, longest_ripple);
}
}
} else if (!qIsNaN(duration->value())) {
// simply set duration
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
set_speed(ca, c, (c->getLength() * c->speed) / duration->value(), ripple->isChecked(), earliest_point, longest_ripple);
}
}
// set reverse setting if the user made a selection
if (reverse->checkState() != Qt::PartiallyChecked && c->reversed() != reverse->isChecked()) {
long new_clip_in = (c->media_length() - (c->length() + c->clip_in()));
move_clip(ca, c, c->timeline_in(), c->timeline_out(), new_clip_in, c->track());
c->set_clip_in(new_clip_in);
reversed_action->AddSetting(c, reverse->isChecked());
}
}
if (ripple->isChecked()) {
ripple_clips(ca, clips.at(0)->sequence, earliest_point, longest_ripple);
}
// setting the actual speed
if (!qIsNaN(percent->value())) {
sel_command->new_data = olive::ActiveSequence->selections;
ca->append(sel_command);
// if we have a percentage value, use that on all the clips
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
set_speed(ca, c, percent->value(), ripple->isChecked(), earliest_point, longest_ripple);
}
olive::UndoStack.push(ca);
} else if (!qIsNaN(frame_rate->value())) {
update_ui(true);
QDialog::accept();
// if the user changed the speed by changing the frame rate,
bool can_change_all = true;
double cached_speed;
double cached_fr = qSNaN();
// see if we can use the frame rate to change all the speeds
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
if (i == 0) {
cached_speed = c->speed().value;
} else if (!qFuzzyCompare(cached_speed, c->speed().value)) {
can_change_all = false;
}
if (c->track() < 0) {
if (qIsNaN(cached_fr)) {
cached_fr = c->media_frame_rate();
} else if (!qFuzzyCompare(cached_fr, c->media_frame_rate())) {
can_change_all = false;
break;
}
}
}
// make changes
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
if (c->track() < 0) {
set_speed(ca, c, frame_rate->value() / c->media_frame_rate(), ripple->isChecked(), earliest_point, longest_ripple);
} else if (can_change_all) {
set_speed(ca, c, frame_rate->value() / cached_fr, ripple->isChecked(), earliest_point, longest_ripple);
}
}
} else if (!qIsNaN(duration->value())) {
// simply set duration
for (int i=0;i<clips.size();i++) {
ClipPtr c = clips.at(i);
set_speed(ca, c, (c->length() * c->speed().value) / duration->value(), ripple->isChecked(), earliest_point, longest_ripple);
}
}
if (ripple->isChecked()) {
ripple_clips(ca, clips.at(0)->sequence, earliest_point, longest_ripple);
}
sel_command->new_data = olive::ActiveSequence->selections;
ca->append(sel_command);
ca->append(reversed_action);
ca->append(audio_pitch_action);
olive::UndoStack.push(ca);
update_ui(true);
QDialog::accept();
}