diff --git a/app/core.cpp b/app/core.cpp index 94987a6a0..18464120e 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -342,10 +342,11 @@ void Core::DialogPreferencesShow() void Core::DialogExportShow() { - Sequence* viewer = GetSequenceToExport(); + ViewerOutput* viewer; + TimelinePoints* points; - if (viewer) { - ExportDialog* ed = new ExportDialog(viewer, main_window_); + if (GetSequenceToExport(&viewer, &points) && viewer) { + ExportDialog* ed = new ExportDialog(viewer, points, main_window_); connect(ed, &ExportDialog::finished, ed, &ExportDialog::deleteLater); ed->open(); } @@ -751,7 +752,7 @@ void Core::SaveProjectInternal(Project* project, const QString& override_filenam task_dialog->open(); } -Sequence *Core::GetSequenceToExport() +bool Core::GetSequenceToExport(ViewerOutput** viewer, TimelinePoints** points) { // First try the most recently focused time based window TimeBasedPanel* time_panel = PanelManager::instance()->MostRecentlyFocused(); @@ -769,7 +770,9 @@ Sequence *Core::GetSequenceToExport() tr("This Sequence is empty. There is nothing to export."), QMessageBox::Ok); } else { - return time_panel->GetConnectedViewer(); + *viewer = time_panel->GetConnectedViewer(); + *points = time_panel->GetConnectedTimelinePoints(); + return true; } } else { QMessageBox::critical(main_window_, @@ -778,7 +781,7 @@ Sequence *Core::GetSequenceToExport() QMessageBox::Ok); } - return nullptr; + return false; } QString Core::GetAutoRecoveryIndexFilename() diff --git a/app/core.h b/app/core.h index b06551e94..8275b188d 100644 --- a/app/core.h +++ b/app/core.h @@ -496,7 +496,7 @@ private: /** * @brief Retrieves the currently most active sequence for exporting */ - Sequence* GetSequenceToExport(); + bool GetSequenceToExport(ViewerOutput **viewer, TimelinePoints **points); static QString GetAutoRecoveryIndexFilename(); diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index fb7dead2c..bf1971c21 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -39,9 +39,10 @@ namespace olive { -ExportDialog::ExportDialog(Sequence *sequence, QWidget *parent) : +ExportDialog::ExportDialog(ViewerOutput *viewer_node, TimelinePoints *points, QWidget *parent) : QDialog(parent), - sequence_(sequence) + viewer_node_(viewer_node), + timeline_points_(points) { QHBoxLayout* layout = new QHBoxLayout(this); @@ -104,7 +105,7 @@ ExportDialog::ExportDialog(Sequence *sequence, QWidget *parent) : range_combobox_ = new QComboBox(); range_combobox_->addItem(tr("Entire Sequence")); range_combobox_->addItem(tr("In to Out")); - range_combobox_->setEnabled(sequence_->timeline_points()->workarea()->enabled()); + range_combobox_->setEnabled(timeline_points_ && timeline_points_->workarea()->enabled()); preferences_layout->addWidget(range_combobox_, row, 1, 1, 3); @@ -136,7 +137,7 @@ ExportDialog::ExportDialog(Sequence *sequence, QWidget *parent) : QTabWidget* preferences_tabs = new QTabWidget(); QScrollArea* video_area = new QScrollArea(); - color_manager_ = sequence_->project()->color_manager(); + color_manager_ = viewer_node_->project()->color_manager(); video_tab_ = new ExportVideoTab(color_manager_); video_area->setWidgetResizable(true); video_area->setWidget(video_tab_); @@ -188,18 +189,18 @@ ExportDialog::ExportDialog(Sequence *sequence, QWidget *parent) : &ExportDialog::FormatChanged); FormatChanged(ExportFormat::kFormatMPEG4); - video_tab_->width_slider()->SetValue(sequence_->video_params().width()); - video_tab_->width_slider()->SetDefaultValue(sequence_->video_params().width()); - video_tab_->height_slider()->SetValue(sequence_->video_params().height()); - video_tab_->height_slider()->SetDefaultValue(sequence_->video_params().height()); - video_tab_->frame_rate_combobox()->SetFrameRate(sequence_->video_params().time_base().flipped()); - video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(sequence_->video_params().pixel_aspect_ratio()); + video_tab_->width_slider()->SetValue(viewer_node_->video_params().width()); + video_tab_->width_slider()->SetDefaultValue(viewer_node_->video_params().width()); + video_tab_->height_slider()->SetValue(viewer_node_->video_params().height()); + video_tab_->height_slider()->SetDefaultValue(viewer_node_->video_params().height()); + video_tab_->frame_rate_combobox()->SetFrameRate(viewer_node_->video_params().time_base().flipped()); + video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(viewer_node_->video_params().pixel_aspect_ratio()); video_tab_->pixel_format_field()->SetPixelFormat(static_cast(Config::Current()["OnlinePixelFormat"].toInt())); - video_tab_->interlaced_combobox()->SetInterlaceMode(sequence_->video_params().interlacing()); - audio_tab_->sample_rate_combobox()->SetSampleRate(sequence_->audio_params().sample_rate()); - audio_tab_->channel_layout_combobox()->SetChannelLayout(sequence_->audio_params().channel_layout()); + video_tab_->interlaced_combobox()->SetInterlaceMode(viewer_node_->video_params().interlacing()); + audio_tab_->sample_rate_combobox()->SetSampleRate(viewer_node_->audio_params().sample_rate()); + audio_tab_->channel_layout_combobox()->SetChannelLayout(viewer_node_->audio_params().channel_layout()); - video_aspect_ratio_ = static_cast(sequence_->video_params().width()) / static_cast(sequence_->video_params().height()); + video_aspect_ratio_ = static_cast(viewer_node_->video_params().width()) / static_cast(viewer_node_->video_params().height()); connect(video_tab_->width_slider(), &IntegerSlider::ValueChanged, @@ -227,8 +228,8 @@ ExportDialog::ExportDialog(Sequence *sequence, QWidget *parent) : static_cast(&ViewerWidget::SetColorTransform)); // Set viewer to view the node - preview_viewer_->ConnectViewerNode(sequence_); - preview_viewer_->ruler()->ConnectTimelinePoints(sequence_->timeline_points()); + preview_viewer_->ConnectViewerNode(viewer_node_); + preview_viewer_->ruler()->ConnectTimelinePoints(timeline_points_); preview_viewer_->SetColorMenuEnabled(false); preview_viewer_->SetColorTransform(video_tab_->CurrentOCIOColorSpace()); } @@ -315,7 +316,7 @@ void ExportDialog::StartExport() return; } - ExportTask* task = new ExportTask(sequence_, color_manager_, GenerateParams()); + ExportTask* task = new ExportTask(viewer_node_, color_manager_, GenerateParams()); TaskDialog* td = new TaskDialog(task, tr("Export"), this); connect(td, &TaskDialog::TaskSucceeded, this, &ExportDialog::ExportFinished); td->open(); @@ -428,7 +429,7 @@ void ExportDialog::LoadPresets() void ExportDialog::SetDefaultFilename() { - Project* p = sequence_->project(); + Project* p = viewer_node_->project(); QDir doc_location; @@ -438,7 +439,7 @@ void ExportDialog::SetDefaultFilename() doc_location = QFileInfo(p->filename()).dir(); } - QString file_location = doc_location.filePath(sequence_->GetLabel()); + QString file_location = doc_location.filePath(viewer_node_->GetLabel()); filename_edit_->setText(file_location); } @@ -459,11 +460,12 @@ ExportParams ExportDialog::GenerateParams() const ExportParams params; params.SetFilename(filename_edit_->text().trimmed()); - params.SetExportLength(sequence_->GetLength()); + params.SetExportLength(viewer_node_->GetLength()); - if (range_combobox_->currentIndex() == kRangeInToOut - && sequence_->timeline_points()->workarea()->enabled()) { - params.set_custom_range(sequence_->timeline_points()->workarea()->range()); + if (range_combobox_->isEnabled() && range_combobox_->currentIndex() == kRangeInToOut) { + // Assume if this combobox is enabled, that we have timeline points - a check that we make + // in this dialog's constructor + params.set_custom_range(timeline_points_->workarea()->range()); } if (video_tab_->scaling_method_combobox()->isEnabled()) { @@ -500,8 +502,8 @@ void ExportDialog::UpdateViewerDimensions() QMatrix4x4 transform = ExportParams::GenerateMatrix(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt()), - sequence_->video_params().width(), - sequence_->video_params().height(), + viewer_node_->video_params().width(), + viewer_node_->video_params().height(), static_cast(video_tab_->width_slider()->GetValue()), static_cast(video_tab_->height_slider()->GetValue())); diff --git a/app/dialog/export/export.h b/app/dialog/export/export.h index 71f7196c9..179485f74 100644 --- a/app/dialog/export/export.h +++ b/app/dialog/export/export.h @@ -40,7 +40,7 @@ class ExportDialog : public QDialog { Q_OBJECT public: - ExportDialog(Sequence* sequence, QWidget* parent = nullptr); + ExportDialog(ViewerOutput* viewer_node, TimelinePoints* points, QWidget* parent = nullptr); protected: virtual void closeEvent(QCloseEvent *e) override; @@ -51,7 +51,8 @@ private: ExportParams GenerateParams() const; - Sequence* sequence_; + ViewerOutput* viewer_node_; + TimelinePoints* timeline_points_; ExportFormat::Format previously_selected_format_; diff --git a/app/node/output/track/tracklist.cpp b/app/node/output/track/tracklist.cpp index 65b766ac8..2867e5833 100644 --- a/app/node/output/track/tracklist.cpp +++ b/app/node/output/track/tracklist.cpp @@ -24,6 +24,7 @@ #include "node/math/math/math.h" #include "node/math/merge/merge.h" #include "node/output/viewer/viewer.h" +#include "project/item/sequence/sequence.h" namespace olive { diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index bf253714c..b4f4b8abb 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -20,13 +20,39 @@ #include "viewer.h" +#include "config/config.h" +#include "core.h" +#include "node/traverser.h" +#include "widget/videoparamedit/videoparamedit.h" + namespace olive { -#define super Sequence +const QString ViewerOutput::kVideoParamsInput = QStringLiteral("video_param_in"); +const QString ViewerOutput::kAudioParamsInput = QStringLiteral("audio_param_in"); +const QString ViewerOutput::kTextureInput = QStringLiteral("tex_in"); +const QString ViewerOutput::kSamplesInput = QStringLiteral("samples_in"); + +const uint64_t ViewerOutput::kVideoParamEditMask = VideoParamEdit::kWidthHeight | VideoParamEdit::kInterlacing | VideoParamEdit::kFrameRate | VideoParamEdit::kPixelAspect; + +#define super Node ViewerOutput::ViewerOutput() : - Sequence(true) + video_frame_cache_(this), + audio_playback_cache_(this), + operation_stack_(0) { + AddInput(kVideoParamsInput, NodeValue::kVideoParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + SetInputProperty(kVideoParamsInput, QStringLiteral("mask"), QVariant::fromValue(kVideoParamEditMask)); + + AddInput(kAudioParamsInput, NodeValue::kAudioParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + + AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + AddInput(kSamplesInput, NodeValue::kSamples, InputFlags(kInputFlagNotKeyframable)); +} + +ViewerOutput::~ViewerOutput() +{ + DisconnectAll(); } Node *ViewerOutput::copy() const @@ -54,4 +80,275 @@ QString ViewerOutput::Description() const return tr("Interface between a Viewer panel and the node system."); } +QString ViewerOutput::duration() const +{ + rational timeline_length = GetLength(); + + int64_t timestamp = Timecode::time_to_timestamp(timeline_length, video_params().time_base()); + + return Timecode::timestamp_to_timecode(timestamp, video_params().time_base(), Core::instance()->GetTimecodeDisplay()); +} + +QString ViewerOutput::rate() const +{ + return tr("%1 FPS").arg(video_params().time_base().flipped().toDouble()); +} + +void ViewerOutput::set_default_parameters() +{ + int width = Config::Current()["DefaultSequenceWidth"].toInt(); + int height = Config::Current()["DefaultSequenceHeight"].toInt(); + + set_video_params(VideoParams(width, + height, + Config::Current()["DefaultSequenceFrameRate"].value(), + static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + VideoParams::kInternalChannelCount, + Config::Current()["DefaultSequencePixelAspect"].value(), + Config::Current()["DefaultSequenceInterlacing"].value(), + VideoParams::generate_auto_divider(width, height))); + set_audio_params(AudioParams(Config::Current()["DefaultSequenceAudioFrequency"].toInt(), + Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), + AudioParams::kInternalFormat)); +} + +void ViewerOutput::ShiftVideoCache(const rational &from, const rational &to) +{ + video_frame_cache_.Shift(from, to); + + ShiftVideoEvent(from, to); +} + +void ViewerOutput::ShiftAudioCache(const rational &from, const rational &to) +{ + audio_playback_cache_.Shift(from, to); + + ShiftAudioEvent(from, to); +} + +void ViewerOutput::ShiftCache(const rational &from, const rational &to) +{ + ShiftVideoCache(from, to); + ShiftAudioCache(from, to); +} + +void ViewerOutput::InvalidateCache(const TimeRange& range, const QString& from, int element, qint64 job_time) +{ + Q_UNUSED(element) + + if (operation_stack_ == 0) { + if (from == kTextureInput || from == kSamplesInput + || from == kVideoParamsInput || from == kAudioParamsInput) { + TimeRange invalidated_range(qMax(rational(), range.in()), + qMin(GetLength(), range.out())); + + if (invalidated_range.in() != invalidated_range.out()) { + if (from == kTextureInput || from == kVideoParamsInput) { + video_frame_cache_.Invalidate(invalidated_range, job_time); + } else { + audio_playback_cache_.Invalidate(invalidated_range, job_time); + } + } + } + + VerifyLength(); + } + + super::InvalidateCache(range, from, element, job_time); +} + +const rational& ViewerOutput::GetLength() const +{ + return last_length_; +} + +void ViewerOutput::Retranslate() +{ + super::Retranslate(); + + SetInputName(kVideoParamsInput, tr("Video Parameters")); + SetInputName(kAudioParamsInput, tr("Audio Parameters")); + + SetInputName(kTextureInput, tr("Texture")); + SetInputName(kSamplesInput, tr("Samples")); +} + +void ViewerOutput::VerifyLength() +{ + if (operation_stack_ != 0) { + return; + } + + NodeTraverser traverser; + + rational video_length, audio_length, subtitle_length; + + { + video_length = GetCustomLength(Track::kVideo); + + if (video_length.isNull() && IsInputConnected(kTextureInput)) { + NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kTextureInput), TimeRange(0, 0)); + video_length = t.Get(NodeValue::kRational, QStringLiteral("length")).value(); + } + + video_frame_cache_.SetLength(video_length); + } + + { + audio_length = GetCustomLength(Track::kAudio); + + if (audio_length.isNull() && IsInputConnected(kSamplesInput)) { + NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kSamplesInput), TimeRange(0, 0)); + audio_length = t.Get(NodeValue::kRational, QStringLiteral("length")).value(); + } + + audio_playback_cache_.SetLength(audio_length); + } + + { + subtitle_length = GetCustomLength(Track::kSubtitle); + } + + rational real_length = qMax(subtitle_length, qMax(video_length, audio_length)); + + if (real_length != last_length_) { + last_length_ = real_length; + emit LengthChanged(last_length_); + } +} + +void ViewerOutput::InputConnectedEvent(const QString &input, int element, const NodeOutput &output) +{ + if (input == kTextureInput) { + emit TextureInputChanged(); + } + + super::InputConnectedEvent(input, element, output); +} + +void ViewerOutput::InputDisconnectedEvent(const QString &input, int element, const NodeOutput &output) +{ + if (input == kTextureInput) { + emit TextureInputChanged(); + } + + super::InputDisconnectedEvent(input, element, output); +} + +rational ViewerOutput::GetCustomLength(Track::Type type) const +{ + Q_UNUSED(type) + return rational(); +} + +void ViewerOutput::BeginOperation() +{ + operation_stack_++; + + super::BeginOperation(); +} + +void ViewerOutput::EndOperation() +{ + operation_stack_--; + + super::EndOperation(); +} + +void ViewerOutput::InputValueChangedEvent(const QString &input, int element) +{ + if (input == kVideoParamsInput) { + + VideoParams new_video_params = video_params(); + + bool size_changed = cached_video_params_.width() != new_video_params.width() || cached_video_params_.height() != new_video_params.height(); + bool timebase_changed = cached_video_params_.time_base() != new_video_params.time_base(); + bool pixel_aspect_changed = cached_video_params_.pixel_aspect_ratio() != new_video_params.pixel_aspect_ratio(); + bool interlacing_changed = cached_video_params_.interlacing() != new_video_params.interlacing(); + + if (size_changed) { + emit SizeChanged(new_video_params.width(), new_video_params.height()); + } + + if (pixel_aspect_changed) { + emit PixelAspectChanged(new_video_params.pixel_aspect_ratio()); + } + + if (interlacing_changed) { + emit InterlacingChanged(new_video_params.interlacing()); + } + + if (timebase_changed) { + video_frame_cache_.SetTimebase(new_video_params.time_base()); + emit TimebaseChanged(new_video_params.time_base()); + } + + emit VideoParamsChanged(); + + cached_video_params_ = video_params(); + + } else if (input == kAudioParamsInput) { + + emit AudioParamsChanged(); + + audio_playback_cache_.SetParameters(audio_params()); + + } + + super::InputValueChangedEvent(input, element); +} + +void ViewerOutput::ShiftVideoEvent(const rational &from, const rational &to) +{ + Q_UNUSED(from) + Q_UNUSED(to) +} + +void ViewerOutput::ShiftAudioEvent(const rational &from, const rational &to) +{ + Q_UNUSED(from) + Q_UNUSED(to) +} + +void ViewerOutput::set_parameters_from_footage(const QVector footage) +{ + foreach (Footage* f, footage) { + QVector video_streams = f->GetEnabledVideoStreams(); + QVector audio_streams = f->GetEnabledAudioStreams(); + + foreach (const VideoParams& s, video_streams) { + bool found_video_params = false; + rational using_timebase; + + if (s.video_type() == VideoParams::kVideoTypeStill) { + // If this is a still image, we'll use it's resolution but won't set + // `found_video_params` in case something with a frame rate comes along which we'll + // prioritize + using_timebase = video_params().time_base(); + } else { + using_timebase = s.frame_rate().flipped(); + found_video_params = true; + } + + set_video_params(VideoParams(s.width(), + s.height(), + using_timebase, + static_cast(Config::Current()[QStringLiteral("OfflinePixelFormat")].toInt()), + VideoParams::kInternalChannelCount, + s.pixel_aspect_ratio(), + s.interlacing(), + VideoParams::generate_auto_divider(s.width(), s.height()))); + + if (found_video_params) { + break; + } + } + + if (!audio_streams.isEmpty()) { + const AudioParams& s = audio_streams.first(); + set_audio_params(AudioParams(s.sample_rate(), s.channel_layout(), AudioParams::kInternalFormat)); + } + } +} + } diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index e330c6537..5acb22ad8 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -21,7 +21,15 @@ #ifndef VIEWER_H #define VIEWER_H -#include "project/item/sequence/sequence.h" +#include "common/rational.h" +#include "node/node.h" +#include "node/output/track/track.h" +#include "project/item/footage/footage.h" +#include "render/audioparams.h" +#include "render/audioplaybackcache.h" +#include "render/framehashcache.h" +#include "render/videoparams.h" +#include "render/videoparams.h" namespace olive { @@ -30,11 +38,12 @@ namespace olive { * * Receives update/time change signals from ViewerPanels and responds by sending them a texture of that frame */ -class ViewerOutput : public Sequence +class ViewerOutput : public Node { Q_OBJECT public: ViewerOutput(); + virtual ~ViewerOutput() override; virtual Node* copy() const override; @@ -43,6 +52,108 @@ public: virtual QVector Category() const override; virtual QString Description() const override; + virtual QString duration() const override; + virtual QString rate() const override; + + void set_default_parameters(); + + void set_parameters_from_footage(const QVector footage); + + void ShiftVideoCache(const rational& from, const rational& to); + void ShiftAudioCache(const rational& from, const rational& to); + void ShiftCache(const rational& from, const rational& to); + + virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, qint64 job_time) override; + + VideoParams video_params() const + { + return GetStandardValue(kVideoParamsInput).value(); + } + + AudioParams audio_params() const + { + return GetStandardValue(kAudioParamsInput).value(); + } + + void set_video_params(const VideoParams &video) + { + SetStandardValue(kVideoParamsInput, QVariant::fromValue(video)); + } + + void set_audio_params(const AudioParams &audio) + { + SetStandardValue(kAudioParamsInput, QVariant::fromValue(audio)); + } + + const rational &GetLength() const; + + FrameHashCache* video_frame_cache() + { + return &video_frame_cache_; + } + + AudioPlaybackCache* audio_playback_cache() + { + return &audio_playback_cache_; + } + + virtual void Retranslate() override; + + virtual void BeginOperation() override; + + virtual void EndOperation() override; + + static const QString kVideoParamsInput; + static const QString kAudioParamsInput; + + static const QString kTextureInput; + static const QString kSamplesInput; + + static const uint64_t kVideoParamEditMask; + +signals: + void TimebaseChanged(const rational&); + + void LengthChanged(const rational& length); + + void SizeChanged(int width, int height); + + void PixelAspectChanged(const rational& pixel_aspect); + + void InterlacingChanged(VideoParams::Interlacing mode); + + void VideoParamsChanged(); + void AudioParamsChanged(); + + void TextureInputChanged(); + +public slots: + void VerifyLength(); + +protected: + virtual void InputConnectedEvent(const QString &input, int element, const NodeOutput &output) override; + + virtual void InputDisconnectedEvent(const QString &input, int element, const NodeOutput &output) override; + + virtual rational GetCustomLength(Track::Type type) const; + + virtual void ShiftVideoEvent(const rational &from, const rational &to); + + virtual void ShiftAudioEvent(const rational &from, const rational &to); + + virtual void InputValueChangedEvent(const QString& input, int element) override; + +private: + rational last_length_; + + FrameHashCache video_frame_cache_; + + AudioPlaybackCache audio_playback_cache_; + + int operation_stack_; + + VideoParams cached_video_params_; + }; } diff --git a/app/panel/timebased/timebased.cpp b/app/panel/timebased/timebased.cpp index 3e59f02f0..cdcad93d3 100644 --- a/app/panel/timebased/timebased.cpp +++ b/app/panel/timebased/timebased.cpp @@ -108,22 +108,7 @@ void TimeBasedPanel::ShuttleRight() emit ShuttleRightRequested(); } -TimeBasedWidget *TimeBasedPanel::GetTimeBasedWidget() const -{ - return widget_; -} - -Sequence *TimeBasedPanel::GetConnectedViewer() const -{ - return widget_->GetConnectedNode(); -} - -TimeRuler *TimeBasedPanel::ruler() const -{ - return widget_->ruler(); -} - -void TimeBasedPanel::ConnectViewerNode(Sequence *node) +void TimeBasedPanel::ConnectViewerNode(ViewerOutput *node) { if (widget_->GetConnectedNode() == node) { return; diff --git a/app/panel/timebased/timebased.h b/app/panel/timebased/timebased.h index b3c54975f..b090b786e 100644 --- a/app/panel/timebased/timebased.h +++ b/app/panel/timebased/timebased.h @@ -32,15 +32,26 @@ class TimeBasedPanel : public PanelWidget public: TimeBasedPanel(const QString& object_name, QWidget *parent = nullptr); - void ConnectViewerNode(Sequence *node); + void ConnectViewerNode(ViewerOutput *node); void DisconnectViewerNode(); rational GetTime(); - Sequence *GetConnectedViewer() const; + ViewerOutput *GetConnectedViewer() const + { + return widget_->GetConnectedNode(); + } - TimeRuler* ruler() const; + TimelinePoints* GetConnectedTimelinePoints() const + { + return widget_->GetConnectedTimelinePoints(); + } + + TimeRuler* ruler() const + { + return widget_->ruler(); + } virtual void ZoomIn() override; @@ -107,7 +118,10 @@ signals: void ShuttleRightRequested(); protected: - TimeBasedWidget* GetTimeBasedWidget() const; + TimeBasedWidget* GetTimeBasedWidget() const + { + return widget_; + } void SetTimeBasedWidget(TimeBasedWidget* widget); diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index 26f6a9e5f..beb5da7d3 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -22,68 +22,35 @@ #include -#include "config/config.h" -#include "common/channellayout.h" -#include "common/timecodefunctions.h" -#include "common/xmlutils.h" -#include "node/factory.h" -#include "panel/panelmanager.h" -#include "panel/node/node.h" -#include "panel/curve/curve.h" -#include "panel/param/param.h" #include "panel/timeline/timeline.h" -#include "panel/sequenceviewer/sequenceviewer.h" #include "ui/icons/icons.h" -#include "widget/videoparamedit/videoparamedit.h" namespace olive { -const QString Sequence::kVideoParamsInput = QStringLiteral("video_param_in"); -const QString Sequence::kAudioParamsInput = QStringLiteral("audio_param_in"); -const QString Sequence::kTextureInput = QStringLiteral("tex_in"); -const QString Sequence::kSamplesInput = QStringLiteral("samples_in"); const QString Sequence::kTrackInputFormat = QStringLiteral("track_in_%1"); -const uint64_t Sequence::kVideoParamEditMask = VideoParamEdit::kWidthHeight | VideoParamEdit::kInterlacing | VideoParamEdit::kFrameRate | VideoParamEdit::kPixelAspect; +#define super ViewerOutput -#define super Node - -Sequence::Sequence(bool viewer_only_mode) : - video_frame_cache_(this), - audio_playback_cache_(this), - operation_stack_(0) +Sequence::Sequence() { - AddInput(kVideoParamsInput, NodeValue::kVideoParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); - SetInputProperty(kVideoParamsInput, QStringLiteral("mask"), QVariant::fromValue(kVideoParamEditMask)); + // Create TrackList instances + track_lists_.resize(Track::kCount); - AddInput(kAudioParamsInput, NodeValue::kAudioParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + for (int i=0;i(i), track_input_id); - track_lists_.replace(i, list); - connect(list, &TrackList::TrackListChanged, this, &Sequence::UpdateTrackCache); - connect(list, &TrackList::LengthChanged, this, &Sequence::VerifyLength); - connect(list, &TrackList::TrackAdded, this, &Sequence::TrackAdded); - connect(list, &TrackList::TrackRemoved, this, &Sequence::TrackRemoved); - } + TrackList* list = new TrackList(this, static_cast(i), track_input_id); + track_lists_.replace(i, list); + connect(list, &TrackList::TrackListChanged, this, &Sequence::UpdateTrackCache); + connect(list, &TrackList::LengthChanged, this, &Sequence::VerifyLength); + connect(list, &TrackList::TrackAdded, this, &Sequence::TrackAdded); + connect(list, &TrackList::TrackRemoved, this, &Sequence::TrackRemoved); } - - // Create UUID for this node - uuid_ = QUuid::createUuid(); } Sequence::~Sequence() @@ -103,80 +70,6 @@ QIcon Sequence::icon() const return icon::Sequence; } -QString Sequence::duration() const -{ - rational timeline_length = GetLength(); - - int64_t timestamp = Timecode::time_to_timestamp(timeline_length, video_params().time_base()); - - return Timecode::timestamp_to_timecode(timestamp, video_params().time_base(), Core::instance()->GetTimecodeDisplay()); -} - -QString Sequence::rate() const -{ - return tr("%1 FPS").arg(video_params().time_base().flipped().toDouble()); -} - -void Sequence::set_default_parameters() -{ - int width = Config::Current()["DefaultSequenceWidth"].toInt(); - int height = Config::Current()["DefaultSequenceHeight"].toInt(); - - set_video_params(VideoParams(width, - height, - Config::Current()["DefaultSequenceFrameRate"].value(), - static_cast(Config::Current()["OfflinePixelFormat"].toInt()), - VideoParams::kInternalChannelCount, - Config::Current()["DefaultSequencePixelAspect"].value(), - Config::Current()["DefaultSequenceInterlacing"].value(), - VideoParams::generate_auto_divider(width, height))); - set_audio_params(AudioParams(Config::Current()["DefaultSequenceAudioFrequency"].toInt(), - Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), - AudioParams::kInternalFormat)); -} - -void Sequence::set_parameters_from_footage(const QVector footage) -{ - - foreach (Footage* f, footage) { - QVector video_streams = f->GetEnabledVideoStreams(); - QVector audio_streams = f->GetEnabledAudioStreams(); - - foreach (const VideoParams& s, video_streams) { - bool found_video_params = false; - rational using_timebase; - - if (s.video_type() == VideoParams::kVideoTypeStill) { - // If this is a still image, we'll use it's resolution but won't set - // `found_video_params` in case something with a frame rate comes along which we'll - // prioritize - using_timebase = video_params().time_base(); - } else { - using_timebase = s.frame_rate().flipped(); - found_video_params = true; - } - - set_video_params(VideoParams(s.width(), - s.height(), - using_timebase, - static_cast(Config::Current()[QStringLiteral("OfflinePixelFormat")].toInt()), - VideoParams::kInternalChannelCount, - s.pixel_aspect_ratio(), - s.interlacing(), - VideoParams::generate_auto_divider(s.width(), s.height()))); - - if (found_video_params) { - break; - } - } - - if (!audio_streams.isEmpty()) { - const AudioParams& s = audio_streams.first(); - set_audio_params(AudioParams(s.sample_rate(), s.channel_layout(), AudioParams::kInternalFormat)); - } - } -} - QVector Sequence::GetUnlockedTracks() const { QVector tracks = GetTracks(); @@ -195,12 +88,6 @@ void Sequence::Retranslate() { super::Retranslate(); - SetInputName(kVideoParamsInput, tr("Video Parameters")); - SetInputName(kAudioParamsInput, tr("Audio Parameters")); - - SetInputName(kTextureInput, tr("Texture")); - SetInputName(kSamplesInput, tr("Samples")); - for (int i=0;itrack_input() == input) { - // Return because we found our input - list->TrackConnected(output.node(), element); - return; - } + foreach (TrackList* list, track_lists_) { + if (list->track_input() == input) { + // Return because we found our input + list->TrackConnected(output.node(), element); + return; } } @@ -263,15 +146,11 @@ void Sequence::InputConnectedEvent(const QString &input, int element, const Node void Sequence::InputDisconnectedEvent(const QString &input, int element, const NodeOutput &output) { - if (input == kTextureInput) { - emit TextureInputChanged(); - } else { - foreach (TrackList* list, track_lists_) { - if (list->track_input() == input) { - // Return because we found our input - list->TrackDisconnected(output.node(), element); - return; - } + foreach (TrackList* list, track_lists_) { + if (list->track_input() == input) { + // Return because we found our input + list->TrackDisconnected(output.node(), element); + return; } } @@ -296,113 +175,6 @@ void Sequence::UpdateTrackCache() } } -void Sequence::ShiftVideoCache(const rational &from, const rational &to) -{ - video_frame_cache_.Shift(from, to); - - ShiftVideoEvent(from, to); -} - -void Sequence::ShiftAudioCache(const rational &from, const rational &to) -{ - audio_playback_cache_.Shift(from, to); - - ShiftAudioEvent(from, to); -} - -void Sequence::ShiftCache(const rational &from, const rational &to) -{ - ShiftVideoCache(from, to); - ShiftAudioCache(from, to); -} - -void Sequence::InvalidateCache(const TimeRange& range, const QString& from, int element, qint64 job_time) -{ - Q_UNUSED(element) - - if (operation_stack_ == 0) { - if (from == kTextureInput || from == kSamplesInput) { - TimeRange invalidated_range(qMax(rational(), range.in()), - qMin(GetLength(), range.out())); - - if (invalidated_range.in() != invalidated_range.out()) { - if (from == kTextureInput) { - video_frame_cache_.Invalidate(invalidated_range, job_time); - } else { - audio_playback_cache_.Invalidate(invalidated_range, job_time); - } - } - } - - VerifyLength(); - } - - super::InvalidateCache(range, from, element, job_time); -} - -const rational& Sequence::GetLength() const -{ - return last_length_; -} - -void Sequence::VerifyLength() -{ - if (operation_stack_ != 0) { - return; - } - - NodeTraverser traverser; - - rational video_length, audio_length, subtitle_length; - - { - video_length = GetCustomLength(Track::kVideo); - - if (video_length.isNull() && IsInputConnected(kTextureInput)) { - NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kTextureInput), TimeRange(0, 0)); - video_length = t.Get(NodeValue::kRational, QStringLiteral("length")).value(); - } - - video_frame_cache_.SetLength(video_length); - } - - { - audio_length = GetCustomLength(Track::kAudio); - - if (audio_length.isNull() && IsInputConnected(kSamplesInput)) { - NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kSamplesInput), TimeRange(0, 0)); - audio_length = t.Get(NodeValue::kRational, QStringLiteral("length")).value(); - } - - audio_playback_cache_.SetLength(audio_length); - } - - { - subtitle_length = GetCustomLength(Track::kSubtitle); - } - - rational real_length = qMax(subtitle_length, qMax(video_length, audio_length)); - - if (real_length != last_length_) { - last_length_ = real_length; - emit LengthChanged(last_length_); - } -} - -void Sequence::BeginOperation() -{ - operation_stack_++; - - super::BeginOperation(); -} - -void Sequence::EndOperation() -{ - operation_stack_--; - - super::EndOperation(); -} - void Sequence::LoadInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt *cancelled) { Q_UNUSED(xml_node_data) @@ -426,53 +198,4 @@ void Sequence::SaveInternal(QXmlStreamWriter *writer) const writer->writeEndElement(); // points } -void Sequence::InputValueChangedEvent(const QString &input, int element) -{ - if (input == kVideoParamsInput) { - - VideoParams new_video_params = video_params(); - - bool size_changed = cached_video_params_.width() != new_video_params.width() || cached_video_params_.height() != new_video_params.height(); - bool timebase_changed = cached_video_params_.time_base() != new_video_params.time_base(); - bool pixel_aspect_changed = cached_video_params_.pixel_aspect_ratio() != new_video_params.pixel_aspect_ratio(); - bool interlacing_changed = cached_video_params_.interlacing() != new_video_params.interlacing(); - - if (size_changed) { - emit SizeChanged(new_video_params.width(), new_video_params.height()); - } - - if (pixel_aspect_changed) { - emit PixelAspectChanged(new_video_params.pixel_aspect_ratio()); - } - - if (interlacing_changed) { - emit InterlacingChanged(new_video_params.interlacing()); - } - - if (timebase_changed) { - video_frame_cache_.SetTimebase(new_video_params.time_base()); - emit TimebaseChanged(new_video_params.time_base()); - } - - emit VideoParamsChanged(); - - cached_video_params_ = video_params(); - video_frame_cache_.InvalidateAll(); - - } else if (input == kAudioParamsInput) { - - emit AudioParamsChanged(); - - // This will automatically InvalidateAll - audio_playback_cache_.SetParameters(audio_params()); - - } -} - -void Sequence::ShiftVideoEvent(const rational &from, const rational &to) -{ - Q_UNUSED(from) - Q_UNUSED(to) -} - } diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index db46d836b..2608b424f 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -21,23 +21,8 @@ #ifndef SEQUENCE_H #define SEQUENCE_H -#include - -#include "common/rational.h" -#include "node/block/block.h" -#include "node/graph.h" -#include "node/node.h" -#include "node/output/track/track.h" #include "node/output/track/tracklist.h" -#include "node/traverser.h" -#include "project/item/footage/footage.h" -#include "render/audioparams.h" -#include "render/audioplaybackcache.h" -#include "render/framehashcache.h" -#include "render/videoparams.h" -#include "render/videoparams.h" -#include "timeline/timelinecommon.h" -#include "timeline/timelinepoints.h" +#include "node/output/viewer/viewer.h" #include "timeline/timelinepoints.h" namespace olive { @@ -45,11 +30,11 @@ namespace olive { /** * @brief The main timeline object, an graph of edited clips that forms a complete edit */ -class Sequence : public Node, public TimelinePoints +class Sequence : public ViewerOutput { Q_OBJECT public: - Sequence(bool viewer_only_mode = false); + Sequence(); virtual ~Sequence() override; @@ -82,13 +67,6 @@ public: virtual QIcon icon() const override; - virtual QString duration() const override; - virtual QString rate() const override; - - void set_default_parameters(); - - void set_parameters_from_footage(const QVector footage); - const QVector &GetTracks() const { return track_cache_; @@ -109,130 +87,42 @@ public: return track_lists_.at(type); } - void ShiftVideoCache(const rational& from, const rational& to); - void ShiftAudioCache(const rational& from, const rational& to); - void ShiftCache(const rational& from, const rational& to); - - virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, qint64 job_time) override; - - VideoParams video_params() const - { - return GetStandardValue(kVideoParamsInput).value(); - } - - AudioParams audio_params() const - { - return GetStandardValue(kAudioParamsInput).value(); - } - - void set_video_params(const VideoParams &video) - { - SetStandardValue(kVideoParamsInput, QVariant::fromValue(video)); - } - - void set_audio_params(const AudioParams &audio) - { - SetStandardValue(kAudioParamsInput, QVariant::fromValue(audio)); - } - - const rational &GetLength() const; - virtual void Retranslate() override; - FrameHashCache* video_frame_cache() - { - return &video_frame_cache_; - } - - AudioPlaybackCache* audio_playback_cache() - { - return &audio_playback_cache_; - } - - virtual void BeginOperation() override; - - virtual void EndOperation() override; - - static const QString kVideoParamsInput; - static const QString kAudioParamsInput; - - static const QString kTextureInput; - static const QString kSamplesInput; static const QString kTrackInputFormat; - static const uint64_t kVideoParamEditMask; - TimelinePoints* timeline_points() { return &timeline_points_; } - const QUuid& uuid() const - { - return uuid_; - } - virtual bool IsItem() const override { return true; } -signals: - void TimebaseChanged(const rational&); - - void LengthChanged(const rational& length); - - void SizeChanged(int width, int height); - - void PixelAspectChanged(const rational& pixel_aspect); - - void InterlacingChanged(VideoParams::Interlacing mode); - - void VideoParamsChanged(); - void AudioParamsChanged(); - - void TrackAdded(Track* track); - void TrackRemoved(Track* track); - - void TextureInputChanged(); - -public slots: - void VerifyLength(); - protected: - virtual void InputConnectedEvent(const QString &input, int element, const NodeOutput &output) override; - - virtual void InputDisconnectedEvent(const QString &input, int element, const NodeOutput &output) override; - - virtual rational GetCustomLength(Track::Type type) const; - - virtual void ShiftVideoEvent(const rational &from, const rational &to); - - virtual void ShiftAudioEvent(const rational &from, const rational &to); - virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData &xml_node_data, uint version, const QAtomicInt* cancelled) override; virtual void SaveInternal(QXmlStreamWriter *writer) const override; - virtual void InputValueChangedEvent(const QString& input, int element) override; + virtual void ShiftAudioEvent(const rational &from, const rational &to) override; + + virtual void InputConnectedEvent(const QString &input, int element, const NodeOutput &output) override; + + virtual void InputDisconnectedEvent(const QString &input, int element, const NodeOutput &output) override; + + virtual rational GetCustomLength(Track::Type type) const override; + +signals: + void TrackAdded(Track* track); + void TrackRemoved(Track* track); private: QVector track_lists_; QVector track_cache_; - QUuid uuid_; - - rational last_length_; - - FrameHashCache video_frame_cache_; - - AudioPlaybackCache audio_playback_cache_; - - int operation_stack_; - - VideoParams cached_video_params_; - TimelinePoints timeline_points_; private slots: diff --git a/app/project/project.h b/app/project/project.h index c0bbb0c4b..022531034 100644 --- a/app/project/project.h +++ b/app/project/project.h @@ -21,8 +21,9 @@ #ifndef PROJECT_H #define PROJECT_H -#include #include +#include +#include #include "node/project/projectsettings/projectsettings.h" #include "node/output/viewer/viewer.h" diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index 8f7f5f8fa..5933ddadb 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -3,7 +3,6 @@ #include #include -#include "project/item/sequence/sequence.h" #include "project/project.h" #include "render/rendermanager.h" #include "render/renderprocessor.h" @@ -65,13 +64,13 @@ void PreviewAutoCacher::SetPaused(bool paused) } } -void PreviewAutoCacher::GenerateHashes(Sequence *viewer, FrameHashCache* cache, const QVector ×, qint64 job_time) +void PreviewAutoCacher::GenerateHashes(ViewerOutput *viewer, FrameHashCache* cache, const QVector ×, qint64 job_time) { std::vector existing_hashes; foreach (const rational& time, times) { // See if hash already exists in disk cache - QByteArray hash = RenderManager::Hash(viewer->GetConnectedNode(Sequence::kTextureInput), viewer->video_params(), time); + QByteArray hash = RenderManager::Hash(viewer->GetConnectedNode(ViewerOutput::kTextureInput), viewer->video_params(), time); // Check memory list since disk checking is slow bool hash_exists = (std::find(existing_hashes.begin(), existing_hashes.end(), hash) != existing_hashes.end()); @@ -590,7 +589,7 @@ void PreviewAutoCacher::ForceCacheRange(const TimeRange &range) RequeueFrames(); } -void PreviewAutoCacher::SetViewerNode(Sequence *viewer_node) +void PreviewAutoCacher::SetViewerNode(ViewerOutput *viewer_node) { if (viewer_node_ == viewer_node) { return; @@ -662,7 +661,7 @@ void PreviewAutoCacher::SetViewerNode(Sequence *viewer_node) } // Find copied viewer node - copied_viewer_node_ = static_cast(copy_map_.value(viewer_node_)); + copied_viewer_node_ = static_cast(copy_map_.value(viewer_node_)); // Copy parameters copied_viewer_node_->set_video_params(viewer_node_->video_params()); diff --git a/app/render/previewautocacher.h b/app/render/previewautocacher.h index 78b28ce6c..f07fd8c17 100644 --- a/app/render/previewautocacher.h +++ b/app/render/previewautocacher.h @@ -31,7 +31,7 @@ public: /** * @brief Set the viewer node to auto-cache */ - void SetViewerNode(Sequence *viewer_node); + void SetViewerNode(ViewerOutput *viewer_node); /** * @brief If the mouse is held during the next cache invalidation, cache anyway @@ -85,7 +85,7 @@ public: } private: - static void GenerateHashes(Sequence *viewer, FrameHashCache *cache, const QVector& times, qint64 job_time); + static void GenerateHashes(ViewerOutput *viewer, FrameHashCache *cache, const QVector& times, qint64 job_time); void TryRender(); @@ -125,13 +125,13 @@ private: NodeOutput output; }; - Sequence* viewer_node_; + ViewerOutput* viewer_node_; Project copied_project_; QVector graph_update_queue_; QHash copy_map_; - Sequence* copied_viewer_node_; + ViewerOutput* copied_viewer_node_; QVector created_nodes_; bool paused_; diff --git a/app/render/rendermanager.cpp b/app/render/rendermanager.cpp index e55432af9..0ebf4c528 100644 --- a/app/render/rendermanager.cpp +++ b/app/render/rendermanager.cpp @@ -99,7 +99,7 @@ QByteArray RenderManager::Hash(const Node *n, const VideoParams ¶ms, const r return hasher.result(); } -RenderTicketPtr RenderManager::RenderFrame(Sequence* viewer, ColorManager* color_manager, +RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, FrameHashCache* cache, bool prioritize) { @@ -117,7 +117,7 @@ RenderTicketPtr RenderManager::RenderFrame(Sequence* viewer, ColorManager* color prioritize); } -RenderTicketPtr RenderManager::RenderFrame(Sequence* viewer, ColorManager* color_manager, +RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, const VideoParams &video_params, const AudioParams &audio_params, const QSize& force_size, @@ -156,12 +156,12 @@ RenderTicketPtr RenderManager::RenderFrame(Sequence* viewer, ColorManager* color return ticket; } -RenderTicketPtr RenderManager::RenderAudio(Sequence* viewer, const TimeRange& r, bool generate_waveforms, bool prioritize) +RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange& r, bool generate_waveforms, bool prioritize) { return RenderAudio(viewer, r, viewer->audio_params(), generate_waveforms, prioritize); } -RenderTicketPtr RenderManager::RenderAudio(Sequence* viewer, const TimeRange &r, const AudioParams ¶ms, bool generate_waveforms, bool prioritize) +RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange &r, const AudioParams ¶ms, bool generate_waveforms, bool prioritize) { // Create ticket RenderTicketPtr ticket = std::make_shared(); diff --git a/app/render/rendermanager.h b/app/render/rendermanager.h index 8d9c50c28..7881894a0 100644 --- a/app/render/rendermanager.h +++ b/app/render/rendermanager.h @@ -80,10 +80,10 @@ public: * * This function is thread-safe. */ - RenderTicketPtr RenderFrame(Sequence *viewer, ColorManager* color_manager, + RenderTicketPtr RenderFrame(ViewerOutput *viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, FrameHashCache* cache = nullptr, bool prioritize = false); - RenderTicketPtr RenderFrame(Sequence* viewer, ColorManager* color_manager, + RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager, const rational& time, RenderMode::Mode mode, const VideoParams& video_params, const AudioParams& audio_params, const QSize& force_size, @@ -101,8 +101,8 @@ public: * * This function is thread-safe. */ - RenderTicketPtr RenderAudio(Sequence* viewer, const TimeRange& r, const AudioParams& params, bool generate_waveforms, bool prioritize = false); - RenderTicketPtr RenderAudio(Sequence *viewer, const TimeRange& r, bool generate_waveforms, bool prioritize = false); + RenderTicketPtr RenderAudio(ViewerOutput* viewer, const TimeRange& r, const AudioParams& params, bool generate_waveforms, bool prioritize = false); + RenderTicketPtr RenderAudio(ViewerOutput *viewer, const TimeRange& r, bool generate_waveforms, bool prioritize = false); RenderTicketPtr SaveFrameToCache(FrameHashCache* cache, FramePtr frame, const QByteArray& hash, bool prioritize = false); diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index a5b08019d..0490ff211 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -54,11 +54,11 @@ void RenderProcessor::Run() switch (type) { case RenderManager::kTypeVideo: { - Sequence* viewer = Node::ValueToPtr(ticket_->property("viewer")); + ViewerOutput* viewer = Node::ValueToPtr(ticket_->property("viewer")); const VideoParams& video_params = ticket_->property("vparam").value(); rational time = ticket_->property("time").value(); - NodeValueTable table = ProcessInput(viewer, Sequence::kTextureInput, + NodeValueTable table = ProcessInput(viewer, ViewerOutput::kTextureInput, TimeRange(time, time + video_params.time_base())); TexturePtr texture = table.Get(NodeValue::kTexture).value(); @@ -130,10 +130,10 @@ void RenderProcessor::Run() } case RenderManager::kTypeAudio: { - Sequence* viewer = Node::ValueToPtr(ticket_->property("viewer")); + ViewerOutput* viewer = Node::ValueToPtr(ticket_->property("viewer")); TimeRange time = ticket_->property("time").value(); - NodeValueTable table = ProcessInput(viewer, Sequence::kSamplesInput, time); + NodeValueTable table = ProcessInput(viewer, ViewerOutput::kSamplesInput, time); ticket_->Finish(table.Get(NodeValue::kSamples), IsCancelled()); break; diff --git a/app/task/export/export.cpp b/app/task/export/export.cpp index 927d1ca49..41564a3d8 100644 --- a/app/task/export/export.cpp +++ b/app/task/export/export.cpp @@ -25,7 +25,7 @@ namespace olive { -ExportTask::ExportTask(Sequence *viewer_node, +ExportTask::ExportTask(ViewerOutput *viewer_node, ColorManager* color_manager, const ExportParams& params) : RenderTask(viewer_node, params.video_params(), params.audio_params()), diff --git a/app/task/export/export.h b/app/task/export/export.h index ec4d305b0..1382d6856 100644 --- a/app/task/export/export.h +++ b/app/task/export/export.h @@ -33,7 +33,7 @@ class ExportTask : public RenderTask { Q_OBJECT public: - ExportTask(Sequence *viewer_node, ColorManager *color_manager, const ExportParams ¶ms); + ExportTask(ViewerOutput *viewer_node, ColorManager *color_manager, const ExportParams ¶ms); protected: virtual bool Run() override; diff --git a/app/task/render/render.cpp b/app/task/render/render.cpp index d397d9ec3..913a544ac 100644 --- a/app/task/render/render.cpp +++ b/app/task/render/render.cpp @@ -25,7 +25,7 @@ namespace olive { -RenderTask::RenderTask(Sequence* viewer, const VideoParams &vparams, const AudioParams &aparams) : +RenderTask::RenderTask(ViewerOutput *viewer, const VideoParams &vparams, const AudioParams &aparams) : viewer_(viewer), video_params_(vparams), audio_params_(aparams), diff --git a/app/task/render/render.h b/app/task/render/render.h index b4a2aaeee..391b65884 100644 --- a/app/task/render/render.h +++ b/app/task/render/render.h @@ -35,7 +35,7 @@ class RenderTask : public Task { Q_OBJECT public: - RenderTask(Sequence* viewer, const VideoParams &vparams, const AudioParams &aparams); + RenderTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams); virtual ~RenderTask() override; @@ -53,7 +53,7 @@ protected: virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples, qint64 job_time) = 0; - Sequence* viewer() const + ViewerOutput* viewer() const { return viewer_; } @@ -87,7 +87,7 @@ private: void StartTicket(const QByteArray &hash, QThread *watcher_thread, ColorManager *manager, const rational &time, RenderMode::Mode mode, FrameHashCache *cache, const QSize &force_size, const QMatrix4x4 &force_matrix, VideoParams::Format force_format, ColorProcessorPtr force_color_output); - Sequence* viewer_; + ViewerOutput* viewer_; VideoParams video_params_; diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp index 2e9c0fe53..f8d7f6f94 100644 --- a/app/widget/curvewidget/curvewidget.cpp +++ b/app/widget/curvewidget/curvewidget.cpp @@ -185,7 +185,7 @@ void CurveWidget::TimeTargetChangedEvent(Node *target) view_->SetTimeTarget(target); } -void CurveWidget::ConnectedNodeChanged(Sequence *n) +void CurveWidget::ConnectedNodeChanged(ViewerOutput *n) { SetTimeTarget(n); } diff --git a/app/widget/curvewidget/curvewidget.h b/app/widget/curvewidget/curvewidget.h index 5c2758811..b0a281df7 100644 --- a/app/widget/curvewidget/curvewidget.h +++ b/app/widget/curvewidget/curvewidget.h @@ -67,7 +67,7 @@ protected: virtual void TimeTargetChangedEvent(Node* target) override; - virtual void ConnectedNodeChanged(Sequence* n) override; + virtual void ConnectedNodeChanged(ViewerOutput* n) override; private: void SetKeyframeButtonEnabled(bool enable); diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index 8998117d9..43a55a01e 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -226,7 +226,7 @@ void NodeParamView::TimeChangedEvent(const int64_t ×tamp) UpdateItemTime(timestamp); } -void NodeParamView::ConnectedNodeChanged(Sequence *n) +void NodeParamView::ConnectedNodeChanged(ViewerOutput *n) { // Set viewer as a time target keyframe_view_->SetTimeTarget(n); diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index 9a68e1783..91c842823 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -96,7 +96,7 @@ protected: virtual void TimebaseChangedEvent(const rational&) override; virtual void TimeChangedEvent(const int64_t &) override; - virtual void ConnectedNodeChanged(Sequence* n) override; + virtual void ConnectedNodeChanged(ViewerOutput* n) override; private: void UpdateItemTime(const int64_t ×tamp); diff --git a/app/widget/timebased/timebasedwidget.cpp b/app/widget/timebased/timebasedwidget.cpp index 9b1023320..8236e57e9 100644 --- a/app/widget/timebased/timebasedwidget.cpp +++ b/app/widget/timebased/timebasedwidget.cpp @@ -68,12 +68,12 @@ const int64_t &TimeBasedWidget::GetTimestamp() const return ruler_->GetTime(); } -Sequence *TimeBasedWidget::GetConnectedNode() const +ViewerOutput *TimeBasedWidget::GetConnectedNode() const { return viewer_node_; } -void TimeBasedWidget::ConnectViewerNode(Sequence *node) +void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) { if (viewer_node_ == node) { return; @@ -101,7 +101,7 @@ void TimeBasedWidget::ConnectViewerNode(Sequence *node) if (viewer_node_) { connect(viewer_node_, &ViewerOutput::LengthChanged, this, &TimeBasedWidget::UpdateMaximumScroll); - if ((points_ = ConnectTimelinePoints())) { + if ((points_ = GetTimelinePointsToConnect())) { ruler()->ConnectTimelinePoints(points_); scrollbar_->ConnectTimelinePoints(points_); } @@ -242,9 +242,15 @@ void TimeBasedWidget::resizeEvent(QResizeEvent *event) UpdateMaximumScroll(); } -TimelinePoints *TimeBasedWidget::ConnectTimelinePoints() +TimelinePoints *TimeBasedWidget::GetTimelinePointsToConnect() { - return viewer_node_->timeline_points(); + Sequence* sequence = dynamic_cast(viewer_node_); + + if (sequence) { + return sequence->timeline_points(); + } + + return nullptr; } Project *TimeBasedWidget::GetTimelinePointsProject() diff --git a/app/widget/timebased/timebasedwidget.h b/app/widget/timebased/timebasedwidget.h index 2414d44b1..1089bacfc 100644 --- a/app/widget/timebased/timebasedwidget.h +++ b/app/widget/timebased/timebasedwidget.h @@ -46,9 +46,11 @@ public: void ZoomOut(); - Sequence* GetConnectedNode() const; + ViewerOutput* GetConnectedNode() const; - void ConnectViewerNode(Sequence *node); + TimelinePoints* GetConnectedTimelinePoints() const; + + void ConnectViewerNode(ViewerOutput *node); void SetScaleAndCenterOnPlayhead(const double& scale); @@ -105,22 +107,20 @@ protected: virtual void ScaleChangedEvent(const double &) override; - virtual void ConnectedNodeChanged(Sequence*){} + virtual void ConnectedNodeChanged(ViewerOutput*){} - virtual void ConnectNodeInternal(Sequence*){} + virtual void ConnectNodeInternal(ViewerOutput*){} - virtual void DisconnectNodeInternal(Sequence*){} + virtual void DisconnectNodeInternal(ViewerOutput*){} void SetAutoMaxScrollBar(bool e); virtual void resizeEvent(QResizeEvent *event) override; - virtual TimelinePoints* ConnectTimelinePoints(); + virtual TimelinePoints* GetTimelinePointsToConnect(); virtual Project* GetTimelinePointsProject(); - TimelinePoints* GetConnectedTimelinePoints() const; - void ConnectTimelineView(TimeBasedView* base, bool connect_time_change_event = true); void PassWheelEventsToScrollBar(QObject* object); @@ -189,7 +189,7 @@ private: bool UserIsDraggingPlayhead() const; - Sequence* viewer_node_; + ViewerOutput* viewer_node_; TimeRuler* ruler_; diff --git a/app/widget/timelinewidget/timelineundo.h b/app/widget/timelinewidget/timelineundo.h index 1aa557402..1cfbb8df0 100644 --- a/app/widget/timelinewidget/timelineundo.h +++ b/app/widget/timelinewidget/timelineundo.h @@ -1395,9 +1395,9 @@ public: QString relevant_input; if (timeline_->type() == Track::kVideo) { - relevant_input = Sequence::kTextureInput; + relevant_input = ViewerOutput::kTextureInput; } else { - relevant_input = Sequence::kSamplesInput; + relevant_input = ViewerOutput::kSamplesInput; } if (!timeline_->parent()->IsInputConnected(relevant_input)) { diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 156a3ed7d..6c4a48928 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -218,10 +218,12 @@ void TimelineWidget::ScaleChangedEvent(const double &scale) } } -void TimelineWidget::ConnectNodeInternal(Sequence *n) +void TimelineWidget::ConnectNodeInternal(ViewerOutput *n) { - connect(n, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack); - connect(n, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack); + Sequence* s = static_cast(n); + + connect(s, &Sequence::TrackAdded, this, &TimelineWidget::AddTrack); + connect(s, &Sequence::TrackRemoved, this, &TimelineWidget::RemoveTrack); connect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); ruler()->SetPlaybackCache(n->video_frame_cache()); @@ -229,7 +231,6 @@ void TimelineWidget::ConnectNodeInternal(Sequence *n) SetTimebase(n->video_params().time_base()); for (int i=0;i(n); Track::Type track_type = static_cast(i); TimelineView* view = views_.at(i)->view(); TrackList* track_list = s->track_list(track_type); @@ -246,15 +247,16 @@ void TimelineWidget::ConnectNodeInternal(Sequence *n) } } -void TimelineWidget::DisconnectNodeInternal(Sequence *n) +void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n) { - disconnect(n, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack); - disconnect(n, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack); + Sequence* s = static_cast(n); + + disconnect(s, &Sequence::TrackAdded, this, &TimelineWidget::AddTrack); + disconnect(s, &Sequence::TrackRemoved, this, &TimelineWidget::RemoveTrack); disconnect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); DeselectAll(); - Sequence* s = static_cast(n); foreach (Track* track, s->GetTracks()) { RemoveTrack(track); } diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index c43c3d438..bcc667830 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -245,8 +245,8 @@ protected: virtual void TimeChangedEvent(const int64_t &) override; virtual void ScaleChangedEvent(const double &) override; - virtual void ConnectNodeInternal(Sequence* n) override; - virtual void DisconnectNodeInternal(Sequence* n) override; + virtual void ConnectNodeInternal(ViewerOutput* n) override; + virtual void DisconnectNodeInternal(ViewerOutput* n) override; virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata) override; virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void* userdata) override; diff --git a/app/widget/timelinewidget/tool/add.cpp b/app/widget/timelinewidget/tool/add.cpp index d0e89749d..3994b7b55 100644 --- a/app/widget/timelinewidget/tool/add.cpp +++ b/app/widget/timelinewidget/tool/add.cpp @@ -102,7 +102,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event) command->add_child(new NodeAddCommand(graph, clip)); - command->add_child(new TrackPlaceBlockCommand(static_cast(parent()->GetConnectedNode())->track_list(track.type()), + command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()), track.index(), clip, ghost_->GetAdjustedIn())); diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index d5d89725e..ddfeb2d3d 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -313,12 +313,11 @@ void ImportTool::DropGhosts(bool insert) MultiUndoCommand* command = new MultiUndoCommand(); NodeGraph* dst_graph = nullptr; - Sequence* sequence = nullptr; + Sequence* sequence = this->sequence(); bool open_sequence = false; - if (parent()->GetConnectedNode()) { - sequence = parent()->GetConnectedNode(); - dst_graph = parent()->GetConnectedNode()->parent(); + if (sequence) { + dst_graph = sequence->parent(); } else { // There's no active timeline here, ask the user what to do diff --git a/app/widget/viewer/footageviewer.cpp b/app/widget/viewer/footageviewer.cpp index dfaf8fdf3..6df6a8763 100644 --- a/app/widget/viewer/footageviewer.cpp +++ b/app/widget/viewer/footageviewer.cpp @@ -91,7 +91,7 @@ void FootageViewerWidget::SetFootage(Footage *footage) } } -TimelinePoints *FootageViewerWidget::ConnectTimelinePoints() +TimelinePoints *FootageViewerWidget::GetTimelinePointsToConnect() { return footage_; } diff --git a/app/widget/viewer/footageviewer.h b/app/widget/viewer/footageviewer.h index c25b5449b..8da9f478f 100644 --- a/app/widget/viewer/footageviewer.h +++ b/app/widget/viewer/footageviewer.h @@ -36,7 +36,7 @@ public: void SetFootage(Footage* footage); protected: - virtual TimelinePoints* ConnectTimelinePoints() override; + virtual TimelinePoints* GetTimelinePointsToConnect() override; virtual Project* GetTimelinePointsProject() override; diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index f16f9793f..089ddd3e7 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -35,7 +35,6 @@ #include "common/ratiodialog.h" #include "common/timecodefunctions.h" #include "config/config.h" -#include "project/item/sequence/sequence.h" #include "project/project.h" #include "render/rendermanager.h" #include "task/taskmanager.h" @@ -44,12 +43,14 @@ namespace olive { +#define super TimeBasedWidget + QVector ViewerWidget::instances_; const int kMaxPreQueueSize = 16; ViewerWidget::ViewerWidget(QWidget *parent) : - TimeBasedWidget(false, true, parent), + super(false, true, parent), playback_speed_(0), frame_cache_job_time_(0), color_menu_enabled_(true), @@ -168,7 +169,7 @@ void ViewerWidget::TimeChangedEvent(const int64_t &i) last_time_ = i; } -void ViewerWidget::ConnectNodeInternal(Sequence *n) +void ViewerWidget::ConnectNodeInternal(ViewerOutput *n) { connect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SetViewerResolution); connect(n, &ViewerOutput::PixelAspectChanged, this, &ViewerWidget::SetViewerPixelAspect); @@ -220,7 +221,7 @@ void ViewerWidget::ConnectNodeInternal(Sequence *n) ForceUpdate(); } -void ViewerWidget::DisconnectNodeInternal(Sequence *n) +void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n) { PauseInternal(); @@ -252,21 +253,21 @@ void ViewerWidget::DisconnectNodeInternal(Sequence *n) QMetaObject::invokeMethod(this, "UpdateStack", Qt::QueuedConnection); } -void ViewerWidget::ConnectedNodeChanged(Sequence *n) +void ViewerWidget::ConnectedNodeChanged(ViewerOutput *n) { auto_cacher_.SetViewerNode(n); } void ViewerWidget::ScaleChangedEvent(const double &s) { - TimeBasedWidget::ScaleChangedEvent(s); + super::ScaleChangedEvent(s); waveform_view_->SetScale(s); } void ViewerWidget::resizeEvent(QResizeEvent *event) { - TimeBasedWidget::resizeEvent(event); + super::resizeEvent(event); UpdateMinimumScale(); } @@ -285,11 +286,11 @@ bool ViewerWidget::IsPlaying() const return playback_speed_ != 0; } -void ViewerWidget::ConnectViewerNode(Sequence *node, ColorManager* color_manager) +void ViewerWidget::ConnectViewerNode(ViewerOutput *node, ColorManager* color_manager) { override_color_manager_ = color_manager; - TimeBasedWidget::ConnectViewerNode(node); + super::ConnectViewerNode(node); } void ViewerWidget::SetColorMenuEnabled(bool enabled) @@ -1053,7 +1054,7 @@ void ViewerWidget::SetSignalCursorColorEnabled(bool e) void ViewerWidget::TimebaseChangedEvent(const rational &timebase) { - TimeBasedWidget::TimebaseChangedEvent(timebase); + super::TimebaseChangedEvent(timebase); controls_->SetTimebase(timebase); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 0128ff126..e0e448471 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -63,7 +63,7 @@ public: bool IsPlaying() const; - void ConnectViewerNode(Sequence *node, ColorManager *color_manager = nullptr); + void ConnectViewerNode(ViewerOutput *node, ColorManager *color_manager = nullptr); /** * @brief Enable or disable the color management menu @@ -153,9 +153,9 @@ protected: virtual void TimebaseChangedEvent(const rational &) override; virtual void TimeChangedEvent(const int64_t &) override; - virtual void ConnectNodeInternal(Sequence *) override; - virtual void DisconnectNodeInternal(Sequence *) override; - virtual void ConnectedNodeChanged(Sequence*n) override; + virtual void ConnectNodeInternal(ViewerOutput *) override; + virtual void DisconnectNodeInternal(ViewerOutput *) override; + virtual void ConnectedNodeChanged(ViewerOutput*n) override; virtual void ScaleChangedEvent(const double& s) override; diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index e4bc0763b..67ef4cdf6 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -549,7 +549,7 @@ void MainWindow::RemoveProjectPanel(ProjectPanel *panel) } } -void MainWindow::TimelineFocused(Sequence* viewer) +void MainWindow::TimelineFocused(ViewerOutput* viewer) { sequence_viewer_panel_->ConnectViewerNode(viewer); param_panel_->ConnectViewerNode(viewer); diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index 68c34a01c..4af363f19 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -130,7 +130,7 @@ private: void RemoveProjectPanel(ProjectPanel* panel); - void TimelineFocused(Sequence *viewer); + void TimelineFocused(ViewerOutput *viewer); QByteArray premaximized_state_;