Merge branch 'merge-timeline-and-viewer'

This commit is contained in:
itsmattkc
2020-01-04 02:45:26 +11:00
22 changed files with 194 additions and 368 deletions
-3
View File
@@ -8,7 +8,6 @@
#include "distort/transform/transform.h"
#include "input/media/video/video.h"
#include "input/media/audio/audio.h"
#include "output/timeline/timeline.h"
#include "output/track/track.h"
#include "output/viewer/viewer.h"
#include "external.h"
@@ -127,8 +126,6 @@ Node *NodeFactory::CreateInternal(const NodeFactory::InternalID &id)
return new VideoInput();
case kAudioInput:
return new AudioInput();
case kTimelineOutput:
return new TimelineOutput();
case kTrackOutput:
return new TrackOutput();
case kViewerOutput:
-1
View File
@@ -16,7 +16,6 @@ public:
kAudioInput,
kTransformDistort,
kVideoInput,
kTimelineOutput,
kTrackOutput,
kAudioVolume,
kAudioPanning,
-1
View File
@@ -14,7 +14,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(timeline)
add_subdirectory(track)
add_subdirectory(viewer)
-24
View File
@@ -1,24 +0,0 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2019 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/output/timeline/timeline.h
node/output/timeline/timeline.cpp
node/output/timeline/tracklist.h
node/output/timeline/tracklist.cpp
PARENT_SCOPE
)
-204
View File
@@ -1,204 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "timeline.h"
#include <QDebug>
#include "node/block/gap/gap.h"
#include "node/graph.h"
#include "panel/timeline/timeline.h"
TimelineOutput::TimelineOutput()
{
// Create TrackList instances
track_inputs_.resize(kTrackTypeCount);
track_lists_.resize(kTrackTypeCount);
for (int i=0;i<kTrackTypeCount;i++) {
// Create track input
NodeInputArray* track_input = new NodeInputArray(QStringLiteral("track_in_%1").arg(i), NodeParam::kAny);
AddInput(track_input);
track_inputs_.replace(i, track_input);
TrackList* list = new TrackList(this, static_cast<TrackType>(i), track_input);
track_lists_.replace(i, list);
connect(list, SIGNAL(TrackListChanged()), this, SLOT(UpdateTrackCache()));
connect(list, SIGNAL(LengthChanged(const rational &)), this, SLOT(UpdateLength(const rational &)));
connect(list, SIGNAL(BlockAdded(Block*, int)), this, SLOT(TrackListAddedBlock(Block*, int)));
connect(list, SIGNAL(BlockRemoved(Block*)), this, SIGNAL(BlockRemoved(Block*)));
connect(list, SIGNAL(TrackAdded(TrackOutput*)), this, SLOT(TrackListAddedTrack(TrackOutput*)));
connect(list, SIGNAL(TrackRemoved(TrackOutput*)), this, SIGNAL(TrackRemoved(TrackOutput*)));
connect(list, SIGNAL(TrackHeightChanged(int, int)), this, SLOT(TrackHeightChangedSlot(int, int)));
}
}
Node *TimelineOutput::copy() const
{
return new TimelineOutput();
}
QString TimelineOutput::Name() const
{
return tr("Timeline");
}
QString TimelineOutput::id() const
{
return "org.olivevideoeditor.Olive.timeline";
}
QString TimelineOutput::Category() const
{
return tr("Output");
}
QString TimelineOutput::Description() const
{
return tr("Node for communicating between a Timeline panel and the node graph.");
}
const rational &TimelineOutput::length() const
{
return length_;
}
const QVector<TrackOutput *>& TimelineOutput::Tracks() const
{
return track_cache_;
}
const rational &TimelineOutput::timeline_length() const
{
return length_;
}
const rational &TimelineOutput::timebase() const
{
return timebase_;
}
NodeValueTable TimelineOutput::Value(const NodeValueDatabase &value) const
{
NodeValueTable table = value.Merge();
table.Push(NodeParam::kRational, QVariant::fromValue(length()), "length");
return table;
}
void TimelineOutput::UpdateTrackCache()
{
track_cache_.clear();
foreach (TrackList* list, track_lists_) {
QVector<TrackOutput*> track_list = list->Tracks();
foreach (TrackOutput* track, track_list) {
if (track) {
track_cache_.append(list->Tracks());
}
}
}
}
void TimelineOutput::UpdateLength(const rational &length)
{
// If this length is equal, no-op
if (length == length_) {
return;
}
// If this length is greater, this must be the new total length
if (length > length_) {
length_ = length;
emit LengthChanged(length_);
return;
}
// Otherwise, the new length is shorter and we'll have to manually determine what the new max length is
rational new_length = 0;
foreach (TrackList* list, track_lists_) {
new_length = qMax(new_length, list->TrackLength());
}
if (new_length != length_) {
length_ = new_length;
emit LengthChanged(length_);
}
}
void TimelineOutput::SetTimebase(const rational &timebase)
{
timebase_ = timebase;
emit TimebaseChanged(timebase_);
}
void TimelineOutput::Retranslate()
{
for (int i=0;i<track_inputs_.size();i++) {
QString input_name;
switch (static_cast<TrackType>(i)) {
case kTrackTypeVideo:
input_name = tr("Video Tracks");
break;
case kTrackTypeAudio:
input_name = tr("Audio Tracks");
break;
case kTrackTypeSubtitle:
input_name = tr("Subtitle Tracks");
break;
case kTrackTypeNone:
case kTrackTypeCount:
break;
}
if (!input_name.isEmpty())
track_inputs_.at(i)->set_name(input_name);
}
}
NodeInput *TimelineOutput::track_input(TrackType type) const
{
return track_inputs_.at(type);
}
TrackList *TimelineOutput::track_list(TrackType type) const
{
return track_lists_.at(type);
}
void TimelineOutput::TrackListAddedBlock(Block *block, int index)
{
TrackType type = static_cast<TrackList*>(sender())->TrackType();
emit BlockAdded(block, TrackReference(type, index));
}
void TimelineOutput::TrackListAddedTrack(TrackOutput *track)
{
TrackType type = static_cast<TrackList*>(sender())->TrackType();
emit TrackAdded(track, type);
}
void TimelineOutput::TrackHeightChangedSlot(int index, int height)
{
emit TrackHeightChanged(static_cast<TrackList*>(sender())->type(), index, height);
}
-102
View File
@@ -1,102 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef TIMELINEOUTPUT_H
#define TIMELINEOUTPUT_H
#include "common/timelinecommon.h"
#include "node/block/block.h"
#include "node/output/track/track.h"
#include "timeline/trackreference.h"
#include "timeline/tracktypes.h"
#include "tracklist.h"
/**
* @brief Node that represents the end of the Timeline as well as a time traversal Node
*/
class TimelineOutput : public Node
{
Q_OBJECT
public:
TimelineOutput();
virtual Node* copy() const override;
virtual QString Name() const override;
virtual QString id() const override;
virtual QString Category() const override;
virtual QString Description() const override;
const rational& length() const;
const QVector<TrackOutput *> &Tracks() const;
NodeInput* track_input(TrackType type) const;
TrackList* track_list(TrackType type) const;
const rational& timeline_length() const;
const rational& timebase() const;
void SetTimebase(const rational &timebase);
virtual void Retranslate() override;
signals:
void LengthChanged(const rational& length);
void TimebaseChanged(const rational &timebase);
void BlockAdded(Block* block, TrackReference track);
void BlockRemoved(Block* block);
void TrackAdded(TrackOutput* track, TrackType type);
void TrackRemoved(TrackOutput* track);
void TrackHeightChanged(TrackType type, int index, int height);
protected:
virtual NodeValueTable Value(const NodeValueDatabase& value) const override;
private:
QVector<NodeInput*> track_inputs_;
QVector<TrackList*> track_lists_;
QVector<TrackOutput*> track_cache_;
rational length_;
rational timebase_;
private slots:
void UpdateTrackCache();
void UpdateLength(const rational &length);
void TrackListAddedBlock(Block* block, int index);
void TrackListAddedTrack(TrackOutput* track);
void TrackHeightChangedSlot(int index, int height);
};
#endif // TIMELINEOUTPUT_H
+2
View File
@@ -18,5 +18,7 @@ set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/output/track/track.h
node/output/track/track.cpp
node/output/track/tracklist.h
node/output/track/tracklist.cpp
PARENT_SCOPE
)
@@ -21,9 +21,9 @@
#include "tracklist.h"
#include "node/factory.h"
#include "timeline.h"
#include "node/output/viewer/viewer.h"
TrackList::TrackList(TimelineOutput* parent, const enum TrackType &type, NodeInputArray *track_input) :
TrackList::TrackList(ViewerOutput *parent, const enum TrackType &type, NodeInputArray *track_input) :
QObject(parent),
track_input_(track_input),
type_(type)
@@ -27,12 +27,12 @@
#include "node/output/track/track.h"
#include "timeline/tracktypes.h"
class TimelineOutput;
class ViewerOutput;
class TrackList : public QObject {
Q_OBJECT
public:
TrackList(TimelineOutput *parent, const enum TrackType& type, NodeInputArray* track_input);
TrackList(ViewerOutput *parent, const enum TrackType& type, NodeInputArray* track_input);
const enum TrackType& type() const;
+125 -1
View File
@@ -31,6 +31,27 @@ ViewerOutput::ViewerOutput()
length_input_ = new NodeInput("length_in", NodeInput::kRational);
AddInput(length_input_);
// Create TrackList instances
track_inputs_.resize(kTrackTypeCount);
track_lists_.resize(kTrackTypeCount);
for (int i=0;i<kTrackTypeCount;i++) {
// Create track input
NodeInputArray* track_input = new NodeInputArray(QStringLiteral("track_in_%1").arg(i), NodeParam::kAny);
AddInput(track_input);
track_inputs_.replace(i, track_input);
TrackList* list = new TrackList(this, static_cast<TrackType>(i), track_input);
track_lists_.replace(i, list);
connect(list, SIGNAL(TrackListChanged()), this, SLOT(UpdateTrackCache()));
connect(list, SIGNAL(LengthChanged(const rational &)), this, SLOT(UpdateLength(const rational &)));
connect(list, SIGNAL(BlockAdded(Block*, int)), this, SLOT(TrackListAddedBlock(Block*, int)));
connect(list, SIGNAL(BlockRemoved(Block*)), this, SIGNAL(BlockRemoved(Block*)));
connect(list, SIGNAL(TrackAdded(TrackOutput*)), this, SLOT(TrackListAddedTrack(TrackOutput*)));
connect(list, SIGNAL(TrackRemoved(TrackOutput*)), this, SIGNAL(TrackRemoved(TrackOutput*)));
connect(list, SIGNAL(TrackHeightChanged(int, int)), this, SLOT(TrackHeightChangedSlot(int, int)));
}
// Create UUID for this node
uuid_ = QUuid::createUuid();
}
@@ -115,10 +136,14 @@ void ViewerOutput::set_audio_params(const AudioParams &audio)
rational ViewerOutput::Length()
{
// FIXME: This is pretty messy, there's probably a better way...
if (!length_input_->IsConnected()) {
return timeline_length_;
}
Node* connected_node = length_input_->get_connected_node();
if (connected_node) {
// This is kind of messy?
return connected_node->Value(NodeValueDatabase()).Get(NodeParam::kNumber, "length").value<rational>();
}
@@ -140,3 +165,102 @@ void ViewerOutput::DependentEdgeChanged(NodeInput *from)
Node::DependentEdgeChanged(from);
}
void ViewerOutput::UpdateTrackCache()
{
track_cache_.clear();
foreach (TrackList* list, track_lists_) {
QVector<TrackOutput*> track_list = list->Tracks();
foreach (TrackOutput* track, track_list) {
if (track) {
track_cache_.append(list->Tracks());
}
}
}
}
void ViewerOutput::UpdateLength(const rational &length)
{
// If this length is equal, no-op
if (length == timeline_length_) {
return;
}
// If this length is greater, this must be the new total length
if (length > timeline_length_) {
timeline_length_ = length;
emit LengthChanged(timeline_length_);
return;
}
// Otherwise, the new length is shorter and we'll have to manually determine what the new max length is
rational new_length = 0;
foreach (TrackList* list, track_lists_) {
new_length = qMax(new_length, list->TrackLength());
}
if (new_length != timeline_length_) {
timeline_length_ = new_length;
emit LengthChanged(timeline_length_);
}
}
void ViewerOutput::Retranslate()
{
for (int i=0;i<track_inputs_.size();i++) {
QString input_name;
switch (static_cast<TrackType>(i)) {
case kTrackTypeVideo:
input_name = tr("Video Tracks");
break;
case kTrackTypeAudio:
input_name = tr("Audio Tracks");
break;
case kTrackTypeSubtitle:
input_name = tr("Subtitle Tracks");
break;
case kTrackTypeNone:
case kTrackTypeCount:
break;
}
if (!input_name.isEmpty())
track_inputs_.at(i)->set_name(input_name);
}
}
const QVector<TrackOutput *>& ViewerOutput::Tracks() const
{
return track_cache_;
}
NodeInput *ViewerOutput::track_input(TrackType type) const
{
return track_inputs_.at(type);
}
TrackList *ViewerOutput::track_list(TrackType type) const
{
return track_lists_.at(type);
}
void ViewerOutput::TrackListAddedBlock(Block *block, int index)
{
TrackType type = static_cast<TrackList*>(sender())->TrackType();
emit BlockAdded(block, TrackReference(type, index));
}
void ViewerOutput::TrackListAddedTrack(TrackOutput *track)
{
TrackType type = static_cast<TrackList*>(sender())->TrackType();
emit TrackAdded(track, type);
}
void ViewerOutput::TrackHeightChangedSlot(int index, int height)
{
emit TrackHeightChanged(static_cast<TrackList*>(sender())->type(), index, height);
}
+41
View File
@@ -23,9 +23,15 @@
#include <QUuid>
#include "common/timelinecommon.h"
#include "node/block/block.h"
#include "node/output/track/track.h"
#include "node/output/track/tracklist.h"
#include "node/node.h"
#include "render/videoparams.h"
#include "render/audioparams.h"
#include "timeline/trackreference.h"
#include "timeline/tracktypes.h"
/**
* @brief A bridge between a node system and a ViewerPanel
@@ -61,6 +67,14 @@ public:
const QUuid& uuid() const;
const QVector<TrackOutput *> &Tracks() const;
NodeInput* track_input(TrackType type) const;
TrackList* track_list(TrackType type) const;
virtual void Retranslate() override;
protected:
virtual void DependentEdgeChanged(NodeInput* from) override;
@@ -79,6 +93,14 @@ signals:
void SizeChanged(int width, int height);
void BlockAdded(Block* block, TrackReference track);
void BlockRemoved(Block* block);
void TrackAdded(TrackOutput* track, TrackType type);
void TrackRemoved(TrackOutput* track);
void TrackHeightChanged(TrackType type, int index, int height);
private:
QUuid uuid_;
@@ -92,6 +114,25 @@ private:
AudioParams audio_params_;
QVector<NodeInput*> track_inputs_;
QVector<TrackList*> track_lists_;
QVector<TrackOutput*> track_cache_;
rational timeline_length_;
private slots:
void UpdateTrackCache();
void UpdateLength(const rational &length);
void TrackListAddedBlock(Block* block, int index);
void TrackListAddedTrack(TrackOutput* track);
void TrackHeightChangedSlot(int index, int height);
};
#endif // VIEWER_H
+1 -1
View File
@@ -49,7 +49,7 @@ void TimelinePanel::SetTime(const int64_t &timestamp)
timeline_widget_->SetTime(timestamp);
}
void TimelinePanel::ConnectTimelineNode(TimelineOutput *node)
void TimelinePanel::ConnectTimelineNode(ViewerOutput *node)
{
timeline_widget_->ConnectTimelineNode(node);
}
+1 -1
View File
@@ -36,7 +36,7 @@ public:
void Clear();
void ConnectTimelineNode(TimelineOutput* node);
void ConnectTimelineNode(ViewerOutput* node);
void DisconnectTimelineNode();
+5 -16
View File
@@ -34,7 +34,6 @@
#include "ui/icons/icons.h"
Sequence::Sequence() :
timeline_output_(nullptr),
viewer_output_(nullptr)
{
}
@@ -48,26 +47,19 @@ void Sequence::Open(Sequence* sequence)
NodePanel* node_panel = PanelManager::instance()->MostRecentlyFocused<NodePanel>();
viewer_panel->ConnectViewerNode(sequence->viewer_output_);
timeline_panel->ConnectTimelineNode(sequence->timeline_output_);
timeline_panel->ConnectTimelineNode(sequence->viewer_output_);
node_panel->SetGraph(sequence);
}
void Sequence::add_default_nodes()
{
timeline_output_ = new TimelineOutput();
timeline_output_->SetCanBeDeleted(false);
AddNode(timeline_output_);
viewer_output_ = new ViewerOutput();
viewer_output_->SetCanBeDeleted(false);
AddNode(viewer_output_);
// Connect timeline length to viewer
NodeParam::ConnectEdge(timeline_output_->output(), viewer_output_->length_input());
// Create tracks and connect them to the viewer
Node* video_track_output = timeline_output_->track_list(TrackType::kTrackTypeVideo)->AddTrack();
Node* audio_track_output = timeline_output_->track_list(TrackType::kTrackTypeAudio)->AddTrack();
Node* video_track_output = viewer_output_->track_list(TrackType::kTrackTypeVideo)->AddTrack();
Node* audio_track_output = viewer_output_->track_list(TrackType::kTrackTypeAudio)->AddTrack();
NodeParam::ConnectEdge(video_track_output->output(), viewer_output_->texture_input());
NodeParam::ConnectEdge(audio_track_output->output(), viewer_output_->samples_input());
//timeline_output_->track_list(TrackType::kTrackTypeVideo)->AddTrack();
@@ -89,11 +81,11 @@ QIcon Sequence::icon()
QString Sequence::duration()
{
if (timeline_output_ == nullptr) {
if (!viewer_output_) {
return QString();
}
rational timeline_length = timeline_output_->length();
rational timeline_length = viewer_output_->Length();
int64_t timestamp = Timecode::time_to_timestamp(timeline_length, video_params_.time_base());
@@ -116,9 +108,6 @@ void Sequence::set_video_params(const VideoParams &vparam)
if (viewer_output_ != nullptr)
viewer_output_->set_video_params(video_params_);
if (timeline_output_ != nullptr)
timeline_output_->SetTimebase(video_params_.time_base());
}
const AudioParams &Sequence::audio_params()
-2
View File
@@ -23,7 +23,6 @@
#include "common/rational.h"
#include "node/graph.h"
#include "node/output/timeline/timeline.h"
#include "node/output/viewer/viewer.h"
#include "render/videoparams.h"
#include "project/item/item.h"
@@ -62,7 +61,6 @@ public:
void set_default_parameters();
private:
TimelineOutput* timeline_output_;
ViewerOutput* viewer_output_;
VideoParams video_params_;
+3 -3
View File
@@ -181,7 +181,7 @@ void TimelineWidget::SetTime(int64_t timestamp)
UpdateInternalTime(timestamp);
}
void TimelineWidget::ConnectTimelineNode(TimelineOutput *node)
void TimelineWidget::ConnectTimelineNode(ViewerOutput *node)
{
if (timeline_node_ != nullptr) {
disconnect(timeline_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(UpdateTimelineLength(const rational&)));
@@ -213,7 +213,7 @@ void TimelineWidget::ConnectTimelineNode(TimelineOutput *node)
connect(timeline_node_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&)));
connect(timeline_node_, SIGNAL(TrackHeightChanged(TrackType, int, int)), this, SLOT(TrackHeightChanged(TrackType, int, int)));
SetTimebase(timeline_node_->timebase());
SetTimebase(timeline_node_->video_params().time_base());
for (int i=0;i<views_.size();i++) {
TrackType track_type = static_cast<TrackType>(i);
@@ -223,7 +223,7 @@ void TimelineWidget::ConnectTimelineNode(TimelineOutput *node)
track_view->ConnectTrackList(track_list);
view->ConnectTrackList(track_list);
view->SetEndTime(timeline_node_->timeline_length());
view->SetEndTime(timeline_node_->Length());
// Defer to the track to make all the block UI items necessary
foreach (TrackOutput* track, timeline_node_->track_list(track_type)->Tracks()) {
+3 -2
View File
@@ -7,6 +7,7 @@
#include "core.h"
#include "timelineandtrackview.h"
#include "node/output/viewer/viewer.h"
#include "widget/slider/timeslider.h"
#include "widget/timelinewidget/timelinescaledobject.h"
#include "widget/timeruler/timeruler.h"
@@ -28,7 +29,7 @@ public:
void SetTime(int64_t timestamp);
void ConnectTimelineNode(TimelineOutput* node);
void ConnectTimelineNode(ViewerOutput *node);
void DisconnectTimelineNode();
@@ -368,7 +369,7 @@ private:
TimeRuler* ruler_;
TimelineOutput* timeline_node_;
ViewerOutput* timeline_node_;
int64_t playhead_;
@@ -4,7 +4,7 @@
#include <QScrollArea>
#include <QSplitter>
#include "node/output/timeline/tracklist.h"
#include "node/output/track/tracklist.h"
#include "trackviewitem.h"
#include "trackviewsplitter.h"
+1 -1
View File
@@ -25,8 +25,8 @@
#include "node/block/block.h"
#include "node/block/gap/gap.h"
#include "node/output/timeline/timeline.h"
#include "node/output/track/track.h"
#include "node/output/track/tracklist.h"
class BlockResizeCommand : public QUndoCommand {
public:
@@ -28,7 +28,6 @@
#include <QDropEvent>
#include "node/block/clip/clip.h"
#include "node/output/timeline/timeline.h"
#include "timelineviewbase.h"
#include "timelineviewblockitem.h"
#include "timelineviewmouseevent.h"
+5
View File
@@ -339,6 +339,11 @@ void TimeRuler::DrawPlayhead(QPainter *p, int x, int y)
p->drawPolygon(points, 6);
}
int TimeRuler::CacheStatusHeight() const
{
return fontMetrics().height() / 4;
}
double TimeRuler::ScreenToUnitFloat(int screen)
{
return (screen + scroll_) / scale_ / timebase_dbl_;
+2
View File
@@ -71,6 +71,8 @@ private:
void DrawPlayhead(QPainter* p, int x, int y);
int CacheStatusHeight() const;
double ScreenToUnitFloat(int screen);
int64_t ScreenToUnit(int screen);