better support for various bit rates
This commit is contained in:
@@ -351,8 +351,8 @@ void ExportDialog::export_thread_finished() {
|
||||
prep_ui_for_render(false);
|
||||
|
||||
// Move OpenGL context back to the sequence viewer
|
||||
panel_sequence_viewer->viewer_widget->makeCurrent();
|
||||
panel_sequence_viewer->viewer_widget->initializeGL();
|
||||
panel_sequence_viewer->viewer_widget()->makeCurrent();
|
||||
panel_sequence_viewer->viewer_widget()->initializeGL();
|
||||
|
||||
// Update the application UI
|
||||
update_ui(false);
|
||||
@@ -573,9 +573,9 @@ void ExportDialog::StartExport() {
|
||||
panel_effect_controls->Clear();
|
||||
|
||||
// Close all currently open clips
|
||||
close_active_clips(olive::ActiveSequence.get());
|
||||
olive::ActiveSequence->Close();
|
||||
|
||||
olive::Global->set_rendering_state(true);
|
||||
olive::Global->set_export_state(true);
|
||||
|
||||
olive::Global->save_autorecovery_file();
|
||||
|
||||
|
||||
@@ -30,10 +30,8 @@
|
||||
#include <QListWidget>
|
||||
#include <QCheckBox>
|
||||
#include <QSpinBox>
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
#endif
|
||||
|
||||
#include "project/footage.h"
|
||||
#include "project/media.h"
|
||||
@@ -133,26 +131,26 @@ MediaPropertiesDialog::MediaPropertiesDialog(QWidget *parent, Media *i) :
|
||||
|
||||
row++;
|
||||
|
||||
#ifndef NO_OCIO
|
||||
color_management = new QComboBox(this);
|
||||
input_color_space = new QComboBox(this);
|
||||
|
||||
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
|
||||
|
||||
QString footage_colorspace = f->Colorspace();
|
||||
|
||||
for (int i=0;i<config->getNumColorSpaces();i++) {
|
||||
QString colorspace = config->getColorSpaceNameByIndex(i);
|
||||
|
||||
color_management->addItem(colorspace);
|
||||
input_color_space->addItem(colorspace);
|
||||
|
||||
if (colorspace == f->colorspace) {
|
||||
color_management->setCurrentIndex(i);
|
||||
if (colorspace == footage_colorspace) {
|
||||
input_color_space->setCurrentIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
grid->addWidget(new QLabel(tr("Color Space:")), row, 0);
|
||||
grid->addWidget(color_management, row, 1);
|
||||
grid->addWidget(input_color_space, row, 1);
|
||||
|
||||
row++;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -221,9 +219,7 @@ void MediaPropertiesDialog::accept() {
|
||||
f->alpha_is_associated = premultiply_alpha_setting->isChecked();
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
f->colorspace = color_management->currentText();
|
||||
#endif
|
||||
f->SetColorspace(input_color_space->currentText());
|
||||
|
||||
// set name
|
||||
MediaRename* mr = new MediaRename(item, name_box->text());
|
||||
|
||||
@@ -83,7 +83,7 @@ private:
|
||||
*/
|
||||
QCheckBox* premultiply_alpha_setting;
|
||||
|
||||
QComboBox* color_management;
|
||||
QComboBox* input_color_space;
|
||||
private slots:
|
||||
/**
|
||||
* @brief Overrided accept function for saving the properties back to the Media class
|
||||
|
||||
+137
-117
@@ -168,7 +168,6 @@ void PreferencesDialog::delete_previews(PreviewDeleteTypes type) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
void PreferencesDialog::populate_ocio_menus(OCIO::ConstConfigRcPtr config)
|
||||
{
|
||||
// Get current display name (if the config is empty, get the current default display)
|
||||
@@ -240,7 +239,6 @@ void PreferencesDialog::update_ocio_config(const QString &s)
|
||||
} catch (OCIO::Exception& e) {}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void PreferencesDialog::AddBoolPair(QCheckBox *ui, bool *value, bool restart_required)
|
||||
{
|
||||
@@ -279,6 +277,8 @@ void PreferencesDialog::accept() {
|
||||
bool reinit_audio = false;
|
||||
bool reload_language = false;
|
||||
bool reload_effects = false;
|
||||
bool reset_ocio_shaders = false;
|
||||
bool reset_render_threads = false;
|
||||
|
||||
// Validate whether the specified CSS file exists
|
||||
if (!custom_css_fn->text().isEmpty() && !QFileInfo::exists(custom_css_fn->text())) {
|
||||
@@ -290,31 +290,45 @@ void PreferencesDialog::accept() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate whether the OCIO config path exists
|
||||
if (enable_color_management->isChecked() && !QFileInfo::exists(ocio_config_file->text())) {
|
||||
// Validate whether the chosen OCIO configuration file
|
||||
if (enable_color_management->isChecked()) {
|
||||
|
||||
QString msg_title = tr("Invalid OpenColorIO Configuration File");
|
||||
QString msg_body;
|
||||
// Check whether the file exists
|
||||
if (!QFileInfo::exists(ocio_config_file->text())) {
|
||||
|
||||
QString msg_title = tr("Invalid OpenColorIO Configuration File");
|
||||
QString msg_body;
|
||||
|
||||
if (ocio_config_file->text().isEmpty()) {
|
||||
msg_body = tr("You must specify an OpenColorIO configuration file if color management is enabled.");
|
||||
} else {
|
||||
msg_body = tr("OpenColorIO configuration file '%1' does not exist.").arg(ocio_config_file->text());
|
||||
}
|
||||
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
msg_title,
|
||||
msg_body
|
||||
);
|
||||
return;
|
||||
|
||||
} else if (olive::CurrentConfig.ocio_config_path != ocio_config_file->text()) {
|
||||
|
||||
// Check whether OCIO can load it
|
||||
try {
|
||||
OCIO::Config::CreateFromFile(ocio_config_file->text().toUtf8());
|
||||
} catch (OCIO::Exception& e) {
|
||||
QMessageBox::critical(this,
|
||||
tr("OpenColorIO Config Error"),
|
||||
tr("Failed to set OpenColorIO configuration: %1").arg(e.what()),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ocio_config_file->text().isEmpty()) {
|
||||
msg_body = tr("You must specify an OpenColorIO configuration file if color management is enabled.");
|
||||
} else {
|
||||
msg_body = tr("OpenColorIO configuration file '%1' does not exist.").arg(ocio_config_file->text());
|
||||
}
|
||||
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
msg_title,
|
||||
msg_body
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate whether the effects panel should refresh itself
|
||||
if (olive::CurrentConfig.effect_textbox_lines != effect_textbox_lines_field->value()) {
|
||||
reload_effects = true;
|
||||
}
|
||||
|
||||
// Validate whether one of the bool options requires a restart
|
||||
bool bool_requires_restart = false;
|
||||
for (int i=0;i<bool_restart_required.size();i++) {
|
||||
if (bool_restart_required.at(i)
|
||||
@@ -324,7 +338,7 @@ void PreferencesDialog::accept() {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any settings will require a restart of Olive
|
||||
// Check if any settings will require a restart of Olive (including the bool options determined above)
|
||||
if (bool_requires_restart
|
||||
|| olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value()
|
||||
|| olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()
|
||||
@@ -355,20 +369,8 @@ void PreferencesDialog::accept() {
|
||||
|
||||
}
|
||||
|
||||
// Audio settings may require the audio device to be re-initiated.
|
||||
if (olive::CurrentConfig.preferred_audio_output != audio_output_devices->currentData().toString()
|
||||
|| olive::CurrentConfig.preferred_audio_input != audio_input_devices->currentData().toString()
|
||||
|| olive::CurrentConfig.audio_rate != audio_sample_rate->currentData().toInt()) {
|
||||
reinit_audio = true;
|
||||
}
|
||||
|
||||
// see if the language file should be reloaded (not necessary if the app is restarting anyway)
|
||||
if (!restart_after_saving
|
||||
&& olive::CurrentConfig.language_file != language_combobox->currentData().toString()) {
|
||||
reload_language = true;
|
||||
}
|
||||
|
||||
// save settings from UI to backend
|
||||
// Everything checks out, start saving settings from the UI to the backend
|
||||
olive::CurrentConfig.css_path = custom_css_fn->text();
|
||||
olive::CurrentConfig.recording_mode = recordingComboBox->currentIndex() + 1;
|
||||
olive::CurrentConfig.img_seq_formats = imgSeqFormatEdit->text();
|
||||
@@ -377,53 +379,66 @@ void PreferencesDialog::accept() {
|
||||
olive::CurrentConfig.previous_queue_size = previous_queue_spinbox->value();
|
||||
olive::CurrentConfig.previous_queue_type = previous_queue_type->currentIndex();
|
||||
|
||||
// Audio settings may require the audio device to be re-initiated.
|
||||
if (olive::CurrentConfig.preferred_audio_output != audio_output_devices->currentData().toString()
|
||||
|| olive::CurrentConfig.preferred_audio_input != audio_input_devices->currentData().toString()
|
||||
|| olive::CurrentConfig.audio_rate != audio_sample_rate->currentData().toInt()) {
|
||||
reinit_audio = true;
|
||||
}
|
||||
olive::CurrentConfig.preferred_audio_output = audio_output_devices->currentData().toString();
|
||||
olive::CurrentConfig.preferred_audio_input = audio_input_devices->currentData().toString();
|
||||
olive::CurrentConfig.audio_rate = audio_sample_rate->currentData().toInt();
|
||||
|
||||
olive::CurrentConfig.effect_textbox_lines = effect_textbox_lines_field->value();
|
||||
|
||||
// see if the language file should be reloaded (not necessary if the app is restarting anyway)
|
||||
if (!restart_after_saving
|
||||
&& olive::CurrentConfig.language_file != language_combobox->currentData().toString()) {
|
||||
reload_language = true;
|
||||
}
|
||||
olive::CurrentConfig.language_file = language_combobox->currentData().toString();
|
||||
|
||||
olive::CurrentConfig.enable_color_management = enable_color_management->isChecked();
|
||||
|
||||
#ifndef NO_OCIO
|
||||
if (olive::CurrentConfig.ocio_config_path != ocio_config_file->text()) {
|
||||
try {
|
||||
OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(ocio_config_file->text().toUtf8()));
|
||||
|
||||
olive::CurrentConfig.ocio_config_path = ocio_config_file->text();
|
||||
} catch (OCIO::Exception& e) {
|
||||
QMessageBox::critical(this,
|
||||
tr("OpenColorIO Config Error"),
|
||||
tr("Failed to set OpenColorIO configuration: %1").arg(e.what()),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
|
||||
// Check whether OCIO settings will require a reset of the render threads
|
||||
if (olive::CurrentConfig.playback_bit_depth != playback_bit_depth->currentIndex()
|
||||
|| olive::CurrentConfig.export_bit_depth != export_bit_depth->currentIndex()) {
|
||||
reset_render_threads = true;
|
||||
}
|
||||
|
||||
if (olive::CurrentConfig.ocio_config_path != ocio_config_file->text()
|
||||
|| olive::CurrentConfig.ocio_display != ocio_display->currentText()
|
||||
|| olive::CurrentConfig.ocio_view != ocio_view->currentText()
|
||||
|| olive::CurrentConfig.ocio_look != ocio_look->currentData().toString()) {
|
||||
reset_ocio_shaders = true;
|
||||
}
|
||||
if (olive::CurrentConfig.ocio_config_path != ocio_config_file->text()) {
|
||||
OCIO::SetCurrentConfig(OCIO::Config::CreateFromFile(ocio_config_file->text().toUtf8()));
|
||||
olive::CurrentConfig.ocio_config_path = ocio_config_file->text();
|
||||
}
|
||||
olive::CurrentConfig.enable_color_management = enable_color_management->isChecked();
|
||||
olive::CurrentConfig.playback_bit_depth = playback_bit_depth->currentIndex();
|
||||
olive::CurrentConfig.export_bit_depth = export_bit_depth->currentIndex();
|
||||
olive::CurrentConfig.ocio_display = ocio_display->currentText();
|
||||
olive::CurrentConfig.ocio_view = ocio_view->currentText();
|
||||
|
||||
// We use data here instead of text because there's a "(None)" option with an empty string
|
||||
olive::CurrentConfig.ocio_look = ocio_look->currentData().toString();
|
||||
|
||||
olive::CurrentRuntimeConfig.ocio_config_date = QDateTime::currentMSecsSinceEpoch();
|
||||
#endif
|
||||
|
||||
|
||||
// Set default sequence options
|
||||
olive::CurrentConfig.default_sequence_width = default_sequence.width;
|
||||
olive::CurrentConfig.default_sequence_height = default_sequence.height;
|
||||
olive::CurrentConfig.default_sequence_framerate = default_sequence.frame_rate;
|
||||
olive::CurrentConfig.default_sequence_audio_frequency = default_sequence.audio_frequency;
|
||||
olive::CurrentConfig.default_sequence_audio_channel_layout = default_sequence.audio_layout;
|
||||
|
||||
// Set all bool options
|
||||
for (int i=0;i<bool_ui.size();i++) {
|
||||
*bool_value[i] = bool_ui.at(i)->isChecked();
|
||||
}
|
||||
|
||||
// Set new style
|
||||
olive::CurrentConfig.style = static_cast<olive::styling::Style>(ui_style->currentData().toInt());
|
||||
|
||||
// Check if the thumbnail or waveform icon
|
||||
// Check if the thumbnail or waveform icon fields have changed, we may need to recreate the previews if so
|
||||
if (olive::CurrentConfig.thumbnail_resolution != thumbnail_res_spinbox->value()
|
||||
|| olive::CurrentConfig.waveform_resolution != waveform_res_spinbox->value()) {
|
||||
// we're changing the size of thumbnails and waveforms, so let's delete them and regenerate them next start
|
||||
@@ -461,29 +476,46 @@ void PreferencesDialog::accept() {
|
||||
key_shortcut_fields.at(i)->set_action_shortcut();
|
||||
}
|
||||
|
||||
// Audio settings may require the audio device to be re-initiated.
|
||||
if (reinit_audio) {
|
||||
init_audio();
|
||||
}
|
||||
|
||||
if (reload_effects) {
|
||||
panel_effect_controls->Reload();
|
||||
}
|
||||
|
||||
// reload language file if it changed
|
||||
if (reload_language) {
|
||||
olive::Global->load_translation_from_config();
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
|
||||
if (restart_after_saving) {
|
||||
|
||||
// since we already ran can_close_project(), bypass checking again by running set_modified(false)
|
||||
olive::Global->set_modified(false);
|
||||
|
||||
olive::MainWindow->close();
|
||||
|
||||
QProcess::startDetached(QApplication::applicationFilePath(), { olive::ActiveProjectFilename });
|
||||
} else {
|
||||
|
||||
// Audio settings may require the audio device to be re-initiated.
|
||||
if (reinit_audio) {
|
||||
init_audio();
|
||||
}
|
||||
|
||||
if (reload_effects) {
|
||||
panel_effect_controls->Reload();
|
||||
}
|
||||
|
||||
// reload language file if it changed
|
||||
if (reload_language) {
|
||||
olive::Global->load_translation_from_config();
|
||||
}
|
||||
|
||||
if (reset_render_threads) {
|
||||
if (panel_footage_viewer->seq != nullptr) {
|
||||
panel_footage_viewer->seq->Close();
|
||||
}
|
||||
panel_footage_viewer->viewer_widget()->get_renderer()->delete_ctx();
|
||||
if (panel_sequence_viewer->seq != nullptr) {
|
||||
panel_sequence_viewer->seq->Close();
|
||||
}
|
||||
panel_sequence_viewer->viewer_widget()->get_renderer()->delete_ctx();
|
||||
} else if (reset_ocio_shaders) {
|
||||
panel_footage_viewer->viewer_widget()->get_renderer()->destroy_ocio();
|
||||
panel_sequence_viewer->viewer_widget()->get_renderer()->destroy_ocio();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,12 +650,10 @@ void PreferencesDialog::browse_ocio_config()
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
void PreferencesDialog::update_ocio_view_menu()
|
||||
{
|
||||
update_ocio_view_menu(OCIO::GetCurrentConfig());
|
||||
}
|
||||
#endif
|
||||
|
||||
void PreferencesDialog::delete_all_previews() {
|
||||
if (QMessageBox::question(this,
|
||||
@@ -988,87 +1018,77 @@ void PreferencesDialog::setup_ui() {
|
||||
|
||||
row = 0;
|
||||
|
||||
#ifdef NO_OCIO
|
||||
QLabel* no_ocio_available_lbl = new QLabel(tr("<html><b>Color management is unavailable because Olive was "
|
||||
"compiled without OpenColorIO support.</b></html>"));
|
||||
no_ocio_available_lbl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
|
||||
color_management_layout->addWidget(no_ocio_available_lbl, row, 0, 1, 3);
|
||||
row++;
|
||||
#endif
|
||||
|
||||
// COLOR MANAGEMENT -> Enable Color Management
|
||||
enable_color_management = new QCheckBox(tr("Enable Color Management"));
|
||||
enable_color_management->setChecked(olive::CurrentConfig.enable_color_management);
|
||||
color_management_layout->addWidget(enable_color_management, row, 0, 1, 3);
|
||||
color_management_layout->addWidget(enable_color_management, row, 0);
|
||||
|
||||
row++;
|
||||
|
||||
QGroupBox* opencolorio_groupbox = new QGroupBox();
|
||||
QGridLayout* opencolorio_groupbox_layout = new QGridLayout(opencolorio_groupbox);
|
||||
|
||||
// COLOR MANAGEMENT -> OpenColorIO Config File
|
||||
color_management_layout->addWidget(new QLabel(tr("OpenColorIO Config File:")), row, 0);
|
||||
opencolorio_groupbox_layout->addWidget(new QLabel(tr("OpenColorIO Config File:")), 0, 0);
|
||||
|
||||
ocio_config_file = new QLineEdit();
|
||||
ocio_config_file->setText(olive::CurrentConfig.ocio_config_path);
|
||||
connect(ocio_config_file, SIGNAL(textChanged(const QString &)), this, SLOT(update_ocio_config(const QString&)));
|
||||
color_management_layout->addWidget(ocio_config_file, row, 1);
|
||||
opencolorio_groupbox_layout->addWidget(ocio_config_file, 0, 1, 1, 4);
|
||||
|
||||
QPushButton* ocio_config_browse_btn = new QPushButton(tr("Browse"));
|
||||
connect(ocio_config_browse_btn, SIGNAL(clicked(bool)), this, SLOT(browse_ocio_config()));
|
||||
color_management_layout->addWidget(ocio_config_browse_btn, row, 2);
|
||||
|
||||
row++;
|
||||
opencolorio_groupbox_layout->addWidget(ocio_config_browse_btn, 0, 5);
|
||||
|
||||
// COLOR MANAGEMENT -> Display
|
||||
ocio_display = new QComboBox();
|
||||
connect(ocio_display, SIGNAL(currentIndexChanged(int)), this, SLOT(update_ocio_view_menu()));
|
||||
color_management_layout->addWidget(new QLabel("Display:"), row, 0);
|
||||
color_management_layout->addWidget(ocio_display, row, 1);
|
||||
|
||||
row++;
|
||||
opencolorio_groupbox_layout->addWidget(new QLabel(tr("Display:")), 1, 0);
|
||||
opencolorio_groupbox_layout->addWidget(ocio_display, 1, 1);
|
||||
|
||||
// COLOR MANAGEMENT -> View
|
||||
ocio_view = new QComboBox();
|
||||
color_management_layout->addWidget(new QLabel("View:"), row, 0);
|
||||
color_management_layout->addWidget(ocio_view, row, 1);
|
||||
|
||||
row++;
|
||||
opencolorio_groupbox_layout->addWidget(new QLabel(tr("View:")), 1, 2);
|
||||
opencolorio_groupbox_layout->addWidget(ocio_view, 1, 3);
|
||||
|
||||
// COLOR MANAGEMENT -> Look
|
||||
ocio_look = new QComboBox();
|
||||
color_management_layout->addWidget(new QLabel("Look:"), row, 0);
|
||||
color_management_layout->addWidget(ocio_look, row, 1);
|
||||
opencolorio_groupbox_layout->addWidget(new QLabel(tr("Look:")), 1, 4);
|
||||
opencolorio_groupbox_layout->addWidget(ocio_look, 1, 5);
|
||||
|
||||
color_management_layout->addWidget(opencolorio_groupbox, row, 0);
|
||||
|
||||
row++;
|
||||
|
||||
// COLOR MANAGEMENT -> Playback Bit Depth
|
||||
QComboBox* playback_bit_depth = new QComboBox();
|
||||
// COLOR MANAGEMENT -> Bit Depth
|
||||
QGroupBox* bit_depth_groupbox = new QGroupBox(tr("Bit Depth"));
|
||||
QGridLayout* bit_depth_groupbox_layout = new QGridLayout(bit_depth_groupbox);
|
||||
|
||||
// COLOR MANAGEMENT -> Bit Depth -> Playback
|
||||
playback_bit_depth = new QComboBox();
|
||||
for (int i=0;i<olive::rendering::bit_depths.size();i++) {
|
||||
playback_bit_depth->addItem(olive::rendering::bit_depths.at(i).name, i);
|
||||
}
|
||||
color_management_layout->addWidget(new QLabel("Playback Bit Depth:"), row, 0);
|
||||
color_management_layout->addWidget(playback_bit_depth, row, 1);
|
||||
playback_bit_depth->setCurrentIndex(olive::CurrentConfig.playback_bit_depth);
|
||||
bit_depth_groupbox_layout->addWidget(new QLabel(tr("Playback (Offline):")), 0, 0);
|
||||
bit_depth_groupbox_layout->addWidget(playback_bit_depth, 0, 1);
|
||||
|
||||
row++;
|
||||
|
||||
// COLOR MANAGEMENT -> Rendering Bit Depth
|
||||
QComboBox* rendering_bit_depth = new QComboBox();
|
||||
// COLOR MANAGEMENT -> Bit Depth -> Export
|
||||
export_bit_depth = new QComboBox();
|
||||
for (int i=0;i<olive::rendering::bit_depths.size();i++) {
|
||||
rendering_bit_depth->addItem(olive::rendering::bit_depths.at(i).name, i);
|
||||
export_bit_depth->addItem(olive::rendering::bit_depths.at(i).name, i);
|
||||
}
|
||||
color_management_layout->addWidget(new QLabel("Rendering Bit Depth:"), row, 0);
|
||||
color_management_layout->addWidget(rendering_bit_depth, row, 1);
|
||||
export_bit_depth->setCurrentIndex(olive::CurrentConfig.export_bit_depth);
|
||||
bit_depth_groupbox_layout->addWidget(new QLabel(tr("Export (Online):")), 0, 2);
|
||||
bit_depth_groupbox_layout->addWidget(export_bit_depth, 0, 3);
|
||||
|
||||
row++;
|
||||
color_management_layout->addWidget(bit_depth_groupbox, row, 0);
|
||||
|
||||
|
||||
|
||||
//row++;
|
||||
|
||||
#ifdef NO_OCIO
|
||||
enable_color_management->setEnabled(false);
|
||||
ocio_config_file->setEnabled(false);
|
||||
ocio_config_browse_btn->setEnabled(false);
|
||||
ocio_display->setEnabled(false);
|
||||
ocio_view->setEnabled(false);
|
||||
ocio_look->setEnabled(false);
|
||||
#else
|
||||
populate_ocio_menus(OCIO::GetCurrentConfig());
|
||||
#endif
|
||||
|
||||
tabWidget->addTab(color_management_tab, tr("Color Management"));
|
||||
|
||||
|
||||
@@ -33,10 +33,8 @@
|
||||
#include <QCheckBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QSpinBox>
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
#endif
|
||||
|
||||
#include "timeline/sequence.h"
|
||||
|
||||
@@ -125,11 +123,9 @@ private slots:
|
||||
void browse_ocio_config();
|
||||
|
||||
// OCIO function
|
||||
#ifndef NO_OCIO
|
||||
void update_ocio_view_menu();
|
||||
void update_ocio_view_menu(OCIO::ConstConfigRcPtr config);
|
||||
void update_ocio_config(const QString&);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Shows a NewSequenceDialog attached to default_sequence
|
||||
@@ -188,9 +184,7 @@ private:
|
||||
*/
|
||||
void delete_previews(PreviewDeleteTypes type);
|
||||
|
||||
#ifndef NO_OCIO
|
||||
void populate_ocio_menus(OCIO::ConstConfigRcPtr config);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief UI widget for editing the CSS filename
|
||||
@@ -273,6 +267,8 @@ private:
|
||||
QComboBox* ocio_display;
|
||||
QComboBox* ocio_view;
|
||||
QComboBox* ocio_look;
|
||||
QComboBox* playback_bit_depth;
|
||||
QComboBox* export_bit_depth;
|
||||
|
||||
/**
|
||||
* @brief UI widget for selecting the current UI style
|
||||
|
||||
+2
-2
@@ -424,7 +424,7 @@ void Effect::move_up() {
|
||||
command->to = command->from - 1;
|
||||
olive::UndoStack.push(command);
|
||||
panel_effect_controls->Reload();
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
panel_sequence_viewer->viewer_widget()->frame_update();
|
||||
}
|
||||
|
||||
void Effect::move_down() {
|
||||
@@ -439,7 +439,7 @@ void Effect::move_down() {
|
||||
command->to = command->from + 1;
|
||||
olive::UndoStack.push(command);
|
||||
panel_effect_controls->Reload();
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
panel_sequence_viewer->viewer_widget()->frame_update();
|
||||
}
|
||||
|
||||
void Effect::save_to_file() {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "rendering/renderfunctions.h"
|
||||
#include "global/config.h"
|
||||
#include "global/timing.h"
|
||||
#include "effects/effectrow.h"
|
||||
#include "effects/effect.h"
|
||||
#include "undo/undo.h"
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/sequence.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "global/timing.h"
|
||||
#include "ui/comboboxex.h"
|
||||
#include "ui/colorbutton.h"
|
||||
#include "global/config.h"
|
||||
|
||||
+12
-3
@@ -79,7 +79,9 @@ Config::Config()
|
||||
default_sequence_height(1080),
|
||||
default_sequence_framerate(29.97),
|
||||
default_sequence_audio_frequency(48000),
|
||||
default_sequence_audio_channel_layout(3)
|
||||
default_sequence_audio_channel_layout(3),
|
||||
playback_bit_depth(olive::rendering::PIX_FMT_RGBA16F),
|
||||
export_bit_depth(olive::rendering::PIX_FMT_RGBA32F)
|
||||
{}
|
||||
|
||||
void Config::load(QString path) {
|
||||
@@ -246,6 +248,12 @@ void Config::load(QString path) {
|
||||
} else if (stream.name() == "DefaultSequenceAudioLayout") {
|
||||
stream.readNext();
|
||||
default_sequence_audio_channel_layout = stream.text().toInt();
|
||||
} else if (stream.name() == "PlaybackBitDepth") {
|
||||
stream.readNext();
|
||||
playback_bit_depth = stream.text().toInt();
|
||||
} else if (stream.name() == "ExportBitDepth") {
|
||||
stream.readNext();
|
||||
export_bit_depth = stream.text().toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,6 +330,8 @@ void Config::save(QString path) {
|
||||
stream.writeTextElement("DefaultSequenceFrameRate", QString::number(default_sequence_framerate));
|
||||
stream.writeTextElement("DefaultSequenceAudioFrequency", QString::number(default_sequence_audio_frequency));
|
||||
stream.writeTextElement("DefaultSequenceAudioLayout", QString::number(default_sequence_audio_channel_layout));
|
||||
stream.writeTextElement("PlaybackBitDepth", QString::number(playback_bit_depth));
|
||||
stream.writeTextElement("ExportBitDepth", QString::number(export_bit_depth));
|
||||
|
||||
stream.writeEndElement(); // configuration
|
||||
stream.writeEndDocument(); // doc
|
||||
@@ -329,6 +339,5 @@ void Config::save(QString path) {
|
||||
}
|
||||
|
||||
RuntimeConfig::RuntimeConfig() :
|
||||
shaders_are_enabled(true),
|
||||
ocio_config_date(QDateTime::currentMSecsSinceEpoch())
|
||||
shaders_are_enabled(true)
|
||||
{}
|
||||
|
||||
+10
-7
@@ -593,6 +593,16 @@ struct Config {
|
||||
*/
|
||||
int default_sequence_audio_channel_layout;
|
||||
|
||||
/**
|
||||
* @brief Playback bit depth (an index of olive::rendering::bit_depths)
|
||||
*/
|
||||
int playback_bit_depth;
|
||||
|
||||
/**
|
||||
* @brief Export bit depth (an index of olive::rendering::bit_depths)
|
||||
*/
|
||||
int export_bit_depth;
|
||||
|
||||
/**
|
||||
* @brief Load config from file
|
||||
*
|
||||
@@ -644,13 +654,6 @@ struct RuntimeConfig {
|
||||
*/
|
||||
QString external_translation_file;
|
||||
|
||||
/**
|
||||
* @brief OpenColorIO Configuration Time
|
||||
*
|
||||
* A crude but quick way of determining whether the OCIO config has changed and if the rendering threads need to
|
||||
* re-create their OCIO shaders. Not intended to be saved - could be moved
|
||||
*/
|
||||
qint64 ocio_config_date;
|
||||
};
|
||||
|
||||
namespace olive {
|
||||
|
||||
+9
-3
@@ -52,7 +52,8 @@ QString olive::ActiveProjectFilename;
|
||||
QString olive::AppName;
|
||||
|
||||
OliveGlobal::OliveGlobal() :
|
||||
changed_since_last_autorecovery(false)
|
||||
changed_since_last_autorecovery(false),
|
||||
rendering_(false)
|
||||
{
|
||||
// sets current app name
|
||||
QString version_id;
|
||||
@@ -108,8 +109,13 @@ void OliveGlobal::check_for_autorecovery_file() {
|
||||
}
|
||||
}
|
||||
|
||||
void OliveGlobal::set_rendering_state(bool rendering) {
|
||||
audio_rendering = rendering;
|
||||
bool OliveGlobal::is_exporting()
|
||||
{
|
||||
return rendering_;
|
||||
}
|
||||
|
||||
void OliveGlobal::set_export_state(bool rendering) {
|
||||
rendering_ = rendering;
|
||||
if (rendering) {
|
||||
autorecovery_timer.stop();
|
||||
} else {
|
||||
|
||||
+16
-1
@@ -74,6 +74,16 @@ public:
|
||||
*/
|
||||
void check_for_autorecovery_file();
|
||||
|
||||
/**
|
||||
* @brief Get whether the project is currently being rendered or not. Useful for determining whether to treat the
|
||||
* render as online or offline.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* TRUE if the project is being exported, FALSE if not.
|
||||
*/
|
||||
bool is_exporting();
|
||||
|
||||
/**
|
||||
* @brief Set the application state depending on if the user is exporting a video
|
||||
*
|
||||
@@ -90,7 +100,7 @@ public:
|
||||
*
|
||||
* **TRUE** if Olive is about to export a video. **FALSE** if Olive has finished exporting.
|
||||
*/
|
||||
void set_rendering_state(bool rendering);
|
||||
void set_export_state(bool rendering);
|
||||
|
||||
/**
|
||||
* @brief Set the application's "modified" state
|
||||
@@ -423,6 +433,11 @@ private:
|
||||
*/
|
||||
bool changed_since_last_autorecovery;
|
||||
|
||||
/**
|
||||
* @brief Internal variable for rendering state (set by set_rendering_state() and accessed by is_rendering() ).
|
||||
*/
|
||||
bool rendering_;
|
||||
|
||||
private slots:
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
#include "timing.h"
|
||||
|
||||
#include "timeline/sequence.h"
|
||||
#include "timeline/clip.h"
|
||||
#include "global/config.h"
|
||||
|
||||
double get_timecode(Clip* c, long playhead) {
|
||||
return double(playhead_to_clip_frame(c, playhead))/c->sequence->frame_rate;
|
||||
}
|
||||
|
||||
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) {
|
||||
return qRound((double(framenumber)/source_frame_rate)*target_frame_rate);
|
||||
}
|
||||
|
||||
long playhead_to_clip_frame(Clip* c, long playhead) {
|
||||
return (qMax(0L, playhead - c->timeline_in(true)) + c->clip_in(true));
|
||||
}
|
||||
|
||||
double playhead_to_clip_seconds(Clip* c, long playhead) {
|
||||
// returns time in seconds
|
||||
long clip_frame = playhead_to_clip_frame(c, playhead);
|
||||
|
||||
if (c->reversed()) {
|
||||
clip_frame = c->media_length() - clip_frame - 1;
|
||||
}
|
||||
|
||||
double secs = (double(clip_frame)/c->sequence->frame_rate)*c->speed().value;
|
||||
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
secs *= c->media()->to_footage()->speed;
|
||||
}
|
||||
|
||||
return secs;
|
||||
}
|
||||
|
||||
int64_t seconds_to_timestamp(Clip *c, double seconds) {
|
||||
return qRound64(seconds * av_q2d(av_inv_q(c->time_base())));
|
||||
}
|
||||
|
||||
int64_t playhead_to_timestamp(Clip* c, long playhead) {
|
||||
return seconds_to_timestamp(c, playhead_to_clip_seconds(c, playhead));
|
||||
}
|
||||
|
||||
bool frame_rate_is_droppable(double rate) {
|
||||
return (qFuzzyCompare(rate, 23.976)
|
||||
|| qFuzzyCompare(rate, 29.97)
|
||||
|| qFuzzyCompare(rate, 59.94));
|
||||
}
|
||||
|
||||
long timecode_to_frame(const QString& s, int view, double frame_rate) {
|
||||
QList<QString> list = s.split(QRegExp("[:;]"));
|
||||
|
||||
if (view == olive::kTimecodeFrames || (list.size() == 1 && view != olive::kTimecodeMilliseconds)) {
|
||||
return s.toLong();
|
||||
}
|
||||
|
||||
int frRound = qRound(frame_rate);
|
||||
int hours, minutes, seconds, frames;
|
||||
|
||||
if (view == olive::kTimecodeMilliseconds) {
|
||||
long milliseconds = s.toLong();
|
||||
|
||||
hours = milliseconds/3600000;
|
||||
milliseconds -= (hours*3600000);
|
||||
minutes = milliseconds/60000;
|
||||
milliseconds -= (minutes*60000);
|
||||
seconds = milliseconds/1000;
|
||||
milliseconds -= (seconds*1000);
|
||||
frames = qRound64((milliseconds*0.001)*frame_rate);
|
||||
|
||||
seconds = qRound64(seconds * frame_rate);
|
||||
minutes = qRound64(minutes * frame_rate * 60);
|
||||
hours = qRound64(hours * frame_rate * 3600);
|
||||
} else {
|
||||
hours = ((list.size() > 0) ? list.at(0).toInt() : 0) * frRound * 3600;
|
||||
minutes = ((list.size() > 1) ? list.at(1).toInt() : 0) * frRound * 60;
|
||||
seconds = ((list.size() > 2) ? list.at(2).toInt() : 0) * frRound;
|
||||
frames = (list.size() > 3) ? list.at(3).toInt() : 0;
|
||||
}
|
||||
|
||||
int f = (frames + seconds + minutes + hours);
|
||||
|
||||
if ((view == olive::kTimecodeDrop || view == olive::kTimecodeMilliseconds) && frame_rate_is_droppable(frame_rate)) {
|
||||
// return drop
|
||||
int d;
|
||||
int m;
|
||||
|
||||
int dropFrames = qRound(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
|
||||
int framesPer10Minutes = qRound(frame_rate * 60 * 10); //Number of frames per ten minutes
|
||||
int framesPerMinute = (qRound(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
|
||||
|
||||
d = f / framesPer10Minutes;
|
||||
f -= dropFrames*9*d;
|
||||
|
||||
m = f % framesPer10Minutes;
|
||||
|
||||
if (m > dropFrames) {
|
||||
f -= (dropFrames * ((m - dropFrames) / framesPerMinute));
|
||||
}
|
||||
}
|
||||
|
||||
// return non-drop
|
||||
return f;
|
||||
}
|
||||
|
||||
QString frame_to_timecode(long f, int view, double frame_rate) {
|
||||
if (view == olive::kTimecodeFrames) {
|
||||
return QString::number(f);
|
||||
}
|
||||
|
||||
// return timecode
|
||||
int hours = 0;
|
||||
int mins = 0;
|
||||
int secs = 0;
|
||||
int frames = 0;
|
||||
QString token = ":";
|
||||
|
||||
if ((view == olive::kTimecodeDrop || view == olive::kTimecodeMilliseconds) && frame_rate_is_droppable(frame_rate)) {
|
||||
//CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE
|
||||
//Code by David Heidelberger, adapted from Andrew Duncan, further adapted for Olive by Olive Team
|
||||
//Given an int called framenumber and a double called framerate
|
||||
//Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off.
|
||||
|
||||
int d;
|
||||
int m;
|
||||
|
||||
int dropFrames = qRound(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
|
||||
int framesPerHour = qRound(frame_rate*60*60); //Number of frqRound64ames in an hour
|
||||
int framesPer24Hours = framesPerHour*24; //Number of frames in a day - timecode rolls over after 24 hours
|
||||
int framesPer10Minutes = qRound(frame_rate * 60 * 10); //Number of frames per ten minutes
|
||||
int framesPerMinute = (qRound(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
|
||||
|
||||
//If framenumber is greater than 24 hrs, next operation will rollover clock
|
||||
f = f % framesPer24Hours; // % is the modulus operator, which returns a remainder. a % b = the remainder of a/b
|
||||
|
||||
d = f / framesPer10Minutes; // \ means integer division, which is a/b without a remainder. Some languages you could use floor(a/b)
|
||||
m = f % framesPer10Minutes;
|
||||
|
||||
//In the original post, the next line read m>1, which only worked for 29.97. Jean-Baptiste Mardelle correctly pointed out that m should be compared to dropFrames.
|
||||
if (m > dropFrames) {
|
||||
f = f + (dropFrames*9*d) + dropFrames * ((m - dropFrames) / framesPerMinute);
|
||||
} else {
|
||||
f = f + dropFrames*9*d;
|
||||
}
|
||||
|
||||
int frRound = qRound(frame_rate);
|
||||
frames = f % frRound;
|
||||
secs = (f / frRound) % 60;
|
||||
mins = ((f / frRound) / 60) % 60;
|
||||
hours = (((f / frRound) / 60) / 60);
|
||||
|
||||
token = ";";
|
||||
} else {
|
||||
// non-drop timecode
|
||||
|
||||
int int_fps = qRound(frame_rate);
|
||||
hours = f / (3600 * int_fps);
|
||||
mins = f / (60*int_fps) % 60;
|
||||
secs = f/int_fps % 60;
|
||||
frames = f%int_fps;
|
||||
}
|
||||
if (view == olive::kTimecodeMilliseconds) {
|
||||
return QString::number((hours*3600000)+(mins*60000)+(secs*1000)+qCeil(frames*1000/frame_rate));
|
||||
}
|
||||
return QString(QString::number(hours).rightJustified(2, '0') +
|
||||
":" + QString::number(mins).rightJustified(2, '0') +
|
||||
":" + QString::number(secs).rightJustified(2, '0') +
|
||||
token + QString::number(frames).rightJustified(2, '0')
|
||||
);
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
#ifndef TIMING_H
|
||||
#define TIMING_H
|
||||
|
||||
#include <QString>
|
||||
#include <QtMath>
|
||||
|
||||
class Clip;
|
||||
|
||||
/**
|
||||
* @brief Get timecode
|
||||
*
|
||||
* Get the current clip/media time from the Timeline playhead in seconds. For instance if the playhead was at the start
|
||||
* of a clip (whose in point wasn't trimmed), this would be 0.0 as it's the start of the clip/media;
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* Clip to get the timecode of
|
||||
*
|
||||
* @param playhead
|
||||
*
|
||||
* Sequence playhead to convert to a clip/media timecode
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Timecode in seconds
|
||||
*/
|
||||
double get_timecode(Clip *c, long playhead);
|
||||
|
||||
/**
|
||||
* @brief Rescale a frame number between two frame rates
|
||||
*
|
||||
* Converts a frame number from one frame rate to its equivalent in another frame rate
|
||||
*
|
||||
* @param framenumber
|
||||
*
|
||||
* The frame number to convert
|
||||
*
|
||||
* @param source_frame_rate
|
||||
*
|
||||
* Frame rate that the frame number is currently in
|
||||
*
|
||||
* @param target_frame_rate
|
||||
*
|
||||
* Frame rate to convert to
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Rescaled frame number
|
||||
*/
|
||||
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
|
||||
|
||||
/**
|
||||
* @brief Convert playhead frame number to a clip frame number
|
||||
*
|
||||
* Converts a Timeline playhead to a the current clip's frame. Equivalent to
|
||||
* `PLAYHEAD - CLIP_TIMELINE_IN + CLIP_MEDIA_IN`. All keyframes are in clip frames.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* The clip to get the current frame number of
|
||||
*
|
||||
* @param playhead
|
||||
*
|
||||
* The current Timeline frame number
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* The curren frame number of the clip at `playhead`
|
||||
*/
|
||||
long playhead_to_clip_frame(Clip* c, long playhead);
|
||||
|
||||
/**
|
||||
* @brief Converts the playhead to clip seconds
|
||||
*
|
||||
* Get the current timecode at the playhead in terms of clip seconds.
|
||||
*
|
||||
* FIXME: Possible duplicate of get_timecode()? Will need to research this more.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* Clip to return clip seconds of.
|
||||
*
|
||||
* @param playhead
|
||||
*
|
||||
* Current Timeline playhead to convert to clip seconds
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Clip time in seconds
|
||||
*/
|
||||
double playhead_to_clip_seconds(Clip *c, long playhead);
|
||||
|
||||
/**
|
||||
* @brief Convert seconds to FFmpeg timestamp
|
||||
*
|
||||
* Used for interaction with FFmpeg, converts seconds in a floating-point value to a timestamp in AVStream->time_base
|
||||
* units.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* Clip to get timestamp of
|
||||
*
|
||||
* @param seconds
|
||||
*
|
||||
* Clip time in seconds
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* An FFmpeg-compatible timestamp in AVStream->time_base units.
|
||||
*/
|
||||
int64_t seconds_to_timestamp(Clip* c, double seconds);
|
||||
|
||||
/**
|
||||
* @brief Convert Timeline playhead to FFmpeg timestamp
|
||||
*
|
||||
* Used for interaction with FFmpeg, converts the Timeline playhead to a timestamp in AVStream->time_base
|
||||
* units.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* Clip to get timestamp of
|
||||
*
|
||||
* @param playhead
|
||||
*
|
||||
* Timeline playhead to convert to a timestamp
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* An FFmpeg-compatible timestamp in AVStream->time_base units.
|
||||
*/
|
||||
int64_t playhead_to_timestamp(Clip *c, long playhead);
|
||||
|
||||
bool frame_rate_is_droppable(double rate);
|
||||
long timecode_to_frame(const QString& s, int view, double frame_rate);
|
||||
QString frame_to_timecode(long f, int view, double frame_rate);
|
||||
|
||||
#endif // TIMING_H
|
||||
@@ -177,7 +177,8 @@ SOURCES += \
|
||||
timeline/mediaimportdata.cpp \
|
||||
dialogs/autocutsilencedialog.cpp \
|
||||
ui/columnedgridlayout.cpp \
|
||||
rendering/shadergenerators.cpp
|
||||
rendering/shadergenerators.cpp \
|
||||
global/timing.cpp
|
||||
|
||||
HEADERS += \
|
||||
ui/mainwindow.h \
|
||||
@@ -308,7 +309,8 @@ HEADERS += \
|
||||
timeline/mediaimportdata.h \
|
||||
dialogs/autocutsilencedialog.h \
|
||||
ui/columnedgridlayout.h \
|
||||
rendering/shadergenerators.h
|
||||
rendering/shadergenerators.h \
|
||||
global/timing.h
|
||||
|
||||
FORMS +=
|
||||
|
||||
@@ -327,27 +329,18 @@ TRANSLATIONS += \
|
||||
|
||||
win32 {
|
||||
RC_FILE = packaging/windows/resources.rc
|
||||
LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample -lopengl32 -luser32
|
||||
!contains(DEFINES, NO_OCIO) {
|
||||
LIBS += -lOpenColorIO
|
||||
}
|
||||
LIBS += -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample -lOpenColorIO -lopengl32 -luser32
|
||||
}
|
||||
|
||||
mac {
|
||||
LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample -framework CoreFoundation
|
||||
LIBS += -L/usr/local/lib -lavutil -lavformat -lavcodec -lavfilter -lswscale -lswresample -lOpenColorIO -framework CoreFoundation
|
||||
ICON = packaging/macos/olive.icns
|
||||
INCLUDEPATH = /usr/local/include
|
||||
!contains(DEFINES, NO_OCIO) {
|
||||
LIBS += -lOpenColorIO
|
||||
}
|
||||
}
|
||||
|
||||
unix:!mac {
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += libavutil libavformat libavcodec libavfilter libswscale libswresample
|
||||
!contains(DEFINES, NO_OCIO) {
|
||||
LIBS += -lOpenColorIO
|
||||
}
|
||||
PKGCONFIG += libavutil libavformat libavcodec libavfilter libswscale libswresample OpenColorIO
|
||||
}
|
||||
|
||||
RESOURCES += \
|
||||
|
||||
@@ -127,7 +127,7 @@ void EffectControls::menu_select(QAction* q) {
|
||||
update_ui(true);
|
||||
} else {
|
||||
Reload();
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
panel_sequence_viewer->viewer_widget()->frame_update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ void EffectControls::deselect_all_effects(QWidget* sender) {
|
||||
}
|
||||
|
||||
if (panel_sequence_viewer != nullptr) {
|
||||
panel_sequence_viewer->viewer_widget->update();
|
||||
panel_sequence_viewer->viewer_widget()->update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,6 @@
|
||||
|
||||
#include "ui/sourcetable.h"
|
||||
|
||||
#define LOAD_TYPE_VERSION 69
|
||||
#define LOAD_TYPE_URL 70
|
||||
|
||||
extern QString autorecovery_filename;
|
||||
extern QStringList recent_projects;
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "ui/mainwindow.h"
|
||||
#include "undo/undostack.h"
|
||||
#include "global/debug.h"
|
||||
#include "global/timing.h"
|
||||
#include "ui/menu.h"
|
||||
|
||||
int olive::timeline::kTrackDefaultHeight = 40;
|
||||
|
||||
+26
-148
@@ -43,6 +43,7 @@ extern "C" {
|
||||
#include "timeline/clip.h"
|
||||
#include "panels/panels.h"
|
||||
#include "global/config.h"
|
||||
#include "global/timing.h"
|
||||
#include "project/footage.h"
|
||||
#include "project/media.h"
|
||||
#include "undo/undo.h"
|
||||
@@ -77,8 +78,8 @@ Viewer::Viewer(QWidget *parent) :
|
||||
headers->snapping = false;
|
||||
headers->show_text(false);
|
||||
viewer_container->viewer = this;
|
||||
viewer_widget = viewer_container->child;
|
||||
viewer_widget->viewer = this;
|
||||
viewer_widget_ = viewer_container->child;
|
||||
viewer_widget_->viewer = this;
|
||||
set_media(nullptr);
|
||||
|
||||
current_timecode_slider->setEnabled(false);
|
||||
@@ -93,15 +94,13 @@ Viewer::Viewer(QWidget *parent) :
|
||||
connect(&playback_updater, SIGNAL(timeout()), this, SLOT(timer_update()));
|
||||
connect(&recording_flasher, SIGNAL(timeout()), this, SLOT(recording_flasher_update()));
|
||||
connect(horizontal_bar, SIGNAL(valueChanged(int)), headers, SLOT(set_scroll(int)));
|
||||
connect(horizontal_bar, SIGNAL(valueChanged(int)), viewer_widget, SLOT(set_waveform_scroll(int)));
|
||||
connect(horizontal_bar, SIGNAL(valueChanged(int)), viewer_widget_, SLOT(set_waveform_scroll(int)));
|
||||
connect(horizontal_bar, SIGNAL(resize_move(double)), this, SLOT(resize_move(double)));
|
||||
|
||||
update_playhead_timecode(0);
|
||||
update_end_timecode();
|
||||
}
|
||||
|
||||
Viewer::~Viewer() {}
|
||||
|
||||
void Viewer::Retranslate() {
|
||||
/// Viewer panels are retranslated through the MainWindow to differentiate Media and Sequence Viewers
|
||||
// update_window_title();
|
||||
@@ -109,7 +108,7 @@ void Viewer::Retranslate() {
|
||||
|
||||
bool Viewer::is_focused() {
|
||||
return headers->hasFocus()
|
||||
|| viewer_widget->hasFocus()
|
||||
|| viewer_widget_->hasFocus()
|
||||
|| go_to_start_button->hasFocus()
|
||||
|| prev_frame_button->hasFocus()
|
||||
|| play_button->hasFocus()
|
||||
@@ -146,132 +145,6 @@ void Viewer::reset_all_audio() {
|
||||
clear_audio_ibuffer();
|
||||
}
|
||||
|
||||
long timecode_to_frame(const QString& s, int view, double frame_rate) {
|
||||
QList<QString> list = s.split(QRegExp("[:;]"));
|
||||
|
||||
if (view == olive::kTimecodeFrames || (list.size() == 1 && view != olive::kTimecodeMilliseconds)) {
|
||||
return s.toLong();
|
||||
}
|
||||
|
||||
int frRound = qRound(frame_rate);
|
||||
int hours, minutes, seconds, frames;
|
||||
|
||||
if (view == olive::kTimecodeMilliseconds) {
|
||||
long milliseconds = s.toLong();
|
||||
|
||||
hours = milliseconds/3600000;
|
||||
milliseconds -= (hours*3600000);
|
||||
minutes = milliseconds/60000;
|
||||
milliseconds -= (minutes*60000);
|
||||
seconds = milliseconds/1000;
|
||||
milliseconds -= (seconds*1000);
|
||||
frames = qRound64((milliseconds*0.001)*frame_rate);
|
||||
|
||||
seconds = qRound64(seconds * frame_rate);
|
||||
minutes = qRound64(minutes * frame_rate * 60);
|
||||
hours = qRound64(hours * frame_rate * 3600);
|
||||
} else {
|
||||
hours = ((list.size() > 0) ? list.at(0).toInt() : 0) * frRound * 3600;
|
||||
minutes = ((list.size() > 1) ? list.at(1).toInt() : 0) * frRound * 60;
|
||||
seconds = ((list.size() > 2) ? list.at(2).toInt() : 0) * frRound;
|
||||
frames = (list.size() > 3) ? list.at(3).toInt() : 0;
|
||||
}
|
||||
|
||||
int f = (frames + seconds + minutes + hours);
|
||||
|
||||
if ((view == olive::kTimecodeDrop || view == olive::kTimecodeMilliseconds) && frame_rate_is_droppable(frame_rate)) {
|
||||
// return drop
|
||||
int d;
|
||||
int m;
|
||||
|
||||
int dropFrames = qRound(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
|
||||
int framesPer10Minutes = qRound(frame_rate * 60 * 10); //Number of frames per ten minutes
|
||||
int framesPerMinute = (qRound(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
|
||||
|
||||
d = f / framesPer10Minutes;
|
||||
f -= dropFrames*9*d;
|
||||
|
||||
m = f % framesPer10Minutes;
|
||||
|
||||
if (m > dropFrames) {
|
||||
f -= (dropFrames * ((m - dropFrames) / framesPerMinute));
|
||||
}
|
||||
}
|
||||
|
||||
// return non-drop
|
||||
return f;
|
||||
}
|
||||
|
||||
QString frame_to_timecode(long f, int view, double frame_rate) {
|
||||
if (view == olive::kTimecodeFrames) {
|
||||
return QString::number(f);
|
||||
}
|
||||
|
||||
// return timecode
|
||||
int hours = 0;
|
||||
int mins = 0;
|
||||
int secs = 0;
|
||||
int frames = 0;
|
||||
QString token = ":";
|
||||
|
||||
if ((view == olive::kTimecodeDrop || view == olive::kTimecodeMilliseconds) && frame_rate_is_droppable(frame_rate)) {
|
||||
//CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE
|
||||
//Code by David Heidelberger, adapted from Andrew Duncan, further adapted for Olive by Olive Team
|
||||
//Given an int called framenumber and a double called framerate
|
||||
//Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off.
|
||||
|
||||
int d;
|
||||
int m;
|
||||
|
||||
int dropFrames = qRound(frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
|
||||
int framesPerHour = qRound(frame_rate*60*60); //Number of frqRound64ames in an hour
|
||||
int framesPer24Hours = framesPerHour*24; //Number of frames in a day - timecode rolls over after 24 hours
|
||||
int framesPer10Minutes = qRound(frame_rate * 60 * 10); //Number of frames per ten minutes
|
||||
int framesPerMinute = (qRound(frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
|
||||
|
||||
//If framenumber is greater than 24 hrs, next operation will rollover clock
|
||||
f = f % framesPer24Hours; // % is the modulus operator, which returns a remainder. a % b = the remainder of a/b
|
||||
|
||||
d = f / framesPer10Minutes; // \ means integer division, which is a/b without a remainder. Some languages you could use floor(a/b)
|
||||
m = f % framesPer10Minutes;
|
||||
|
||||
//In the original post, the next line read m>1, which only worked for 29.97. Jean-Baptiste Mardelle correctly pointed out that m should be compared to dropFrames.
|
||||
if (m > dropFrames) {
|
||||
f = f + (dropFrames*9*d) + dropFrames * ((m - dropFrames) / framesPerMinute);
|
||||
} else {
|
||||
f = f + dropFrames*9*d;
|
||||
}
|
||||
|
||||
int frRound = qRound(frame_rate);
|
||||
frames = f % frRound;
|
||||
secs = (f / frRound) % 60;
|
||||
mins = ((f / frRound) / 60) % 60;
|
||||
hours = (((f / frRound) / 60) / 60);
|
||||
|
||||
token = ";";
|
||||
} else {
|
||||
// non-drop timecode
|
||||
|
||||
int int_fps = qRound(frame_rate);
|
||||
hours = f / (3600 * int_fps);
|
||||
mins = f / (60*int_fps) % 60;
|
||||
secs = f/int_fps % 60;
|
||||
frames = f%int_fps;
|
||||
}
|
||||
if (view == olive::kTimecodeMilliseconds) {
|
||||
return QString::number((hours*3600000)+(mins*60000)+(secs*1000)+qCeil(frames*1000/frame_rate));
|
||||
}
|
||||
return QString(QString::number(hours).rightJustified(2, '0') +
|
||||
":" + QString::number(mins).rightJustified(2, '0') +
|
||||
":" + QString::number(secs).rightJustified(2, '0') +
|
||||
token + QString::number(frames).rightJustified(2, '0')
|
||||
);
|
||||
}
|
||||
|
||||
bool frame_rate_is_droppable(double rate) {
|
||||
return (qFuzzyCompare(rate, 23.976) || qFuzzyCompare(rate, 29.97) || qFuzzyCompare(rate, 59.94));
|
||||
}
|
||||
|
||||
void Viewer::seek(long p) {
|
||||
pause();
|
||||
if (main_sequence) {
|
||||
@@ -499,7 +372,7 @@ void Viewer::update_header_zoom() {
|
||||
minimum_zoom = (sequenceEndFrame > 0) ? ((double) headers->width() / (double) sequenceEndFrame) : 1;
|
||||
headers->update_zoom(qMax(headers->get_zoom(), minimum_zoom));
|
||||
set_sb_max();
|
||||
viewer_widget->waveform_zoom = headers->get_zoom();
|
||||
viewer_widget_->waveform_zoom = headers->get_zoom();
|
||||
} else {
|
||||
headers->update();
|
||||
}
|
||||
@@ -519,6 +392,11 @@ int Viewer::get_playback_speed() {
|
||||
return playback_speed;
|
||||
}
|
||||
|
||||
ViewerWidget *Viewer::viewer_widget()
|
||||
{
|
||||
return viewer_widget_;
|
||||
}
|
||||
|
||||
void Viewer::set_marker() {
|
||||
set_marker_internal(seq.get());
|
||||
}
|
||||
@@ -527,13 +405,13 @@ void Viewer::resizeEvent(QResizeEvent *e) {
|
||||
QDockWidget::resizeEvent(e);
|
||||
if (seq != nullptr) {
|
||||
set_sb_max();
|
||||
viewer_widget->update();
|
||||
viewer_widget_->update();
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::update_viewer() {
|
||||
update_header_zoom();
|
||||
viewer_widget->frame_update();
|
||||
viewer_widget_->frame_update();
|
||||
if (seq != nullptr) {
|
||||
update_playhead_timecode(seq->playhead);
|
||||
}
|
||||
@@ -616,9 +494,9 @@ void Viewer::update_window_title() {
|
||||
|
||||
void Viewer::set_zoom_value(double d) {
|
||||
headers->update_zoom(d);
|
||||
if (viewer_widget->waveform) {
|
||||
viewer_widget->waveform_zoom = d;
|
||||
viewer_widget->update();
|
||||
if (viewer_widget_->waveform) {
|
||||
viewer_widget_->waveform_zoom = d;
|
||||
viewer_widget_->update();
|
||||
}
|
||||
if (seq != nullptr) {
|
||||
set_sb_max();
|
||||
@@ -843,10 +721,10 @@ void Viewer::set_media(Media* m) {
|
||||
new_sequence->clips.append(c);
|
||||
|
||||
if (footage->video_tracks.size() == 0) {
|
||||
viewer_widget->waveform = true;
|
||||
viewer_widget->waveform_clip = c;
|
||||
viewer_widget->waveform_ms = &audio_stream;
|
||||
viewer_widget->frame_update();
|
||||
viewer_widget_->waveform = true;
|
||||
viewer_widget_->waveform_clip = c;
|
||||
viewer_widget_->waveform_ms = &audio_stream;
|
||||
viewer_widget_->frame_update();
|
||||
}
|
||||
} else {
|
||||
new_sequence->audio_frequency = olive::CurrentConfig.default_sequence_audio_frequency;
|
||||
@@ -926,7 +804,7 @@ void Viewer::drag_audio_only()
|
||||
}
|
||||
|
||||
void Viewer::clean_created_seq() {
|
||||
viewer_widget->waveform = false;
|
||||
viewer_widget_->waveform = false;
|
||||
|
||||
if (created_sequence) {
|
||||
// TODO delete undo commands referencing this sequence to avoid crashes
|
||||
@@ -950,11 +828,11 @@ void Viewer::set_sequence(bool main, SequencePtr s) {
|
||||
|
||||
reset_all_audio();
|
||||
|
||||
viewer_widget->wait_until_render_is_paused();
|
||||
viewer_widget_->wait_until_render_is_paused();
|
||||
|
||||
// If we had a current sequence open, close it
|
||||
if (seq != nullptr) {
|
||||
close_active_clips(seq.get());
|
||||
seq->Close();
|
||||
}
|
||||
|
||||
clean_created_seq();
|
||||
@@ -969,8 +847,8 @@ void Viewer::set_sequence(bool main, SequencePtr s) {
|
||||
|
||||
headers->setEnabled(!null_sequence);
|
||||
current_timecode_slider->setEnabled(!null_sequence);
|
||||
viewer_widget->setEnabled(!null_sequence);
|
||||
viewer_widget->setVisible(!null_sequence);
|
||||
viewer_widget_->setEnabled(!null_sequence);
|
||||
viewer_widget_->setVisible(!null_sequence);
|
||||
go_to_start_button->setEnabled(!null_sequence);
|
||||
prev_frame_button->setEnabled(!null_sequence);
|
||||
play_button->setEnabled(!null_sequence);
|
||||
@@ -1001,7 +879,7 @@ void Viewer::set_sequence(bool main, SequencePtr s) {
|
||||
|
||||
update_header_zoom();
|
||||
|
||||
viewer_widget->frame_update();
|
||||
viewer_widget_->frame_update();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
+3
-7
@@ -37,17 +37,12 @@
|
||||
#include "ui/labelslider.h"
|
||||
#include "ui/resizablescrollbar.h"
|
||||
|
||||
bool frame_rate_is_droppable(double rate);
|
||||
long timecode_to_frame(const QString& s, int view, double frame_rate);
|
||||
QString frame_to_timecode(long f, int view, double frame_rate);
|
||||
|
||||
class Viewer : public Panel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Viewer(QWidget *parent = nullptr);
|
||||
~Viewer();
|
||||
|
||||
bool is_focused();
|
||||
bool is_main_sequence();
|
||||
@@ -90,7 +85,7 @@ public:
|
||||
|
||||
int get_playback_speed();
|
||||
|
||||
ViewerWidget* viewer_widget;
|
||||
ViewerWidget* viewer_widget();
|
||||
|
||||
Media* media;
|
||||
SequencePtr seq;
|
||||
@@ -134,7 +129,6 @@ private slots:
|
||||
void drag_audio_only();
|
||||
|
||||
private:
|
||||
|
||||
void update_window_title();
|
||||
void clean_created_seq();
|
||||
void set_sequence(bool main, SequencePtr s);
|
||||
@@ -155,6 +149,8 @@ private:
|
||||
|
||||
void setup_ui();
|
||||
|
||||
ViewerWidget* viewer_widget_;
|
||||
|
||||
ResizableScrollBar* horizontal_bar;
|
||||
ViewerContainer* viewer_container;
|
||||
LabelSlider* current_timecode_slider;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <QDebug>
|
||||
#include <QtMath>
|
||||
#include <QPainter>
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
|
||||
#include "project/previewgenerator.h"
|
||||
#include "timeline/clip.h"
|
||||
@@ -45,6 +47,28 @@ Footage::~Footage() {
|
||||
reset();
|
||||
}
|
||||
|
||||
QString Footage::Colorspace()
|
||||
{
|
||||
if (!colorspace_.isEmpty()) {
|
||||
return colorspace_;
|
||||
}
|
||||
|
||||
// If this footage has no color space set, try to guess the color space from the filename
|
||||
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
|
||||
QString guess_colorspace = config->parseColorSpaceFromString(url.toUtf8());
|
||||
|
||||
if (!guess_colorspace.isEmpty()) {
|
||||
return guess_colorspace;
|
||||
}
|
||||
|
||||
return OCIO::ROLE_SCENE_LINEAR;
|
||||
}
|
||||
|
||||
void Footage::SetColorspace(const QString &cs)
|
||||
{
|
||||
colorspace_ = cs;
|
||||
}
|
||||
|
||||
void Footage::reset() {
|
||||
if (preview_gen != nullptr) {
|
||||
preview_gen->cancel();
|
||||
|
||||
+6
-4
@@ -65,7 +65,8 @@ struct FootageStream {
|
||||
QVector<char> audio_preview;
|
||||
};
|
||||
|
||||
struct Footage {
|
||||
class Footage {
|
||||
public:
|
||||
Footage();
|
||||
~Footage();
|
||||
|
||||
@@ -82,10 +83,9 @@ struct Footage {
|
||||
bool alpha_is_associated;
|
||||
int start_number;
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// color management
|
||||
QString colorspace;
|
||||
#endif
|
||||
QString Colorspace();
|
||||
void SetColorspace(const QString& cs);
|
||||
|
||||
// proxy config
|
||||
bool proxy;
|
||||
@@ -107,6 +107,8 @@ struct Footage {
|
||||
long get_length_in_frames(double frame_rate);
|
||||
FootageStream *get_stream_from_file_index(bool video, int index);
|
||||
void reset();
|
||||
private:
|
||||
QString colorspace_;
|
||||
};
|
||||
|
||||
using FootagePtr = std::shared_ptr<Footage>;
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
#include <QFile>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
const int LOAD_TYPE_VERSION = 100;
|
||||
const int LOAD_TYPE_URL = 101;
|
||||
|
||||
LoadThread::LoadThread(const QString& filename, bool autorecovery) :
|
||||
filename_(filename),
|
||||
autorecovery_(autorecovery),
|
||||
|
||||
+1
-1
@@ -33,11 +33,11 @@ extern "C" {
|
||||
#include "undo/undo.h"
|
||||
#include "undo/undostack.h"
|
||||
#include "global/config.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "panels/project.h"
|
||||
#include "ui/icons.h"
|
||||
#include "projectmodel.h"
|
||||
#include "global/debug.h"
|
||||
#include "global/timing.h"
|
||||
|
||||
QString get_interlacing_name(int interlacing) {
|
||||
switch (interlacing) {
|
||||
|
||||
@@ -432,7 +432,7 @@ void SourcesCommon::clear_proxies_from_selected() {
|
||||
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
// close all clips so we can delete any proxies requested to be deleted
|
||||
close_active_clips(olive::ActiveSequence.get());
|
||||
olive::ActiveSequence->Close();
|
||||
}
|
||||
|
||||
// delete proxies requested to be deleted
|
||||
@@ -442,7 +442,7 @@ void SourcesCommon::clear_proxies_from_selected() {
|
||||
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
// update viewer (will re-open active clips with original media)
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
panel_sequence_viewer->viewer_widget()->frame_update();
|
||||
}
|
||||
|
||||
olive::Global->set_modified(true);
|
||||
|
||||
+1
-2
@@ -52,7 +52,6 @@ QAudioInput* audio_input = nullptr;
|
||||
QFile output_recording;
|
||||
bool recording = false;
|
||||
|
||||
bool audio_rendering = false;
|
||||
int audio_rendering_rate = 0;
|
||||
|
||||
qint8 audio_ibuffer[audio_ibuffer_size];
|
||||
@@ -154,7 +153,7 @@ void clear_audio_ibuffer() {
|
||||
}
|
||||
|
||||
int current_audio_freq() {
|
||||
return audio_rendering ? audio_rendering_rate : audio_output->format().sampleRate();
|
||||
return olive::Global->is_exporting() ? audio_rendering_rate : audio_output->format().sampleRate();
|
||||
}
|
||||
|
||||
qint64 get_buffer_offset_from_frame(double framerate, long frame) {
|
||||
|
||||
@@ -61,7 +61,6 @@ extern long audio_ibuffer_frame;
|
||||
extern double audio_ibuffer_timecode;
|
||||
extern bool audio_scrub;
|
||||
extern bool recording;
|
||||
extern bool audio_rendering;
|
||||
extern int audio_rendering_rate;
|
||||
void clear_audio_ibuffer();
|
||||
|
||||
|
||||
+20
-13
@@ -28,22 +28,29 @@ namespace rendering {
|
||||
QVector<BitDepthInfo> bit_depths;
|
||||
|
||||
void InitializeBitDepths() {
|
||||
BitDepthInfo bdi;
|
||||
|
||||
bdi.name = QCoreApplication::translate("bitdepths", "8-bit");
|
||||
bdi.pixel_type = GL_UNSIGNED_BYTE;
|
||||
bdi.internal_format = GL_RGBA8;
|
||||
bit_depths.append(bdi);
|
||||
bit_depths.resize(PIX_FMT_COUNT);
|
||||
|
||||
bdi.name = QCoreApplication::translate("bitdepths", "Half-Float (16-bit)");
|
||||
bdi.pixel_type = GL_HALF_FLOAT;
|
||||
bdi.internal_format = GL_RGBA16F;
|
||||
bit_depths.append(bdi);
|
||||
bit_depths[PIX_FMT_RGBA8].name = QCoreApplication::translate("bitdepths", "8-bit");
|
||||
bit_depths[PIX_FMT_RGBA8].internal_format = GL_RGBA8;
|
||||
bit_depths[PIX_FMT_RGBA8].pixel_format = GL_RGBA;
|
||||
bit_depths[PIX_FMT_RGBA8].pixel_type = GL_UNSIGNED_BYTE;
|
||||
|
||||
bit_depths[PIX_FMT_RGBA16].name = QCoreApplication::translate("bitdepths", "16-bit Integer");
|
||||
bit_depths[PIX_FMT_RGBA16].internal_format = GL_RGBA16UI;
|
||||
bit_depths[PIX_FMT_RGBA16].pixel_format = GL_RGBA_INTEGER;
|
||||
bit_depths[PIX_FMT_RGBA16].pixel_type = GL_UNSIGNED_SHORT;
|
||||
|
||||
bit_depths[PIX_FMT_RGBA16F].name = QCoreApplication::translate("bitdepths", "Half-Float (16-bit)");
|
||||
bit_depths[PIX_FMT_RGBA16F].internal_format = GL_RGBA16F;
|
||||
bit_depths[PIX_FMT_RGBA16F].pixel_format = GL_RGBA;
|
||||
bit_depths[PIX_FMT_RGBA16F].pixel_type = GL_HALF_FLOAT;
|
||||
|
||||
bit_depths[PIX_FMT_RGBA32F].name = QCoreApplication::translate("bitdepths", "Full-Float (32-bit)");
|
||||
bit_depths[PIX_FMT_RGBA32F].internal_format = GL_RGBA32F;
|
||||
bit_depths[PIX_FMT_RGBA32F].pixel_format = GL_RGBA;
|
||||
bit_depths[PIX_FMT_RGBA32F].pixel_type = GL_FLOAT;
|
||||
|
||||
bdi.name = QCoreApplication::translate("bitdepths", "Full-Float (32-bit)");
|
||||
bdi.pixel_type = GL_FLOAT;
|
||||
bdi.internal_format = GL_RGBA32F;
|
||||
bit_depths.append(bdi);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+26
-9
@@ -26,17 +26,34 @@
|
||||
#include <QOpenGLExtraFunctions>
|
||||
|
||||
namespace olive {
|
||||
namespace rendering {
|
||||
struct BitDepthInfo {
|
||||
QString name;
|
||||
GLuint pixel_type;
|
||||
GLuint internal_format;
|
||||
};
|
||||
namespace rendering {
|
||||
|
||||
extern QVector<BitDepthInfo> bit_depths;
|
||||
struct BitDepthInfo {
|
||||
QString name;
|
||||
GLint internal_format;
|
||||
GLenum pixel_format;
|
||||
GLenum pixel_type;
|
||||
};
|
||||
|
||||
void InitializeBitDepths();
|
||||
}
|
||||
/**
|
||||
* @brief The OlivePixelFormat enum
|
||||
*
|
||||
* Olive's internal supported pixel formats. With the exception of OLIVE_PIX_FMT_COUNT, these must all
|
||||
* be defined in InitializeBitDepths().
|
||||
*/
|
||||
enum PixelFormat {
|
||||
PIX_FMT_RGBA8,
|
||||
PIX_FMT_RGBA16,
|
||||
PIX_FMT_RGBA16F,
|
||||
PIX_FMT_RGBA32F,
|
||||
PIX_FMT_COUNT
|
||||
};
|
||||
|
||||
extern QVector<BitDepthInfo> bit_depths;
|
||||
|
||||
void InitializeBitDepths();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BITDEPTHS_H
|
||||
|
||||
+28
-6
@@ -33,10 +33,11 @@
|
||||
#include <QStatusBar>
|
||||
#include <math.h>
|
||||
|
||||
#include "panels/panels.h"
|
||||
#include "project/projectelements.h"
|
||||
#include "rendering/audio.h"
|
||||
#include "rendering/renderfunctions.h"
|
||||
#include "panels/panels.h"
|
||||
#include "global/timing.h"
|
||||
#include "global/config.h"
|
||||
#include "global/debug.h"
|
||||
#include "ui/mainwindow.h"
|
||||
@@ -44,7 +45,6 @@
|
||||
// Enable verbose audio messages - good for debugging reversed audio
|
||||
//#define AUDIOWARNINGS
|
||||
|
||||
const AVPixelFormat kDestPixFmt = AV_PIX_FMT_RGBA;
|
||||
const AVSampleFormat kDestSampleFmt = AV_SAMPLE_FMT_S16;
|
||||
|
||||
double bytes_to_seconds(int nb_bytes, int nb_channels, int sample_rate) {
|
||||
@@ -858,8 +858,6 @@ Cacher::Cacher(Clip* c) :
|
||||
{}
|
||||
|
||||
void Cacher::OpenWorker() {
|
||||
qint64 time_start = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
// set some defaults for the audio cacher
|
||||
if (clip->track() >= 0) {
|
||||
audio_reset_ = false;
|
||||
@@ -988,7 +986,26 @@ void Cacher::OpenWorker() {
|
||||
last_filter = yadif_filter;
|
||||
}
|
||||
|
||||
const char* chosen_format = av_get_pix_fmt_name(kDestPixFmt);
|
||||
AVPixelFormat possible_pix_fmts[] = {
|
||||
AV_PIX_FMT_RGBA,
|
||||
AV_PIX_FMT_RGBA64,
|
||||
AV_PIX_FMT_NONE
|
||||
};
|
||||
|
||||
AVPixelFormat pix_fmt = avcodec_find_best_pix_fmt_of_list(possible_pix_fmts,
|
||||
static_cast<AVPixelFormat>(stream->codecpar->format),
|
||||
1,
|
||||
nullptr);
|
||||
|
||||
if (pix_fmt == AV_PIX_FMT_RGBA) {
|
||||
qDebug() << "This is an 8-bit image.";
|
||||
media_pixel_format_ = olive::rendering::PIX_FMT_RGBA8;
|
||||
} else {
|
||||
qDebug() << "This is an HDR image.";
|
||||
media_pixel_format_ = olive::rendering::PIX_FMT_RGBA16;
|
||||
}
|
||||
|
||||
const char* chosen_format = av_get_pix_fmt_name(pix_fmt);
|
||||
snprintf(filter_args, sizeof(filter_args), "pix_fmts=%s", chosen_format);
|
||||
|
||||
AVFilterContext* format_conv;
|
||||
@@ -1091,7 +1108,7 @@ void Cacher::OpenWorker() {
|
||||
frame_ = av_frame_alloc();
|
||||
}
|
||||
|
||||
qInfo() << "Clip opened on track" << clip->track() << "(took" << (QDateTime::currentMSecsSinceEpoch() - time_start) << "ms)";
|
||||
qInfo() << "Clip opened on track" << clip->track();
|
||||
|
||||
is_valid_state_ = true;
|
||||
}
|
||||
@@ -1336,6 +1353,11 @@ ClipQueue *Cacher::queue()
|
||||
return &queue_;
|
||||
}
|
||||
|
||||
const olive::rendering::PixelFormat &Cacher::media_pixel_format()
|
||||
{
|
||||
return media_pixel_format_;
|
||||
}
|
||||
|
||||
int Cacher::RetrieveFrameFromDecoder(AVFrame* f) {
|
||||
int result = 0;
|
||||
int receive_ret;
|
||||
|
||||
@@ -43,6 +43,7 @@ extern "C" {
|
||||
#include <QMutex>
|
||||
|
||||
#include "rendering/clipqueue.h"
|
||||
#include "rendering/bitdepths.h"
|
||||
|
||||
class Clip;
|
||||
|
||||
@@ -254,6 +255,15 @@ public:
|
||||
*/
|
||||
ClipQueue* queue();
|
||||
|
||||
/**
|
||||
* @brief Retrieve OpenGL information about this media's bit depth
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* A olive::rendering::PixelFormat value corresponding to a member of olive::rendering::bit_depths.
|
||||
*/
|
||||
const olive::rendering::PixelFormat& media_pixel_format();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Reference to the parent clip. Set in the constructor and never changed during this object's lifetime.
|
||||
@@ -582,6 +592,11 @@ private:
|
||||
* @brief Internal function using the Cacher's known information to determine whether this media is playing in reverse
|
||||
*/
|
||||
bool IsReversed();
|
||||
|
||||
/**
|
||||
* @brief Internal struct holding bit depth information for the current media
|
||||
*/
|
||||
olive::rendering::PixelFormat media_pixel_format_;
|
||||
};
|
||||
|
||||
#endif // CACHER_H
|
||||
|
||||
@@ -413,10 +413,10 @@ void ExportThread::Export()
|
||||
long remaining_frames, frame_count = 1;
|
||||
|
||||
// Use Sequence Viewer's render thread - TODO separate this into a new render thread for background rendering
|
||||
RenderThread* renderer = panel_sequence_viewer->viewer_widget->get_renderer();
|
||||
RenderThread* renderer = panel_sequence_viewer->viewer_widget()->get_renderer();
|
||||
|
||||
// Override connection from RenderThread
|
||||
disconnect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget, SLOT(queue_repaint()));
|
||||
disconnect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget(), SLOT(queue_repaint()));
|
||||
connect(renderer, SIGNAL(ready()), this, SLOT(wake()));
|
||||
|
||||
// Lock mutex (used for synchronization with RenderThread)
|
||||
@@ -548,7 +548,7 @@ void ExportThread::Export()
|
||||
|
||||
// Restore original connection from RenderThread
|
||||
disconnect(renderer, SIGNAL(ready()), this, SLOT(wake()));
|
||||
connect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget, SLOT(queue_repaint()));
|
||||
connect(renderer, SIGNAL(ready()), panel_sequence_viewer->viewer_widget(), SLOT(queue_repaint()));
|
||||
|
||||
mutex.unlock();
|
||||
|
||||
@@ -559,7 +559,7 @@ void ExportThread::Export()
|
||||
if (params_.video_enabled) vpkt_alloc = true;
|
||||
if (params_.audio_enabled) apkt_alloc = true;
|
||||
|
||||
olive::Global->set_rendering_state(false);
|
||||
olive::Global->set_export_state(false);
|
||||
|
||||
// If audio is enabled, flush the rest of the audio out of swresample
|
||||
if (params_.audio_enabled) {
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <QDebug>
|
||||
|
||||
// TODO take this from Config rather than having a constant
|
||||
const GLuint kPixelFormat = GL_RGBA16F;
|
||||
#include "global/config.h"
|
||||
#include "global/global.h"
|
||||
#include "bitdepths.h"
|
||||
|
||||
FramebufferObject::FramebufferObject() :
|
||||
buffer_(0),
|
||||
@@ -64,8 +65,22 @@ void FramebufferObject::Create(QOpenGLContext *ctx, int width, int height)
|
||||
ctx->functions()->glBindTexture(GL_TEXTURE_2D, texture_);
|
||||
|
||||
// allocate storage for texture
|
||||
const olive::rendering::BitDepthInfo& bit_depth = olive::rendering::bit_depths.at(olive::Global->is_exporting() ?
|
||||
olive::CurrentConfig.export_bit_depth :
|
||||
olive::CurrentConfig.playback_bit_depth);
|
||||
|
||||
qDebug() << "hello" << bit_depth.name;
|
||||
|
||||
ctx->functions()->glTexImage2D(
|
||||
GL_TEXTURE_2D, 0, kPixelFormat, width, height, 0, GL_RGBA, GL_FLOAT, nullptr
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
bit_depth.internal_format,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
bit_depth.pixel_format,
|
||||
bit_depth.pixel_type,
|
||||
nullptr
|
||||
);
|
||||
|
||||
// set texture filtering to bilinear
|
||||
|
||||
@@ -40,9 +40,9 @@ extern "C" {
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "rendering/audio.h"
|
||||
#include "global/math.h"
|
||||
#include "global/timing.h"
|
||||
#include "global/config.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "qopenglshaderprogramptr.h"
|
||||
#include "shadergenerators.h"
|
||||
|
||||
@@ -365,6 +365,20 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
int video_width = c->media_width();
|
||||
int video_height = c->media_height();
|
||||
|
||||
// prepare framebuffers for backend drawing operations
|
||||
if (c->fbo.isEmpty()) {
|
||||
// create 3 fbos for nested sequences, 2 for most clips
|
||||
int fbo_count = (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) ? 3 : 2;
|
||||
|
||||
c->fbo.resize(fbo_count);
|
||||
|
||||
for (int j=0;j<fbo_count;j++) {
|
||||
c->fbo[j].Create(params.ctx, video_width, video_height);
|
||||
}
|
||||
}
|
||||
|
||||
bool convert_frame_to_internal = false;
|
||||
|
||||
// if media is footage
|
||||
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
|
||||
@@ -378,19 +392,13 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
}
|
||||
|
||||
if (textureID == 0) {
|
||||
|
||||
qWarning() << "Failed to create texture";
|
||||
}
|
||||
}
|
||||
|
||||
// prepare framebuffers for backend drawing operations
|
||||
if (c->fbo.isEmpty()) {
|
||||
// create 3 fbos for nested sequences, 2 for most clips
|
||||
int fbo_count = (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_SEQUENCE) ? 3 : 2;
|
||||
} else {
|
||||
|
||||
c->fbo.resize(fbo_count);
|
||||
convert_frame_to_internal = true;
|
||||
|
||||
for (int j=0;j<fbo_count;j++) {
|
||||
c->fbo[j].Create(params.ctx, video_width, video_height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,60 +430,43 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
|
||||
} else if (c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
|
||||
#ifndef NO_OCIO
|
||||
|
||||
// Convert texture to float
|
||||
if (textureID != c->fbo.at(0).texture() && textureID != c->fbo.at(1).texture()) {
|
||||
textureID = draw_clip(params.ctx, params.pipeline, c->fbo.at(fbo_switcher), textureID, true);
|
||||
fbo_switcher = !fbo_switcher;
|
||||
}
|
||||
|
||||
// Convert frame from source to linear colorspace
|
||||
if (olive::CurrentConfig.enable_color_management)
|
||||
{
|
||||
|
||||
if (c->ocio_shader == nullptr) {
|
||||
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
|
||||
// Convert texture to sequence's internal format
|
||||
if (textureID != c->fbo.at(0).texture() && textureID != c->fbo.at(1).texture()) {
|
||||
textureID = draw_clip(params.ctx, params.pipeline, c->fbo.at(fbo_switcher), textureID, true);
|
||||
fbo_switcher = !fbo_switcher;
|
||||
}
|
||||
|
||||
// Check if this clip has an OCIO shader set up or not
|
||||
if (c->ocio_shader == nullptr) {
|
||||
|
||||
|
||||
// Set default input colorspace
|
||||
QString input_cs = OCIO::ROLE_SCENE_LINEAR;
|
||||
|
||||
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
|
||||
if (!c->media()->to_footage()->colorspace.isEmpty()) {
|
||||
|
||||
input_cs = c->media()->to_footage()->colorspace;
|
||||
|
||||
} else {
|
||||
|
||||
// If this is a footage clip, try to guess the color space from the filename
|
||||
QString guess_colorspace = config->parseColorSpaceFromString(c->media()->to_footage()->url.toUtf8());
|
||||
|
||||
if (!guess_colorspace.isEmpty()) {
|
||||
input_cs = guess_colorspace;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
input_cs = c->media()->to_footage()->Colorspace();
|
||||
}
|
||||
|
||||
qDebug() << "Input colorspace:" << input_cs;
|
||||
|
||||
// Try to get a shader based on the input color space to scene linear
|
||||
try {
|
||||
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
|
||||
OCIO::ConstProcessorRcPtr processor = config->getProcessor(input_cs.toUtf8(),
|
||||
OCIO::ROLE_SCENE_LINEAR);
|
||||
|
||||
olive::shader::AlphaAssociateMode associate_mode = (c->media()->to_footage()->alpha_is_associated)
|
||||
? olive::shader::DisassociateAndReassociate : olive::shader::Associate;
|
||||
|
||||
c->ocio_shader = olive::shader::SetupOCIO(params.ctx,
|
||||
c->ocio_lut_texture,
|
||||
processor,
|
||||
associate_mode);
|
||||
c->media()->to_footage()->alpha_is_associated);
|
||||
} catch (OCIO::Exception& e) {
|
||||
qWarning() << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we got a shader, and if so, blit with it
|
||||
if (c->ocio_shader != nullptr) {
|
||||
textureID = olive::rendering::OCIOBlit(c->ocio_shader.get(),
|
||||
c->ocio_lut_texture,
|
||||
@@ -486,8 +477,6 @@ GLuint olive::rendering::compose_sequence(ComposeSequenceParams ¶ms) {
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,54 +790,6 @@ void olive::rendering::compose_audio(Viewer* viewer, Sequence* seq, int playback
|
||||
compose_sequence(params);
|
||||
}
|
||||
|
||||
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate) {
|
||||
return qRound((double(framenumber)/source_frame_rate)*target_frame_rate);
|
||||
}
|
||||
|
||||
double get_timecode(Clip* c, long playhead) {
|
||||
return double(playhead_to_clip_frame(c, playhead))/c->sequence->frame_rate;
|
||||
}
|
||||
|
||||
long playhead_to_clip_frame(Clip* c, long playhead) {
|
||||
return (qMax(0L, playhead - c->timeline_in(true)) + c->clip_in(true));
|
||||
}
|
||||
|
||||
double playhead_to_clip_seconds(Clip* c, long playhead) {
|
||||
// returns time in seconds
|
||||
long clip_frame = playhead_to_clip_frame(c, playhead);
|
||||
|
||||
if (c->reversed()) {
|
||||
clip_frame = c->media_length() - clip_frame - 1;
|
||||
}
|
||||
|
||||
double secs = (double(clip_frame)/c->sequence->frame_rate)*c->speed().value;
|
||||
if (c->media() != nullptr && c->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
secs *= c->media()->to_footage()->speed;
|
||||
}
|
||||
|
||||
return secs;
|
||||
}
|
||||
|
||||
int64_t seconds_to_timestamp(Clip *c, double seconds) {
|
||||
return qRound64(seconds * av_q2d(av_inv_q(c->time_base())));
|
||||
}
|
||||
|
||||
int64_t playhead_to_timestamp(Clip* c, long playhead) {
|
||||
return seconds_to_timestamp(c, playhead_to_clip_seconds(c, playhead));
|
||||
}
|
||||
|
||||
void close_active_clips(Sequence* s) {
|
||||
if (s != nullptr) {
|
||||
for (int i=0;i<s->clips.size();i++) {
|
||||
Clip* c = s->clips.at(i).get();
|
||||
if (c != nullptr) {
|
||||
c->Close(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
GLuint olive::rendering::OCIOBlit(QOpenGLShaderProgram *pipeline,
|
||||
GLuint lut,
|
||||
const FramebufferObject& fbo,
|
||||
@@ -880,4 +821,3 @@ GLuint olive::rendering::OCIOBlit(QOpenGLShaderProgram *pipeline,
|
||||
|
||||
return textureID;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -24,10 +24,8 @@
|
||||
#include <QOpenGLContext>
|
||||
#include <QVector>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
#endif
|
||||
|
||||
#include "timeline/sequence.h"
|
||||
#include "effects/effect.h"
|
||||
@@ -244,143 +242,6 @@ void compose_audio(Viewer* viewer, Sequence *seq, int playback_speed, bool wait_
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rescale a frame number between two frame rates
|
||||
*
|
||||
* Converts a frame number from one frame rate to its equivalent in another frame rate
|
||||
*
|
||||
* @param framenumber
|
||||
*
|
||||
* The frame number to convert
|
||||
*
|
||||
* @param source_frame_rate
|
||||
*
|
||||
* Frame rate that the frame number is currently in
|
||||
*
|
||||
* @param target_frame_rate
|
||||
*
|
||||
* Frame rate to convert to
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Rescaled frame number
|
||||
*/
|
||||
long rescale_frame_number(long framenumber, double source_frame_rate, double target_frame_rate);
|
||||
|
||||
/**
|
||||
* @brief Get timecode
|
||||
*
|
||||
* Get the current clip/media time from the Timeline playhead in seconds. For instance if the playhead was at the start
|
||||
* of a clip (whose in point wasn't trimmed), this would be 0.0 as it's the start of the clip/media;
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* Clip to get the timecode of
|
||||
*
|
||||
* @param playhead
|
||||
*
|
||||
* Sequence playhead to convert to a clip/media timecode
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Timecode in seconds
|
||||
*/
|
||||
double get_timecode(Clip *c, long playhead);
|
||||
|
||||
/**
|
||||
* @brief Convert playhead frame number to a clip frame number
|
||||
*
|
||||
* Converts a Timeline playhead to a the current clip's frame. Equivalent to
|
||||
* `PLAYHEAD - CLIP_TIMELINE_IN + CLIP_MEDIA_IN`. All keyframes are in clip frames.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* The clip to get the current frame number of
|
||||
*
|
||||
* @param playhead
|
||||
*
|
||||
* The current Timeline frame number
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* The curren frame number of the clip at `playhead`
|
||||
*/
|
||||
long playhead_to_clip_frame(Clip* c, long playhead);
|
||||
|
||||
/**
|
||||
* @brief Converts the playhead to clip seconds
|
||||
*
|
||||
* Get the current timecode at the playhead in terms of clip seconds.
|
||||
*
|
||||
* FIXME: Possible duplicate of get_timecode()? Will need to research this more.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* Clip to return clip seconds of.
|
||||
*
|
||||
* @param playhead
|
||||
*
|
||||
* Current Timeline playhead to convert to clip seconds
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Clip time in seconds
|
||||
*/
|
||||
double playhead_to_clip_seconds(Clip *c, long playhead);
|
||||
|
||||
/**
|
||||
* @brief Convert seconds to FFmpeg timestamp
|
||||
*
|
||||
* Used for interaction with FFmpeg, converts seconds in a floating-point value to a timestamp in AVStream->time_base
|
||||
* units.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* Clip to get timestamp of
|
||||
*
|
||||
* @param seconds
|
||||
*
|
||||
* Clip time in seconds
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* An FFmpeg-compatible timestamp in AVStream->time_base units.
|
||||
*/
|
||||
int64_t seconds_to_timestamp(Clip* c, double seconds);
|
||||
|
||||
/**
|
||||
* @brief Convert Timeline playhead to FFmpeg timestamp
|
||||
*
|
||||
* Used for interaction with FFmpeg, converts the Timeline playhead to a timestamp in AVStream->time_base
|
||||
* units.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* Clip to get timestamp of
|
||||
*
|
||||
* @param playhead
|
||||
*
|
||||
* Timeline playhead to convert to a timestamp
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* An FFmpeg-compatible timestamp in AVStream->time_base units.
|
||||
*/
|
||||
int64_t playhead_to_timestamp(Clip *c, long playhead);
|
||||
|
||||
/**
|
||||
* @brief Close all open clips in a Sequence
|
||||
*
|
||||
* Closes any currently open clips on a Sequence and waits for them to close before returning. This may be slow as a
|
||||
* result on large Sequence objects. If a Clip is a nested Sequence, this function calls itself recursively on that
|
||||
* Sequence too.
|
||||
*
|
||||
* @param s
|
||||
*
|
||||
* The Sequence to close all clips on.
|
||||
*/
|
||||
void close_active_clips(Sequence* s);
|
||||
|
||||
void UpdateOCIOGLState(const ComposeSequenceParams ¶ms);
|
||||
|
||||
namespace olive {
|
||||
@@ -389,13 +250,10 @@ namespace olive {
|
||||
extern GLfloat blit_texcoords[];
|
||||
extern GLfloat flipped_blit_texcoords[];
|
||||
void Blit(QOpenGLShaderProgram* pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4());
|
||||
|
||||
#ifndef NO_OCIO
|
||||
GLuint OCIOBlit(QOpenGLShaderProgram *pipeline,
|
||||
GLuint lut,
|
||||
const FramebufferObject& fbo,
|
||||
GLuint texture);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,8 @@
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <QDebug>
|
||||
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
#endif
|
||||
|
||||
#include "timeline/sequence.h"
|
||||
#include "effects/effectloaders.h"
|
||||
@@ -48,14 +46,10 @@ RenderThread::RenderThread() :
|
||||
tex_height(-1),
|
||||
queued(false),
|
||||
texture_failed(false),
|
||||
#ifndef NO_OCIO
|
||||
ocio_lut_texture(0),
|
||||
ocio_shader(nullptr),
|
||||
#endif
|
||||
running(true),
|
||||
#ifndef NO_OCIO
|
||||
ocio_config_date(0),
|
||||
#endif
|
||||
front_buffer_switcher(false)
|
||||
{
|
||||
surface.create();
|
||||
@@ -121,17 +115,12 @@ void RenderThread::run() {
|
||||
pipeline_program = olive::shader::GetPipeline();
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// If there's no OpenColorIO shader or the configuration has changed, (re-)create it now
|
||||
if (olive::CurrentConfig.enable_color_management
|
||||
&& (ocio_shader == nullptr || ocio_config_date != olive::CurrentRuntimeConfig.ocio_config_date)) {
|
||||
ocio_config_date = olive::CurrentRuntimeConfig.ocio_config_date;
|
||||
|
||||
if (olive::CurrentConfig.enable_color_management && ocio_shader == nullptr) {
|
||||
destroy_ocio();
|
||||
|
||||
set_up_ocio();
|
||||
}
|
||||
#endif
|
||||
|
||||
// draw frame
|
||||
paint();
|
||||
@@ -160,7 +149,6 @@ const GLuint &RenderThread::get_texture()
|
||||
return front_buffer_switcher ? front_buffer_2.texture() : front_buffer_1.texture();
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
void RenderThread::set_up_ocio()
|
||||
{
|
||||
|
||||
@@ -194,7 +182,7 @@ void RenderThread::set_up_ocio()
|
||||
OCIO::ConstProcessorRcPtr processor = config->getProcessor(transform);
|
||||
|
||||
// Create a OCIO shader with this processor
|
||||
ocio_shader = olive::shader::SetupOCIO(ctx, ocio_lut_texture, processor, olive::shader::NoAssociate);
|
||||
ocio_shader = olive::shader::SetupOCIO(ctx, ocio_lut_texture, processor, true);
|
||||
|
||||
} catch(OCIO::Exception & e) {
|
||||
qCritical() << e.what();
|
||||
@@ -205,12 +193,12 @@ void RenderThread::set_up_ocio()
|
||||
void RenderThread::destroy_ocio()
|
||||
{
|
||||
// Destroy LUT texture
|
||||
ctx->functions()->glDeleteTextures(1, &ocio_lut_texture);
|
||||
if (ocio_lut_texture > 0) {
|
||||
ctx->functions()->glDeleteTextures(1, &ocio_lut_texture);
|
||||
}
|
||||
ocio_lut_texture = 0;
|
||||
|
||||
ocio_shader = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void RenderThread::paint() {
|
||||
// set up compose_sequence() parameters
|
||||
@@ -254,29 +242,24 @@ void RenderThread::paint() {
|
||||
FramebufferObject& buffer = front_buffer_switcher ? front_buffer_1 : front_buffer_2;
|
||||
|
||||
// Blit the composite buffer to one of the front buffers
|
||||
bool standard_blit = true;
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// If we're color managing, conver the linear composited frame to display color space
|
||||
if (olive::CurrentConfig.enable_color_management && ocio_shader != nullptr) {
|
||||
|
||||
olive::rendering::OCIOBlit(ocio_shader.get(),
|
||||
ocio_lut_texture,
|
||||
buffer,
|
||||
composite_buffer.texture());
|
||||
|
||||
standard_blit = false;
|
||||
}
|
||||
#else
|
||||
} else {
|
||||
|
||||
#endif
|
||||
|
||||
// If we're not color managing, just blit normally
|
||||
if (standard_blit) {
|
||||
// If we're not color managing, just blit normally
|
||||
buffer.BindBuffer();
|
||||
composite_buffer.BindTexture();
|
||||
olive::rendering::Blit(pipeline_program.get());
|
||||
composite_buffer.ReleaseTexture();
|
||||
buffer.ReleaseBuffer();
|
||||
|
||||
}
|
||||
|
||||
// flush changes
|
||||
@@ -404,10 +387,7 @@ void RenderThread::delete_ctx() {
|
||||
if (ctx != nullptr) {
|
||||
delete_shaders();
|
||||
delete_buffers();
|
||||
|
||||
#ifndef NO_OCIO
|
||||
destroy_ocio();
|
||||
#endif
|
||||
}
|
||||
|
||||
delete ctx;
|
||||
|
||||
@@ -60,23 +60,20 @@ public:
|
||||
public slots:
|
||||
// cleanup functions
|
||||
void delete_ctx();
|
||||
void delete_buffers();
|
||||
void delete_shaders();
|
||||
void destroy_ocio();
|
||||
signals:
|
||||
void ready();
|
||||
private:
|
||||
// cleanup functions
|
||||
void delete_buffers();
|
||||
void delete_shaders();
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// OpenColorIO functions
|
||||
void set_up_ocio();
|
||||
void destroy_ocio();
|
||||
|
||||
// OpenColorIO variables
|
||||
GLuint ocio_lut_texture;
|
||||
QOpenGLShaderProgramPtr ocio_shader;
|
||||
qint64 ocio_config_date;
|
||||
#endif
|
||||
|
||||
FramebufferObject front_buffer_1;
|
||||
QMutex front_mutex1;
|
||||
|
||||
@@ -118,8 +118,6 @@ QString olive::shader::GetAlphaAssociateFunction(const QString &function_name)
|
||||
"}\n").arg(function_name);
|
||||
}
|
||||
|
||||
#ifndef NO_OCIO
|
||||
|
||||
// copied from source code to OCIODisplay
|
||||
const int OCIO_LUT3D_EDGE_SIZE = 32;
|
||||
|
||||
@@ -129,7 +127,7 @@ const int OCIO_NUM_3D_ENTRIES = 98304;
|
||||
QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx,
|
||||
GLuint& lut_texture,
|
||||
OCIO::ConstProcessorRcPtr processor,
|
||||
AlphaAssociateMode alpha_associate_mode)
|
||||
bool alpha_is_associated)
|
||||
{
|
||||
|
||||
QOpenGLExtraFunctions* xf = ctx->extraFunctions();
|
||||
@@ -157,8 +155,9 @@ QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx,
|
||||
//
|
||||
|
||||
OCIO::GpuShaderDesc shaderDesc;
|
||||
const char* ocio_func_name = "OCIODisplay";
|
||||
shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
|
||||
shaderDesc.setFunctionName("OCIODisplay");
|
||||
shaderDesc.setFunctionName(ocio_func_name);
|
||||
shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE);
|
||||
|
||||
//
|
||||
@@ -179,39 +178,45 @@ QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx,
|
||||
// Create OCIO shader code
|
||||
QString shader_text(processor->getGpuShaderText(shaderDesc));
|
||||
|
||||
QString ocio_call_func;
|
||||
QString shader_call;
|
||||
|
||||
// Enforce alpha association
|
||||
switch (alpha_associate_mode) {
|
||||
case Associate:
|
||||
if (alpha_is_associated) {
|
||||
|
||||
// If alpha is already associated, we'll need to disassociate and reassociate
|
||||
shader_text.append("\n");
|
||||
|
||||
QString disassociate_func_name = "disassoc";
|
||||
shader_text.append(GetAlphaDisassociateFunction(disassociate_func_name));
|
||||
|
||||
QString reassociate_func_name = "reassoc";
|
||||
shader_text.append(GetAlphaReassociateFunction(reassociate_func_name));
|
||||
|
||||
// Make OCIO call pass through disassociate and reassociate function
|
||||
shader_call = QString("%3(%1(%2(col), tex2));").arg(ocio_func_name,
|
||||
disassociate_func_name,
|
||||
reassociate_func_name);
|
||||
|
||||
} else {
|
||||
|
||||
// If alpha is not already associated, we can just associate after OCIO
|
||||
|
||||
// Add associate function
|
||||
shader_text.append(GetAlphaAssociateFunction("assoc"));
|
||||
QString associate_func_name = "assoc";
|
||||
shader_text.append(GetAlphaAssociateFunction(associate_func_name));
|
||||
|
||||
// Make OCIO call pass through associate function
|
||||
ocio_call_func = "assoc(OCIODisplay(col, tex2));";
|
||||
break;
|
||||
case DisassociateAndReassociate:
|
||||
// If alpha is already associated, we'll need to disassociate and reassociate
|
||||
shader_text.append("\n");
|
||||
shader_text.append(GetAlphaDisassociateFunction("disassoc"));
|
||||
shader_text.append(GetAlphaReassociateFunction("reassoc"));
|
||||
shader_call = QString("%2(%1(col, tex2));").arg(ocio_func_name, associate_func_name);
|
||||
|
||||
// Make OCIO call pass through disassociate and reassociate function
|
||||
ocio_call_func = "reassoc(OCIODisplay(disassoc(col), tex2));";
|
||||
break;
|
||||
default:
|
||||
// No association
|
||||
ocio_call_func = "OCIODisplay(col, tex2);";
|
||||
}
|
||||
|
||||
// Add process() function, which GetPipeline() will call if specified
|
||||
shader_text.append(QString("\n"
|
||||
"uniform sampler3D tex2;\n"
|
||||
"\n"
|
||||
"vec4 process(vec4 col) {\n"
|
||||
" return %1\n"
|
||||
"}\n").arg(ocio_call_func));
|
||||
"}\n").arg(shader_call));
|
||||
|
||||
|
||||
// Get pipeline-based shader to inject OCIO shader into
|
||||
@@ -222,4 +227,3 @@ QOpenGLShaderProgramPtr olive::shader::SetupOCIO(QOpenGLContext* ctx,
|
||||
|
||||
return shader;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3,29 +3,18 @@
|
||||
|
||||
#include "qopenglshaderprogramptr.h"
|
||||
#include "framebufferobject.h"
|
||||
|
||||
#ifndef NO_OCIO
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE::v1;
|
||||
#endif
|
||||
|
||||
namespace olive {
|
||||
namespace shader {
|
||||
|
||||
QOpenGLShaderProgramPtr GetPipeline(const QString &shader_code = QString());
|
||||
|
||||
#ifndef NO_OCIO
|
||||
enum AlphaAssociateMode {
|
||||
NoAssociate,
|
||||
Associate,
|
||||
DisassociateAndReassociate
|
||||
};
|
||||
|
||||
QOpenGLShaderProgramPtr SetupOCIO(QOpenGLContext *ctx,
|
||||
GLuint &lut_texture,
|
||||
OCIO::ConstProcessorRcPtr processor,
|
||||
AlphaAssociateMode alpha_associate_mode);
|
||||
#endif
|
||||
bool alpha_is_associated);
|
||||
|
||||
QString GetAlphaDisassociateFunction(const QString& function_name);
|
||||
QString GetAlphaReassociateFunction(const QString& function_name);
|
||||
|
||||
+6
-5
@@ -35,6 +35,7 @@
|
||||
#include "project/clipboard.h"
|
||||
#include "undo/undo.h"
|
||||
#include "global/debug.h"
|
||||
#include "global/timing.h"
|
||||
|
||||
const int kRGBAComponentCount = 4;
|
||||
|
||||
@@ -492,7 +493,7 @@ void Clip::Close(bool wait) {
|
||||
open_ = false;
|
||||
|
||||
if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
close_active_clips(media()->to_sequence().get());
|
||||
media()->to_sequence()->Close();
|
||||
}
|
||||
|
||||
// destroy opengl texture in main thread
|
||||
@@ -511,10 +512,8 @@ void Clip::Close(bool wait) {
|
||||
// delete framebuffers
|
||||
fbo.clear();
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// delete OCIO shader
|
||||
ocio_shader = nullptr;
|
||||
#endif
|
||||
|
||||
if (UsesCacher()) {
|
||||
cacher.Close(wait);
|
||||
@@ -590,18 +589,20 @@ bool Clip::Retrieve()
|
||||
int video_width = cacher.media_width();
|
||||
int video_height = cacher.media_height();
|
||||
|
||||
const olive::rendering::BitDepthInfo& bit_depth_info = olive::rendering::bit_depths.at(cacher.media_pixel_format());
|
||||
|
||||
if (allocate_data) {
|
||||
|
||||
// the raw frame size may differ from the one we're using (e.g. a lower resolution proxy), so we make sure
|
||||
// the texture is using the correct dimensions, but then treat it as if it's the original resolution in the
|
||||
// composition
|
||||
f->glTexImage2D(
|
||||
GL_TEXTURE_2D, 0, GL_RGBA8, video_width, video_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame->data[0]
|
||||
GL_TEXTURE_2D, 0, bit_depth_info.internal_format, video_width, video_height, 0, bit_depth_info.pixel_format, bit_depth_info.pixel_type, frame->data[0]
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_width, video_height, GL_RGBA, GL_UNSIGNED_BYTE, frame->data[0]);
|
||||
f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_width, video_height, bit_depth_info.pixel_format, bit_depth_info.pixel_type, frame->data[0]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -39,11 +39,6 @@
|
||||
|
||||
#include "marker.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavfilter/avfilter.h>
|
||||
}
|
||||
|
||||
struct ClipSpeed {
|
||||
ClipSpeed();
|
||||
double value;
|
||||
|
||||
+10
-2
@@ -34,8 +34,6 @@ Sequence::Sequence() :
|
||||
{
|
||||
}
|
||||
|
||||
Sequence::~Sequence() {}
|
||||
|
||||
SequencePtr Sequence::copy() {
|
||||
SequencePtr s = std::make_shared<Sequence>();
|
||||
s->name = QCoreApplication::translate("Sequence", "%1 (copy)").arg(name);
|
||||
@@ -75,6 +73,16 @@ long Sequence::getEndFrame() {
|
||||
return end;
|
||||
}
|
||||
|
||||
void Sequence::Close()
|
||||
{
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
Clip* c = clips.at(i).get();
|
||||
if (c != nullptr) {
|
||||
c->Close(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sequence::RefreshClips(Media *m) {
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr c = clips.at(i);
|
||||
|
||||
+14
-1
@@ -31,8 +31,8 @@
|
||||
class Sequence {
|
||||
public:
|
||||
Sequence();
|
||||
~Sequence();
|
||||
SequencePtr copy();
|
||||
|
||||
QString name;
|
||||
void getTrackLimits(int* video_tracks, int* audio_tracks);
|
||||
long getEndFrame();
|
||||
@@ -42,6 +42,19 @@ public:
|
||||
int audio_frequency;
|
||||
int audio_layout;
|
||||
|
||||
/**
|
||||
* @brief Close all open clips in a Sequence
|
||||
*
|
||||
* Closes any currently open clips on a Sequence and waits for them to close before returning. This may be slow as a
|
||||
* result on large Sequence objects. If a Clip is a nested Sequence, this function calls itself recursively on that
|
||||
* Sequence too.
|
||||
*
|
||||
* @param s
|
||||
*
|
||||
* The Sequence to close all clips on.
|
||||
*/
|
||||
void Close();
|
||||
|
||||
void RefreshClips(Media* m = nullptr);
|
||||
QVector<Clip*> SelectedClips(bool containing = true);
|
||||
QVector<int> SelectedClipIndexes();
|
||||
|
||||
+2
-2
@@ -93,9 +93,9 @@ void FocusFilter::go_to_end() {
|
||||
|
||||
void FocusFilter::set_viewer_fullscreen() {
|
||||
if (get_focused_panel() == panel_footage_viewer) {
|
||||
panel_footage_viewer->viewer_widget->set_fullscreen();
|
||||
panel_footage_viewer->viewer_widget()->set_fullscreen();
|
||||
} else {
|
||||
panel_sequence_viewer->viewer_widget->set_fullscreen();
|
||||
panel_sequence_viewer->viewer_widget()->set_fullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
#include <QMenu>
|
||||
|
||||
#include "undo/undo.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "global/timing.h"
|
||||
#include "global/config.h"
|
||||
#include "global/math.h"
|
||||
#include "global/debug.h"
|
||||
|
||||
+2
-4
@@ -271,7 +271,6 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
olive::icon::Initialize();
|
||||
|
||||
#ifndef NO_OCIO
|
||||
// Load OpenColorIO configuration if set
|
||||
if (olive::CurrentConfig.enable_color_management && !olive::CurrentConfig.ocio_config_path.isEmpty()) {
|
||||
try {
|
||||
@@ -283,7 +282,6 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
alloc_panels(this);
|
||||
|
||||
@@ -971,8 +969,8 @@ void MainWindow::closeEvent(QCloseEvent *e) {
|
||||
|
||||
olive::Global->set_sequence(nullptr);
|
||||
|
||||
panel_footage_viewer->viewer_widget->close_window();
|
||||
panel_sequence_viewer->viewer_widget->close_window();
|
||||
panel_footage_viewer->viewer_widget()->close_window();
|
||||
panel_sequence_viewer->viewer_widget()->close_window();
|
||||
|
||||
panel_footage_viewer->set_main_sequence();
|
||||
|
||||
|
||||
+1
-1
@@ -242,7 +242,7 @@ void MenuHelper::set_titlesafe_from_menu() {
|
||||
|
||||
}
|
||||
|
||||
panel_sequence_viewer->viewer_widget->update();
|
||||
panel_sequence_viewer->viewer_widget()->update();
|
||||
}
|
||||
|
||||
void MenuHelper::set_autoscroll() {
|
||||
|
||||
@@ -28,11 +28,10 @@
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "panels/panels.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "timeline/sequence.h"
|
||||
#include "undo/undo.h"
|
||||
#include "project/media.h"
|
||||
#include "panels/viewer.h"
|
||||
#include "global/timing.h"
|
||||
#include "global/config.h"
|
||||
#include "global/global.h"
|
||||
#include "ui/menu.h"
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "project/projectelements.h"
|
||||
#include "rendering/audio.h"
|
||||
#include "global/config.h"
|
||||
#include "global/timing.h"
|
||||
#include "ui/sourcetable.h"
|
||||
#include "ui/sourceiconview.h"
|
||||
#include "undo/undo.h"
|
||||
|
||||
+1
-4
@@ -49,6 +49,7 @@ extern "C" {
|
||||
#include "global/config.h"
|
||||
#include "global/debug.h"
|
||||
#include "global/math.h"
|
||||
#include "global/timing.h"
|
||||
#include "ui/collapsiblewidget.h"
|
||||
#include "undo/undo.h"
|
||||
#include "project/media.h"
|
||||
@@ -278,10 +279,6 @@ QMatrix4x4 ViewerWidget::get_matrix()
|
||||
void ViewerWidget::context_destroy() {
|
||||
makeCurrent();
|
||||
|
||||
if (viewer->seq != nullptr) {
|
||||
close_active_clips(viewer->seq.get());
|
||||
}
|
||||
|
||||
renderer.delete_ctx();
|
||||
|
||||
title_safe_area_buffer_.destroy();
|
||||
|
||||
+4
-4
@@ -675,13 +675,13 @@ void SetClipProperty::MainLoop(bool undo)
|
||||
|
||||
void SetClipProperty::doUndo() {
|
||||
MainLoop(true);
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
panel_sequence_viewer->viewer_widget()->frame_update();
|
||||
|
||||
}
|
||||
|
||||
void SetClipProperty::doRedo() {
|
||||
MainLoop(false);
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
panel_sequence_viewer->viewer_widget()->frame_update();
|
||||
}
|
||||
|
||||
AddMarkerAction::AddMarkerAction(QVector<Marker>* m, long t, QString n) {
|
||||
@@ -896,7 +896,7 @@ void CloseAllClipsCommand::doUndo() {
|
||||
}
|
||||
|
||||
void CloseAllClipsCommand::doRedo() {
|
||||
close_active_clips(olive::ActiveSequence.get());
|
||||
olive::ActiveSequence->Close();
|
||||
}
|
||||
|
||||
UpdateFootageTooltip::UpdateFootageTooltip(Media *i) {
|
||||
@@ -1112,7 +1112,7 @@ void UpdateViewer::doUndo() {
|
||||
}
|
||||
|
||||
void UpdateViewer::doRedo() {
|
||||
panel_sequence_viewer->viewer_widget->frame_update();
|
||||
panel_sequence_viewer->viewer_widget()->frame_update();
|
||||
}
|
||||
|
||||
SetEffectData::SetEffectData(Effect *e, const QByteArray &s) {
|
||||
|
||||
Reference in New Issue
Block a user