From 0ea98be443cfb46a4ad2a5aa7069478541661164 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 14 Jan 2020 00:10:21 +1100 Subject: [PATCH] ensure objects are in the correct thread when loading Since we load in a separate thread, when the QObject based objects are instantiated, they're created with affinity to that separate thread. Now we specifically ensure they are moved to the main thread after their creation. --- app/node/graph.cpp | 8 +- app/node/input.cpp | 33 ++++-- app/node/input.h | 6 +- app/node/inputarray.cpp | 12 +- app/node/inputarray.h | 2 +- app/node/node.cpp | 27 +++-- app/node/node.h | 4 +- app/node/output.cpp | 12 +- app/node/output.h | 2 +- app/node/output/track/track.cpp | 6 +- app/node/output/track/tracklist.cpp | 22 ++-- app/node/param.cpp | 20 ---- app/node/param.h | 9 +- app/project/item/folder/folder.cpp | 10 +- app/project/item/footage/footage.cpp | 2 +- app/project/item/sequence/sequence.cpp | 157 +++++++++++++++++-------- app/project/item/sequence/sequence.h | 7 +- app/project/project.cpp | 23 +++- app/project/projectloadmanager.cpp | 3 + 19 files changed, 231 insertions(+), 134 deletions(-) diff --git a/app/node/graph.cpp b/app/node/graph.cpp index 4e467671f..84b8c8308 100644 --- a/app/node/graph.cpp +++ b/app/node/graph.cpp @@ -41,8 +41,8 @@ void NodeGraph::AddNode(Node *node) node->setParent(this); - connect(node, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SIGNAL(EdgeAdded(NodeEdgePtr))); - connect(node, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SIGNAL(EdgeRemoved(NodeEdgePtr))); + connect(node, &Node::EdgeAdded, this, &NodeGraph::EdgeAdded); + connect(node, &Node::EdgeRemoved, this, &NodeGraph::EdgeRemoved); node_children_.append(node); @@ -62,8 +62,8 @@ void NodeGraph::TakeNode(Node *node, QObject* new_parent) node->DisconnectAll(); - disconnect(node, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SIGNAL(EdgeAdded(NodeEdgePtr))); - disconnect(node, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SIGNAL(EdgeRemoved(NodeEdgePtr))); + disconnect(node, &Node::EdgeAdded, this, &NodeGraph::EdgeAdded); + disconnect(node, &Node::EdgeRemoved, this, &NodeGraph::EdgeRemoved); node->setParent(new_parent); diff --git a/app/node/input.cpp b/app/node/input.cpp index 58ffa56c9..6131a13d5 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -85,7 +85,7 @@ QString NodeInput::name() return NodeParam::name(); } -void NodeInput::Load(QXmlStreamReader *reader) +void NodeInput::Load(QXmlStreamReader *reader, QHash& param_ptrs, QList &input_connections) { XMLAttributeLoop(reader, attr) { if (attr.name() == "keyframing") { @@ -100,7 +100,7 @@ void NodeInput::Load(QXmlStreamReader *reader) int val_index = 0; XMLReadLoop(reader, "standard") { - if (reader->name() == "value") { + if (reader->isStartElement() && reader->name() == "value") { reader->readNext(); QString value_text = reader->text().toString(); @@ -118,7 +118,7 @@ void NodeInput::Load(QXmlStreamReader *reader) int track = 0; XMLReadLoop(reader, "keyframes") { - if (reader->name() == "track") { + if (reader->isStartElement() && reader->name() == "track") { XMLReadLoop(reader, "track") { if (reader->name() == "key") { rational key_time; @@ -157,8 +157,16 @@ void NodeInput::Load(QXmlStreamReader *reader) track++; } } - } else { + } else if (reader->name() == "connections") { + XMLReadLoop(reader, "connections") { + if (reader->isStartElement() && reader->name() == "connection") { + reader->readNext(); + input_connections.append({this, reader->text().toULongLong()}); + } + } + } else { + LoadInternal(reader, param_ptrs, input_connections); } } } @@ -170,8 +178,6 @@ void NodeInput::Save(QXmlStreamWriter *writer) const writer->writeAttribute("id", id()); - writer->writeAttribute("ptr", QString::number(reinterpret_cast(this))); - writer->writeAttribute("keyframing", QString::number(keyframing_)); // Write standard value @@ -216,12 +222,25 @@ void NodeInput::Save(QXmlStreamWriter *writer) const writer->writeEndElement(); // input } +void NodeInput::SaveConnections(QXmlStreamWriter *writer) const +{ + writer->writeStartElement("connections"); + + foreach (NodeEdgePtr edge, edges_) { + writer->writeTextElement("connection", + QString::number(reinterpret_cast(edge->output()))); + } + + writer->writeEndElement(); // connections +} + + const NodeParam::DataType &NodeInput::data_type() const { return data_type_; } -void NodeInput::LoadInternal(QXmlStreamReader *reader) +void NodeInput::LoadInternal(QXmlStreamReader *reader, QHash ¶m_ptrs, QList &input_connections) { } diff --git a/app/node/input.h b/app/node/input.h index b320cf2ce..bd52593b1 100644 --- a/app/node/input.h +++ b/app/node/input.h @@ -54,7 +54,7 @@ public: virtual QString name() override; - virtual void Load(QXmlStreamReader* reader) override; + virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections) override; virtual void Save(QXmlStreamWriter* writer) const override; @@ -243,11 +243,13 @@ signals: void KeyframeRemoved(NodeKeyframePtr key); protected: - virtual void LoadInternal(QXmlStreamReader* reader); + virtual void LoadInternal(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections); virtual void SaveInternal(QXmlStreamWriter* writer) const; private: + void SaveConnections(QXmlStreamWriter* writer) const; + /** * @brief Returns whether a data type can be interpolated or not */ diff --git a/app/node/inputarray.cpp b/app/node/inputarray.cpp index ba32c8727..4d9a5272c 100644 --- a/app/node/inputarray.cpp +++ b/app/node/inputarray.cpp @@ -1,5 +1,7 @@ #include "inputarray.h" +#include + #include "common/xmlreadloop.h" #include "node.h" @@ -57,9 +59,9 @@ void NodeInputArray::SetSize(int size, bool lock) new_param->setParent(this); sub_params_.replace(i, new_param); - connect(new_param, SIGNAL(ValueChanged(rational, rational)), this, SIGNAL(ValueChanged(rational, rational))); - connect(new_param, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SIGNAL(EdgeAdded(NodeEdgePtr))); - connect(new_param, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SIGNAL(EdgeRemoved(NodeEdgePtr))); + connect(new_param, &NodeInput::ValueChanged, this, &NodeInput::ValueChanged); + connect(new_param, &NodeInput::EdgeAdded, this, &NodeInput::EdgeAdded); + connect(new_param, &NodeInput::EdgeRemoved, this, &NodeInput::EdgeRemoved); } } @@ -168,13 +170,13 @@ void NodeInputArray::RemoveAt(int index) RemoveLast(); } -void NodeInputArray::LoadInternal(QXmlStreamReader *reader) +void NodeInputArray::LoadInternal(QXmlStreamReader *reader, QHash& param_ptrs, QList &input_connections) { if (reader->name() == "subparameters") { XMLReadLoop(reader, "subparameters") { if (reader->name() == "input") { Append(); - At(GetSize() - 1)->Load(reader); + At(GetSize() - 1)->Load(reader, param_ptrs, input_connections); } } } diff --git a/app/node/inputarray.h b/app/node/inputarray.h index b6aaf4550..5ebb04fdb 100644 --- a/app/node/inputarray.h +++ b/app/node/inputarray.h @@ -33,7 +33,7 @@ signals: void SizeChanged(int size); protected: - virtual void LoadInternal(QXmlStreamReader* reader) override; + virtual void LoadInternal(QXmlStreamReader* reader, QHash ¶m_ptrs, QList &input_connections) override; virtual void SaveInternal(QXmlStreamWriter* writer) const override; diff --git a/app/node/node.cpp b/app/node/node.cpp index 1ed039ffc..1f4f05910 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -20,6 +20,7 @@ #include "node.h" +#include #include #include @@ -49,9 +50,9 @@ Node::~Node() } } -void Node::Load(QXmlStreamReader *reader) +void Node::Load(QXmlStreamReader *reader, QHash &output_ptrs, QList& input_connections, const QString& element) { - XMLReadLoop(reader, "node") { + XMLReadLoop(reader, (element.isEmpty() ? "node" : element)) { if (reader->isStartElement()) { if (reader->name() == "input" || reader->name() == "output") { QString param_id; @@ -76,15 +77,15 @@ void Node::Load(QXmlStreamReader *reader) continue; } - param->Load(reader); + param->Load(reader, output_ptrs, input_connections); } } } } -void Node::Save(QXmlStreamWriter *writer) const +void Node::Save(QXmlStreamWriter *writer, const QString &custom_name) const { - writer->writeStartElement("node"); + writer->writeStartElement(custom_name.isEmpty() ? "node" : custom_name); writer->writeAttribute("id", id()); @@ -129,8 +130,8 @@ void Node::AddParameter(NodeParam *param) params_.insert(params_.size()-1, param); } - connect(param, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SIGNAL(EdgeAdded(NodeEdgePtr))); - connect(param, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SIGNAL(EdgeRemoved(NodeEdgePtr))); + connect(param, &NodeParam::EdgeAdded, this, &Node::EdgeAdded); + connect(param, &NodeParam::EdgeRemoved, this, &Node::EdgeRemoved); if (param->type() == NodeParam::kInput) { ConnectInput(static_cast(param)); @@ -566,16 +567,16 @@ bool Node::HasParamOfType(NodeParam::Type type, bool must_be_connected) const void Node::ConnectInput(NodeInput *input) { - connect(input, SIGNAL(ValueChanged(rational, rational)), this, SLOT(InputChanged(rational, rational))); - connect(input, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(InputConnectionChanged(NodeEdgePtr))); - connect(input, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(InputConnectionChanged(NodeEdgePtr))); + connect(input, &NodeInput::ValueChanged, this, &Node::InputChanged); + connect(input, &NodeInput::EdgeAdded, this, &Node::InputConnectionChanged); + connect(input, &NodeInput::EdgeRemoved, this, &Node::InputConnectionChanged); } void Node::DisconnectInput(NodeInput *input) { - disconnect(input, SIGNAL(ValueChanged(rational, rational)), this, SLOT(InputChanged(rational, rational))); - disconnect(input, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(InputConnectionChanged(NodeEdgePtr))); - disconnect(input, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(InputConnectionChanged(NodeEdgePtr))); + disconnect(input, &NodeInput::ValueChanged, this, &Node::InputChanged); + disconnect(input, &NodeInput::EdgeAdded, this, &Node::InputConnectionChanged); + disconnect(input, &NodeInput::EdgeRemoved, this, &Node::InputConnectionChanged); } void Node::InputChanged(rational start, rational end) diff --git a/app/node/node.h b/app/node/node.h index 0b5cb317c..83378708d 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -68,12 +68,12 @@ public: /** * @brief Clear current node variables and replace them with */ - void Load(QXmlStreamReader* reader); + void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections, const QString &element = QString()); /** * @brief Save this node into a text/XML format */ - void Save(QXmlStreamWriter* writer) const; + void Save(QXmlStreamWriter* writer, const QString& custom_name = QString()) const; /** * @brief Return the name of the node diff --git a/app/node/output.cpp b/app/node/output.cpp index a04226437..319860753 100644 --- a/app/node/output.cpp +++ b/app/node/output.cpp @@ -20,6 +20,7 @@ #include "output.h" +#include "common/xmlreadloop.h" #include "node/node.h" NodeOutput::NodeOutput(const QString &id) : @@ -41,8 +42,15 @@ QString NodeOutput::name() return NodeParam::name(); } -void NodeOutput::Load(QXmlStreamReader *reader) +void NodeOutput::Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections) { + XMLAttributeLoop(reader, attr) { + if (attr.name() == "ptr") { + quintptr saved_ptr = attr.value().toULongLong(); + + param_ptrs.insert(saved_ptr, this); + } + } } void NodeOutput::Save(QXmlStreamWriter *writer) const @@ -53,7 +61,5 @@ void NodeOutput::Save(QXmlStreamWriter *writer) const writer->writeAttribute("ptr", QString::number(reinterpret_cast(this))); - SaveConnections(writer); - writer->writeEndElement(); // output } diff --git a/app/node/output.h b/app/node/output.h index 479ed3f96..733b3b73b 100644 --- a/app/node/output.h +++ b/app/node/output.h @@ -42,7 +42,7 @@ public: virtual QString name() override; - virtual void Load(QXmlStreamReader *reader) override; + virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections) override; virtual void Save(QXmlStreamWriter* writer) const override; diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index e1ec0933b..f85d6d1b2 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -36,9 +36,9 @@ TrackOutput::TrackOutput() : block_input_ = new NodeInputArray("block_in", NodeParam::kAny); block_input_->set_is_keyframable(false); AddInput(block_input_); - connect(block_input_, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(BlockConnected(NodeEdgePtr))); - connect(block_input_, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(BlockDisconnected(NodeEdgePtr))); - connect(block_input_, SIGNAL(SizeChanged(int)), this, SLOT(BlockListSizeChanged(int))); + connect(block_input_, &NodeInputArray::EdgeAdded, this, &TrackOutput::BlockConnected); + connect(block_input_, &NodeInputArray::EdgeRemoved, this, &TrackOutput::BlockDisconnected); + connect(block_input_, &NodeInputArray::SizeChanged, this, &TrackOutput::BlockListSizeChanged); muted_input_ = new NodeInput("muted_in", NodeParam::kBoolean); muted_input_->set_is_keyframable(false); diff --git a/app/node/output/track/tracklist.cpp b/app/node/output/track/tracklist.cpp index 512f894ab..8013391b3 100644 --- a/app/node/output/track/tracklist.cpp +++ b/app/node/output/track/tracklist.cpp @@ -28,9 +28,9 @@ TrackList::TrackList(ViewerOutput *parent, const Timeline::TrackType &type, Node track_input_(track_input), type_(type) { - connect(track_input, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(TrackConnected(NodeEdgePtr))); - connect(track_input, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(TrackDisconnected(NodeEdgePtr))); - connect(track_input, SIGNAL(SizeChanged(int)), this, SLOT(TrackListSizeChanged(int))); + connect(track_input, &NodeInputArray::EdgeAdded, this, &TrackList::TrackConnected); + connect(track_input, &NodeInputArray::EdgeRemoved, this, &TrackList::TrackDisconnected); + connect(track_input, &NodeInputArray::SizeChanged, this, &TrackList::TrackListSizeChanged); } const Timeline::TrackType &TrackList::type() const @@ -154,10 +154,10 @@ void TrackList::TrackConnected(NodeEdgePtr edge) track_cache_.replace(track_index, connected_track); - connect(connected_track, SIGNAL(BlockAdded(Block*)), this, SLOT(TrackAddedBlock(Block*))); - connect(connected_track, SIGNAL(BlockRemoved(Block*)), this, SLOT(TrackRemovedBlock(Block*))); - connect(connected_track, SIGNAL(TrackLengthChanged()), this, SLOT(UpdateTotalLength())); - connect(connected_track, SIGNAL(TrackHeightChanged(int)), this, SLOT(TrackHeightChangedSlot(int))); + connect(connected_track, &TrackOutput::BlockAdded, this, &TrackList::TrackAddedBlock); + connect(connected_track, &TrackOutput::BlockRemoved, this, &TrackList::TrackRemovedBlock); + connect(connected_track, &TrackOutput::TrackLengthChanged, this, &TrackList::UpdateTotalLength); + connect(connected_track, &TrackOutput::TrackHeightChanged, this, &TrackList::TrackHeightChangedSlot); connected_track->SetIndex(track_index); connected_track->set_track_type(type_); @@ -191,10 +191,10 @@ void TrackList::TrackDisconnected(NodeEdgePtr edge) track->SetIndex(-1); track->set_track_type(Timeline::kTrackTypeNone); - disconnect(track, SIGNAL(BlockAdded(Block*)), this, SLOT(TrackAddedBlock(Block*))); - disconnect(track, SIGNAL(BlockRemoved(Block*)), this, SLOT(TrackRemovedBlock(Block*))); - disconnect(track, SIGNAL(TrackLengthChanged()), this, SLOT(UpdateTotalLength())); - disconnect(track, SIGNAL(TrackHeightChanged(int)), this, SLOT(TrackHeightChangedSlot(int))); + disconnect(track, &TrackOutput::BlockAdded, this, &TrackList::TrackAddedBlock); + disconnect(track, &TrackOutput::BlockRemoved, this, &TrackList::TrackRemovedBlock); + disconnect(track, &TrackOutput::TrackLengthChanged, this, &TrackList::UpdateTotalLength); + disconnect(track, &TrackOutput::TrackHeightChanged, this, &TrackList::TrackHeightChangedSlot); emit TrackListChanged(); diff --git a/app/node/param.cpp b/app/node/param.cpp index d9a65fef0..d2cbd8b68 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -282,23 +282,3 @@ QByteArray NodeParam::ValueToBytesInternal(const QVariant &v) return bytes; } - -void NodeParam::SaveConnections(QXmlStreamWriter *writer) const -{ - writer->writeStartElement("connections"); - - foreach (NodeEdgePtr edge, edges_) { - NodeParam* other; - - if (edge->input() == this) { - other = edge->output(); - } else { - other = edge->input(); - } - - writer->writeTextElement("connection", - QString::number(reinterpret_cast(other))); - } - - writer->writeEndElement(); // connections -} diff --git a/app/node/param.h b/app/node/param.h index 22d2e42dc..e1419d102 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -230,10 +230,15 @@ public: virtual ~NodeParam() override; + struct SerializedConnection { + NodeInput* input; + quintptr output; + }; + /** * @brief Load function */ - virtual void Load(QXmlStreamReader* reader) = 0; + virtual void Load(QXmlStreamReader* reader, QHash& param_ptrs, QList &input_connections) = 0; /** * @brief Save function @@ -379,8 +384,6 @@ signals: void EdgeRemoved(NodeEdgePtr edge); protected: - void SaveConnections(QXmlStreamWriter* writer) const; - /** * @brief Internal list of edges */ diff --git a/app/project/item/folder/folder.cpp b/app/project/item/folder/folder.cpp index 2d4ee1eaf..956c34ca2 100644 --- a/app/project/item/folder/folder.cpp +++ b/app/project/item/folder/folder.cpp @@ -54,7 +54,7 @@ void Folder::Load(QXmlStreamReader *reader) XMLReadLoop(reader, "folder") { if (reader->isStartElement()) { - ItemPtr child = nullptr; + ItemPtr child; if (reader->name() == "folder") { child = std::make_shared(); @@ -62,12 +62,12 @@ void Folder::Load(QXmlStreamReader *reader) child = std::make_shared(); } else if (reader->name() == "sequence") { child = std::make_shared(); + } else { + continue; } - if (child) { - child->Load(reader); - add_child(child); - } + child->Load(reader); + add_child(child); } } } diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index fe36eeb25..27f98ea41 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -48,7 +48,7 @@ void Footage::Load(QXmlStreamReader *reader) } } - // FIXME: Probe here + // FIXME: Probe here? XMLReadLoop(reader, "footage") { if (reader->isStartElement()) { diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index f983c7d68..4d433f905 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -35,9 +35,11 @@ #include "panel/viewer/viewer.h" #include "ui/icons/icons.h" -Sequence::Sequence() : - viewer_output_(nullptr) +Sequence::Sequence() { + viewer_output_ = new ViewerOutput(); + viewer_output_->SetCanBeDeleted(false); + AddNode(viewer_output_); } void Sequence::Load(QXmlStreamReader *reader) @@ -45,41 +47,101 @@ void Sequence::Load(QXmlStreamReader *reader) XMLAttributeLoop(reader, attr) { if (attr.name() == "name") { set_name(attr.value().toString()); + + // Currently the only thing we care about } } + QHash output_ptrs; + QList desired_connections; + XMLReadLoop(reader, "sequence") { if (reader->isStartElement()) { - if (reader->name() == "node") { - QString node_id; + if (reader->name() == "video") { + int video_width, video_height; + rational video_timebase; - XMLAttributeLoop(reader, attr) { - if (attr.name() == "id") { - node_id = attr.value().toString(); - - // Currently the only thing we need - break; + XMLReadLoop(reader, "video") { + if (reader->isStartElement()) { + if (reader->name() == "width") { + reader->readNext(); + video_width = reader->text().toInt(); + } else if (reader->name() == "height") { + reader->readNext(); + video_height = reader->text().toInt(); + } else if (reader->name() == "timebase") { + reader->readNext(); + video_timebase = rational::fromString(reader->text().toString()); + } } } - if (node_id.isEmpty()) { - qDebug() << "Found node with no ID"; - continue; + set_video_params(VideoParams(video_width, video_height, video_timebase)); + } else if (reader->name() == "audio") { + int rate; + uint64_t layout; + + XMLReadLoop(reader, "audio") { + if (reader->isStartElement()) { + if (reader->name() == "rate") { + reader->readNext(); + rate = reader->text().toInt(); + } else if (reader->name() == "layout") { + reader->readNext(); + layout = reader->text().toULongLong(); + } + } } - Node* node = NodeFactory::CreateFromID(node_id); + set_audio_params(AudioParams(rate, layout)); + } else if (reader->name() == "node" || reader->name() == "viewer") { + Node* node; - if (!node) { - qDebug() << "Failed to load" << node_id << "- no node with that ID is installed"; - continue; + if (reader->name() == "node") { + QString node_id; + + XMLAttributeLoop(reader, attr) { + if (attr.name() == "id") { + node_id = attr.value().toString(); + + // Currently the only thing we need + break; + } + } + + if (node_id.isEmpty()) { + qDebug() << "Found node with no ID"; + continue; + } + + node = NodeFactory::CreateFromID(node_id); + + if (!node) { + qDebug() << "Failed to load" << node_id << "- no node with that ID is installed"; + continue; + } + } else { + node = viewer_output_; } - node->Load(reader); + if (node) { + node->Load(reader, output_ptrs, desired_connections, reader->name().toString()); - AddNode(node); + AddNode(node); + } } } } + + // Make connections + foreach (const NodeParam::SerializedConnection& con, desired_connections) { + NodeParam::ConnectEdge(output_ptrs.value(con.output), + con.input); + } + + // Ensure this and all children are in the main thread + // (FIXME: Weird place for this? This should probably be in ProjectLoadManager somehow) + moveToThread(qApp->thread()); } void Sequence::Save(QXmlStreamWriter *writer) const @@ -88,10 +150,29 @@ void Sequence::Save(QXmlStreamWriter *writer) const writer->writeAttribute("name", name()); + writer->writeStartElement("video"); + + writer->writeTextElement("width", QString::number(video_params().width())); + writer->writeTextElement("height", QString::number(video_params().height())); + writer->writeTextElement("timebase", video_params().time_base().toString()); + + writer->writeEndElement(); // video + + writer->writeStartElement("audio"); + + writer->writeTextElement("rate", QString::number(audio_params().sample_rate())); + writer->writeTextElement("layout", QString::number(audio_params().channel_layout())); + + writer->writeEndElement(); // audio + foreach (Node* node, nodes()) { - node->Save(writer); + if (node != viewer_output_) { + node->Save(writer); + } } + viewer_output_->Save(writer, "viewer"); + writer->writeEndElement(); // sequence } @@ -110,19 +191,11 @@ void Sequence::Open(Sequence* sequence) void Sequence::add_default_nodes() { - viewer_output_ = new ViewerOutput(); - viewer_output_->SetCanBeDeleted(false); - AddNode(viewer_output_); - // Create tracks and connect them to the viewer Node* video_track_output = viewer_output_->track_list(Timeline::kTrackTypeVideo)->AddTrack(); Node* audio_track_output = viewer_output_->track_list(Timeline::kTrackTypeAudio)->AddTrack(); NodeParam::ConnectEdge(video_track_output->output(), viewer_output_->texture_input()); NodeParam::ConnectEdge(audio_track_output->output(), viewer_output_->samples_input()); - - // Update the timebase on these nodes - set_video_params(video_params_); - set_audio_params(audio_params_); } Item::Type Sequence::type() const @@ -137,46 +210,36 @@ QIcon Sequence::icon() QString Sequence::duration() { - if (!viewer_output_) { - return QString(); - } - rational timeline_length = viewer_output_->Length(); - int64_t timestamp = Timecode::time_to_timestamp(timeline_length, video_params_.time_base()); + int64_t timestamp = Timecode::time_to_timestamp(timeline_length, video_params().time_base()); - return Timecode::timestamp_to_timecode(timestamp, video_params_.time_base(), Timecode::CurrentDisplay()); + return Timecode::timestamp_to_timecode(timestamp, video_params().time_base(), Timecode::CurrentDisplay()); } QString Sequence::rate() { - return QCoreApplication::translate("Sequence", "%1 FPS").arg(video_params_.time_base().flipped().toDouble()); + return QCoreApplication::translate("Sequence", "%1 FPS").arg(video_params().time_base().flipped().toDouble()); } -const VideoParams &Sequence::video_params() +const VideoParams &Sequence::video_params() const { - return video_params_; + return viewer_output_->video_params(); } void Sequence::set_video_params(const VideoParams &vparam) { - video_params_ = vparam; - - if (viewer_output_ != nullptr) - viewer_output_->set_video_params(video_params_); + viewer_output_->set_video_params(vparam); } -const AudioParams &Sequence::audio_params() +const AudioParams &Sequence::audio_params() const { - return audio_params_; + return viewer_output_->audio_params(); } void Sequence::set_audio_params(const AudioParams ¶ms) { - audio_params_ = params; - - if (viewer_output_ != nullptr) - viewer_output_->set_audio_params(audio_params_); + viewer_output_->set_audio_params(params); } void Sequence::set_default_parameters() diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index 6d271b80a..51e062985 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -62,10 +62,10 @@ public: virtual QString duration() override; virtual QString rate() override; - const VideoParams& video_params(); + const VideoParams& video_params() const; void set_video_params(const VideoParams& vparam); - const AudioParams& audio_params(); + const AudioParams& audio_params() const; void set_audio_params(const AudioParams& params); void set_default_parameters(); @@ -73,9 +73,6 @@ public: private: ViewerOutput* viewer_output_; - VideoParams video_params_; - - AudioParams audio_params_; }; #endif // SEQUENCE_H diff --git a/app/project/project.cpp b/app/project/project.cpp index fe737490b..24caec1e0 100644 --- a/app/project/project.cpp +++ b/app/project/project.cpp @@ -34,8 +34,23 @@ void Project::Load(QXmlStreamReader *reader) XMLReadLoop(reader, "project") { if (reader->isStartElement()) { if (reader->name() == "folder") { + // Assume this folder is our root root_.Load(reader); + + } else if (reader->name() == "colormanagement") { + + // Read color management info + XMLReadLoop(reader, "colormanagement") { + if (reader->name() == "config") { + reader->readNext(); + set_ocio_config(reader->text().toString()); + } else if (reader->name() == "default") { + reader->readNext(); + set_default_input_colorspace(reader->text().toString()); + } + } + } } } @@ -49,7 +64,13 @@ void Project::Save(QXmlStreamWriter *writer) const root_.Save(writer); - writer->writeTextElement("ocio", ocio_config_); + writer->writeStartElement("colormanagement"); + + writer->writeTextElement("config", ocio_config_); + + writer->writeTextElement("default", default_input_colorspace_); + + writer->writeEndElement(); // colormanagement writer->writeEndElement(); // project } diff --git a/app/project/projectloadmanager.cpp b/app/project/projectloadmanager.cpp index 0d138629c..ebb54f6df 100644 --- a/app/project/projectloadmanager.cpp +++ b/app/project/projectloadmanager.cpp @@ -30,6 +30,9 @@ void ProjectLoadManager::Start() project->Load(&reader); + // Ensure project is in main thread + moveToThread(qApp->thread()); + emit ProjectLoaded(project); } }