implemented footage loading from projects

Footage is a special case where the node parameters can reference objects that
exist outside of the graph. Therefore specific code is needed to
serialize/deserialize.
This commit is contained in:
itsmattkc
2020-01-15 18:26:42 +11:00
parent 75a9291cd2
commit 6771a2f1cb
25 changed files with 142 additions and 79 deletions
+26 -19
View File
@@ -30,6 +30,7 @@
#include "node.h"
#include "output.h"
#include "inputarray.h"
#include "project/item/footage/stream.h"
NodeInput::NodeInput(const QString& id, const DataType &type, const QVariant &default_value) :
NodeParam(id),
@@ -85,7 +86,7 @@ QString NodeInput::name()
return NodeParam::name();
}
void NodeInput::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections)
void NodeInput::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections)
{
XMLAttributeLoop(reader, attr) {
if (attr.name() == "keyframing") {
@@ -108,7 +109,7 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput*>& par
if (value_text.isEmpty()) {
standard_value_.replace(val_index, QVariant());
} else {
standard_value_.replace(val_index, StringToValue(data_type_, value_text));
standard_value_.replace(val_index, StringToValue(value_text, footage_connections));
}
val_index++;
@@ -145,7 +146,7 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput*>& par
reader->readNext();
key_value = StringToValue(data_type_, reader->text().toString());
key_value = StringToValue(reader->text().toString(), footage_connections);
NodeKeyframePtr key = NodeKeyframe::Create(key_time, key_value, key_type, track);
key->set_bezier_control_in(key_in_handle);
@@ -166,7 +167,7 @@ void NodeInput::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput*>& par
}
}
} else {
LoadInternal(reader, param_ptrs, input_connections);
LoadInternal(reader, param_ptrs, input_connections, footage_connections);
}
}
}
@@ -184,7 +185,7 @@ void NodeInput::Save(QXmlStreamWriter *writer) const
writer->writeStartElement("standard");
foreach (const QVariant& v, standard_value_) {
writer->writeTextElement("value", ValueToString(data_type_, v));
writer->writeTextElement("value", ValueToString(v));
}
writer->writeEndElement(); // standard
@@ -205,7 +206,7 @@ void NodeInput::Save(QXmlStreamWriter *writer) const
writer->writeAttribute("outhandlex", QString::number(key->bezier_control_out().x()));
writer->writeAttribute("outhandley", QString::number(key->bezier_control_out().y()));
writer->writeCharacters(ValueToString(data_type_, key->value()));
writer->writeCharacters(ValueToString(key->value()));
writer->writeEndElement(); // key
}
@@ -240,7 +241,7 @@ const NodeParam::DataType &NodeInput::data_type() const
return data_type_;
}
void NodeInput::LoadInternal(QXmlStreamReader *reader, QHash<quintptr, NodeOutput *> &param_ptrs, QList<SerializedConnection> &input_connections)
void NodeInput::LoadInternal(QXmlStreamReader *reader, QHash<quintptr, NodeOutput *> &param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections)
{
}
@@ -248,27 +249,33 @@ void NodeInput::SaveInternal(QXmlStreamWriter *writer) const
{
}
QString NodeInput::ValueToString(const NodeParam::DataType &type, const QVariant &value)
QString NodeInput::ValueToString(const QVariant &value) const
{
if (type == kRational) {
switch (data_type_) {
case kRational:
return value.value<rational>().toString();
}
case kFootage:
return QString::number(reinterpret_cast<quintptr>(value.value<StreamPtr>().get()));
default:
if (value.canConvert<QString>()) {
return value.toString();
}
if (value.canConvert<QString>()) {
return value.toString();
qWarning() << "Failed to convert type" << data_type_ << "to string";
return QString();
}
qWarning() << "Failed to convert type" << type << "to string";
return QString();
}
QVariant NodeInput::StringToValue(const NodeParam::DataType &type, const QString &string)
QVariant NodeInput::StringToValue(const QString &string, QList<NodeInput::FootageConnection>& footage_connections)
{
if (type == kRational) {
switch (data_type_) {
case kRational:
return QVariant::fromValue(rational::fromString(string));
case kFootage:
footage_connections.append({this, string.toULongLong()});
default:
return string;
}
return string;
}
NodeOutput *NodeInput::get_connected_output() const
+4 -4
View File
@@ -54,7 +54,7 @@ public:
virtual QString name() override;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections) override;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections) override;
virtual void Save(QXmlStreamWriter* writer) const override;
@@ -243,14 +243,14 @@ signals:
void KeyframeRemoved(NodeKeyframePtr key);
protected:
virtual void LoadInternal(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections);
virtual void LoadInternal(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections);
virtual void SaveInternal(QXmlStreamWriter* writer) const;
private:
static QString ValueToString(const DataType& type, const QVariant& value);
QString ValueToString(const QVariant& value) const;
static QVariant StringToValue(const DataType& type, const QString &string);
QVariant StringToValue(const QString &string, QList<FootageConnection> &footage_connections);
void SaveConnections(QXmlStreamWriter* writer) const;
+2 -2
View File
@@ -170,13 +170,13 @@ void NodeInputArray::RemoveAt(int index)
RemoveLast();
}
void NodeInputArray::LoadInternal(QXmlStreamReader *reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections)
void NodeInputArray::LoadInternal(QXmlStreamReader *reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections)
{
if (reader->name() == "subparameters") {
XMLReadLoop(reader, "subparameters") {
if (reader->name() == "input") {
Append();
At(GetSize() - 1)->Load(reader, param_ptrs, input_connections);
At(GetSize() - 1)->Load(reader, param_ptrs, input_connections, footage_connections);
}
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ signals:
void SizeChanged(int size);
protected:
virtual void LoadInternal(QXmlStreamReader* reader, QHash<quintptr, NodeOutput *> &param_ptrs, QList<SerializedConnection> &input_connections) override;
virtual void LoadInternal(QXmlStreamReader* reader, QHash<quintptr, NodeOutput *> &param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections) override;
virtual void SaveInternal(QXmlStreamWriter* writer) const override;
+2 -2
View File
@@ -50,7 +50,7 @@ Node::~Node()
}
}
void Node::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput *> &output_ptrs, QList<NodeInput::SerializedConnection>& input_connections, const QString& element)
void Node::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput *> &output_ptrs, QList<NodeInput::SerializedConnection>& input_connections, QList<NodeParam::FootageConnection>& footage_connections, const QString& element)
{
XMLReadLoop(reader, (element.isEmpty() ? "node" : element)) {
if (reader->isStartElement()) {
@@ -77,7 +77,7 @@ void Node::Load(QXmlStreamReader *reader, QHash<quintptr, NodeOutput *> &output_
continue;
}
param->Load(reader, output_ptrs, input_connections);
param->Load(reader, output_ptrs, input_connections, footage_connections);
}
}
}
+1 -1
View File
@@ -68,7 +68,7 @@ public:
/**
* @brief Clear current node variables and replace them with
*/
void Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<NodeInput::SerializedConnection> &input_connections, const QString &element = QString());
void Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<NodeInput::SerializedConnection> &input_connections, QList<NodeParam::FootageConnection>& footage_connections, const QString &element = QString());
/**
* @brief Save this node into a text/XML format
+1 -1
View File
@@ -42,7 +42,7 @@ QString NodeOutput::name()
return NodeParam::name();
}
void NodeOutput::Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections)
void NodeOutput::Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections)
{
XMLAttributeLoop(reader, attr) {
if (attr.name() == "ptr") {
+1 -1
View File
@@ -42,7 +42,7 @@ public:
virtual QString name() override;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections) override;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections) override;
virtual void Save(QXmlStreamWriter* writer) const override;
+6 -1
View File
@@ -235,10 +235,15 @@ public:
quintptr output;
};
struct FootageConnection {
NodeInput* input;
quintptr footage;
};
/**
* @brief Load function
*/
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections) = 0;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, NodeOutput*>& param_ptrs, QList<SerializedConnection> &input_connections, QList<FootageConnection>& footage_connections) = 0;
/**
* @brief Save function
+2 -2
View File
@@ -44,7 +44,7 @@ QIcon Folder::icon()
return icon::Folder;
}
void Folder::Load(QXmlStreamReader *reader)
void Folder::Load(QXmlStreamReader *reader, QHash<quintptr, StreamPtr> &footage_ptrs, QList<NodeParam::FootageConnection>& footage_connections)
{
XMLAttributeLoop(reader, attr) {
if (attr.name() == "name") {
@@ -67,7 +67,7 @@ void Folder::Load(QXmlStreamReader *reader)
}
add_child(child);
child->Load(reader);
child->Load(reader, footage_ptrs, footage_connections);
}
}
}
+3 -1
View File
@@ -21,6 +21,8 @@
#ifndef FOLDER_H
#define FOLDER_H
#include "node/param.h"
#include "project/item/footage/footage.h"
#include "project/item/item.h"
/**
@@ -40,7 +42,7 @@ public:
virtual QIcon icon() override;
virtual void Load(QXmlStreamReader* reader) override;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, StreamPtr> &footage_ptrs, QList<NodeParam::FootageConnection> &footage_connections) override;
virtual void Save(QXmlStreamWriter* writer) const override;
+4 -4
View File
@@ -25,14 +25,14 @@ AudioStream::AudioStream()
set_type(kAudio);
}
QString AudioStream::description()
QString AudioStream::description() const
{
return QCoreApplication::translate("Stream", "%1: Audio - %2 Channels, %3Hz").arg(QString::number(index()),
QString::number(channels()),
QString::number(sample_rate()));
}
const int &AudioStream::channels()
const int &AudioStream::channels() const
{
return channels_;
}
@@ -42,7 +42,7 @@ void AudioStream::set_channels(const int &channels)
channels_ = channels;
}
const uint64_t &AudioStream::channel_layout()
const uint64_t &AudioStream::channel_layout() const
{
return layout_;
}
@@ -52,7 +52,7 @@ void AudioStream::set_channel_layout(const uint64_t &layout)
layout_ = layout;
}
const int &AudioStream::sample_rate()
const int &AudioStream::sample_rate() const
{
return sample_rate_;
}
+4 -4
View File
@@ -32,15 +32,15 @@ class AudioStream : public Stream
public:
AudioStream();
virtual QString description() override;
virtual QString description() const override;
const int& channels();
const int& channels() const;
void set_channels(const int& channels);
const uint64_t& channel_layout();
const uint64_t& channel_layout() const;
void set_channel_layout(const uint64_t& channel_layout);
const int& sample_rate();
const int& sample_rate() const;
void set_sample_rate(const int& sample_rate);
private:
+19 -8
View File
@@ -37,7 +37,7 @@ Footage::~Footage()
ClearStreams();
}
void Footage::Load(QXmlStreamReader *reader)
void Footage::Load(QXmlStreamReader *reader, QHash<quintptr, StreamPtr>& footage_ptrs, QList<NodeParam::FootageConnection>& footage_connections)
{
QXmlStreamAttributes attributes = reader->attributes();
@@ -54,7 +54,24 @@ void Footage::Load(QXmlStreamReader *reader)
XMLReadLoop(reader, "footage") {
if (reader->isStartElement()) {
if (reader->name() == "stream") {
// FIXME: Load stream custom options here
int stream_index = -1;
quintptr stream_ptr = 0;
XMLAttributeLoop(reader, attr) {
if (attr.name() == "index") {
stream_index = attr.value().toInt();
} else if (attr.name() == "ptr") {
stream_ptr = attr.value().toULongLong();
}
}
if (stream_index > -1 && stream_ptr > 0) {
footage_ptrs.insert(stream_ptr, stream(stream_index));
stream(stream_index)->Load(reader);
} else {
qWarning() << "Invalid stream found in project file";
}
}
}
}
@@ -66,7 +83,6 @@ void Footage::Save(QXmlStreamWriter *writer) const
writer->writeAttribute("name", name());
writer->writeAttribute("filename", filename());
writer->writeAttribute("ptr", FootageToString(this));
foreach (StreamPtr stream, streams_) {
stream->Save(writer);
@@ -322,8 +338,3 @@ void Footage::UpdateTooltip()
break;
}
}
QString FootageToString(const Footage *footage)
{
return QString::number(reinterpret_cast<quintptr>(footage));
}
+1 -3
View File
@@ -63,7 +63,7 @@ public:
/**
* @brief Load function
*/
virtual void Load(QXmlStreamReader* reader) override;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, StreamPtr> &footage_ptrs, QList<NodeParam::FootageConnection> &footage_connections) override;
/**
* @brief Save function
@@ -260,8 +260,6 @@ private:
};
QString FootageToString(const Footage* footage);
using FootagePtr = std::shared_ptr<Footage>;
#endif // FOOTAGE_H
+16 -5
View File
@@ -20,6 +20,7 @@
#include "imagestream.h"
#include "common/xmlreadloop.h"
#include "footage.h"
#include "project/project.h"
#include "render/colormanager.h"
@@ -36,19 +37,29 @@ void ImageStream::FootageSetEvent(Footage *f)
connect(f->project()->color_manager(), SIGNAL(ConfigChanged()), this, SLOT(ColorConfigChanged()), Qt::DirectConnection);
}
void ImageStream::LoadCustomParameters(QXmlStreamReader *reader)
{
XMLReadLoop(reader, "stream") {
if (reader->isStartElement() && reader->name() == "colorspace") {
reader->readNext();
set_colorspace(reader->text().toString());
}
}
}
void ImageStream::SaveCustomParameters(QXmlStreamWriter *writer) const
{
writer->writeTextElement("colorspace", colorspace_);
}
QString ImageStream::description()
QString ImageStream::description() const
{
return QCoreApplication::translate("Stream", "%1: Image - %2x%3").arg(QString::number(index()),
QString::number(width()),
QString::number(height()));
}
const int &ImageStream::width()
const int &ImageStream::width() const
{
return width_;
}
@@ -58,7 +69,7 @@ void ImageStream::set_width(const int &width)
width_ = width;
}
const int &ImageStream::height()
const int &ImageStream::height() const
{
return height_;
}
@@ -68,7 +79,7 @@ void ImageStream::set_height(const int &height)
height_ = height;
}
bool ImageStream::premultiplied_alpha()
bool ImageStream::premultiplied_alpha() const
{
return premultiplied_alpha_;
}
@@ -78,7 +89,7 @@ void ImageStream::set_premultiplied_alpha(bool e)
premultiplied_alpha_ = e;
}
const QString &ImageStream::colorspace()
const QString &ImageStream::colorspace() const
{
if (colorspace_.isEmpty()) {
return footage()->project()->default_input_colorspace();
+7 -5
View File
@@ -32,18 +32,18 @@ class ImageStream : public Stream
public:
ImageStream();
virtual QString description() override;
virtual QString description() const override;
const int& width();
const int& width() const;
void set_width(const int& width);
const int& height();
const int& height() const;
void set_height(const int& height);
bool premultiplied_alpha();
bool premultiplied_alpha() const;
void set_premultiplied_alpha(bool e);
const QString& colorspace();
const QString& colorspace() const;
void set_colorspace(const QString& color);
signals:
@@ -52,6 +52,8 @@ signals:
protected:
virtual void FootageSetEvent(Footage*) override;
virtual void LoadCustomParameters(QXmlStreamReader *reader) override;
virtual void SaveCustomParameters(QXmlStreamWriter* writer) const override;
private:
+14 -3
View File
@@ -35,10 +35,17 @@ Stream::~Stream()
{
}
void Stream::Load(QXmlStreamReader *reader)
{
LoadCustomParameters(reader);
}
void Stream::Save(QXmlStreamWriter *writer) const
{
writer->writeStartElement("stream");
writer->writeAttribute("ptr", QString::number(reinterpret_cast<quintptr>(this)));
writer->writeAttribute("index", QString::number(index_));
SaveCustomParameters(writer);
@@ -46,12 +53,12 @@ void Stream::Save(QXmlStreamWriter *writer) const
writer->writeEndElement(); // stream
}
QString Stream::description()
QString Stream::description() const
{
return QCoreApplication::translate("Stream", "%1: Unknown").arg(index());
}
const Stream::Type &Stream::type()
const Stream::Type &Stream::type() const
{
return type_;
}
@@ -102,7 +109,7 @@ void Stream::set_duration(const int64_t &duration)
duration_ = duration;
}
bool Stream::enabled()
bool Stream::enabled() const
{
return enabled_;
}
@@ -137,6 +144,10 @@ void Stream::FootageSetEvent(Footage *)
{
}
void Stream::LoadCustomParameters(QXmlStreamReader* reader)
{
}
void Stream::SaveCustomParameters(QXmlStreamWriter *writer) const
{
}
+7 -3
View File
@@ -75,11 +75,13 @@ public:
*/
virtual ~Stream();
void Load(QXmlStreamReader* reader);
void Save(QXmlStreamWriter *writer) const;
virtual QString description();
virtual QString description() const;
const Type& type();
const Type& type() const;
void set_type(const Type& type);
Footage* footage() const;
@@ -94,7 +96,7 @@ public:
const int64_t& duration() const;
void set_duration(const int64_t& duration);
bool enabled();
bool enabled() const;
void set_enabled(bool e);
static QIcon IconFromType(const Type& type);
@@ -106,6 +108,8 @@ public:
protected:
virtual void FootageSetEvent(Footage*);
virtual void LoadCustomParameters(QXmlStreamReader *reader);
virtual void SaveCustomParameters(QXmlStreamWriter* writer) const;
private:
+2 -2
View File
@@ -25,14 +25,14 @@ VideoStream::VideoStream()
set_type(kVideo);
}
QString VideoStream::description()
QString VideoStream::description() const
{
return QCoreApplication::translate("Stream", "%1: Video - %2x%3").arg(QString::number(index()),
QString::number(width()),
QString::number(height()));
}
const rational &VideoStream::frame_rate()
const rational &VideoStream::frame_rate() const
{
return frame_rate_;
}
+2 -2
View File
@@ -28,14 +28,14 @@ class VideoStream : public ImageStream
public:
VideoStream();
virtual QString description() override;
virtual QString description() const override;
/**
* @brief Get this video stream's frame rate
*
* Used purely for metadata, rendering uses the timebase instead.
*/
const rational& frame_rate();
const rational& frame_rate() const;
void set_frame_rate(const rational& frame_rate);
private:
+3 -1
View File
@@ -30,6 +30,8 @@
#include "common/constructors.h"
#include "common/threadedobject.h"
#include "node/param.h"
#include "project/item/footage/stream.h"
class Project;
@@ -63,7 +65,7 @@ public:
DISABLE_COPY_MOVE(Item)
virtual void Load(QXmlStreamReader* reader) = 0;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, StreamPtr> &footage_ptrs, QList<NodeParam::FootageConnection> &footage_connections) = 0;
virtual void Save(QXmlStreamWriter* writer) const = 0;
+2 -2
View File
@@ -42,7 +42,7 @@ Sequence::Sequence()
AddNode(viewer_output_);
}
void Sequence::Load(QXmlStreamReader *reader)
void Sequence::Load(QXmlStreamReader *reader, QHash<quintptr, StreamPtr> &footage_ptrs, QList<NodeInput::FootageConnection>& footage_connections)
{
XMLAttributeLoop(reader, attr) {
if (attr.name() == "name") {
@@ -125,7 +125,7 @@ void Sequence::Load(QXmlStreamReader *reader)
}
if (node) {
node->Load(reader, output_ptrs, desired_connections, reader->name().toString());
node->Load(reader, output_ptrs, desired_connections, footage_connections, reader->name().toString());
AddNode(node);
}
+2 -1
View File
@@ -25,6 +25,7 @@
#include "node/graph.h"
#include "node/output/viewer/viewer.h"
#include "render/videoparams.h"
#include "project/item/footage/stream.h"
#include "project/item/item.h"
class Sequence;
@@ -41,7 +42,7 @@ public:
/**
* @brief Load function
*/
virtual void Load(QXmlStreamReader* reader) override;
virtual void Load(QXmlStreamReader* reader, QHash<quintptr, StreamPtr> &footage_ptrs, QList<NodeParam::FootageConnection> &footage_connections) override;
/**
* @brief Save function
+10 -1
View File
@@ -35,12 +35,15 @@ Project::Project()
void Project::Load(QXmlStreamReader *reader)
{
QHash<quintptr, StreamPtr> footage_ptrs;
QList<NodeInput::FootageConnection> footage_connections;
XMLReadLoop(reader, "project") {
if (reader->isStartElement()) {
if (reader->name() == "folder") {
// Assume this folder is our root
root_.Load(reader);
root_.Load(reader, footage_ptrs, footage_connections);
} else if (reader->name() == "colormanagement") {
@@ -57,6 +60,12 @@ void Project::Load(QXmlStreamReader *reader)
}
}
}
foreach (const NodeInput::FootageConnection& con, footage_connections) {
if (con.footage) {
con.input->set_standard_value(QVariant::fromValue(footage_ptrs.value(con.footage)));
}
}
}
void Project::Save(QXmlStreamWriter *writer) const