Merge branch 'master' into hashremoval
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2021 Olive Team
|
||||
# Copyright (C) 2022 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2021 Olive Team
|
||||
# Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2021 Olive Team
|
||||
# Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -89,12 +89,8 @@ void Footage::InputValueChangedEvent(const QString &input, int element)
|
||||
|
||||
FootageDescription footage_info;
|
||||
|
||||
if (QFileInfo::exists(meta_cache_file)) {
|
||||
|
||||
// Load meta cache file
|
||||
footage_info.Load(meta_cache_file);
|
||||
|
||||
} else {
|
||||
// Try to load footage info from cache
|
||||
if (!QFileInfo::exists(meta_cache_file) || !footage_info.Load(meta_cache_file)) {
|
||||
|
||||
// Probe and create cache
|
||||
QVector<DecoderPtr> decoder_list = Decoder::ReceiveListOfAllDecoders();
|
||||
@@ -124,6 +120,10 @@ void Footage::InputValueChangedEvent(const QString &input, int element)
|
||||
AddStream(Track::kAudio, QVariant::fromValue(footage_info.GetAudioStreams().at(i)));
|
||||
}
|
||||
|
||||
for (int i=0; i<footage_info.GetSubtitleStreams().size(); i++) {
|
||||
AddStream(Track::kSubtitle, QVariant::fromValue(footage_info.GetSubtitleStreams().at(i)));
|
||||
}
|
||||
|
||||
SetValid();
|
||||
}
|
||||
|
||||
@@ -149,6 +149,12 @@ rational Footage::VerifyLengthInternal(Track::Type type) const
|
||||
if (first_stream.is_valid()) {
|
||||
return Timecode::timestamp_to_time(first_stream.duration(), first_stream.time_base());
|
||||
}
|
||||
} else if (type == Track::kSubtitle) {
|
||||
SubtitleParams first_stream = GetFirstEnabledSubtitleStream();
|
||||
|
||||
if (first_stream.is_valid()) {
|
||||
return first_stream.duration();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -168,6 +174,7 @@ void Footage::Clear()
|
||||
// Clear all dynamically created inputs
|
||||
InputArrayResize(kVideoParamsInput, 0);
|
||||
InputArrayResize(kAudioParamsInput, 0);
|
||||
InputArrayResize(kSubtitleParamsInput, 0);
|
||||
|
||||
// Clear decoder link
|
||||
decoder_.clear();
|
||||
@@ -208,13 +215,19 @@ void Footage::set_timestamp(const qint64 &t)
|
||||
|
||||
int Footage::GetStreamIndex(Track::Type type, int index) const
|
||||
{
|
||||
if (type == Track::kVideo) {
|
||||
switch (type) {
|
||||
case Track::kVideo:
|
||||
return GetVideoParams(index).stream_index();
|
||||
} else if (type == Track::kAudio) {
|
||||
case Track::kAudio:
|
||||
return GetAudioParams(index).stream_index();
|
||||
} else {
|
||||
return -1;
|
||||
case Track::kSubtitle:
|
||||
return GetSubtitleParams(index).stream_index();
|
||||
case Track::kNone:
|
||||
case Track::kCount:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Track::Reference Footage::GetReferenceFromRealIndex(int real_index) const
|
||||
@@ -232,6 +245,12 @@ Track::Reference Footage::GetReferenceFromRealIndex(int real_index) const
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<GetSubtitleStreamCount(); i++) {
|
||||
if (GetSubtitleParams(i).stream_index() == real_index) {
|
||||
return Track::Reference(Track::kSubtitle, i);
|
||||
}
|
||||
}
|
||||
|
||||
return Track::Reference();
|
||||
}
|
||||
|
||||
@@ -252,6 +271,8 @@ QIcon Footage::icon() const
|
||||
return icon::Audio;
|
||||
} else if (s.is_valid() && s.video_type() == VideoParams::kVideoTypeStill) {
|
||||
return icon::Image;
|
||||
} else if (HasEnabledSubtitleStreams()) {
|
||||
return icon::Subtitles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,6 +299,12 @@ QString Footage::DescribeAudioStream(const AudioParams ¶ms)
|
||||
QString::number(params.sample_rate()));
|
||||
}
|
||||
|
||||
QString Footage::DescribeSubtitleStream(const SubtitleParams ¶ms)
|
||||
{
|
||||
return tr("%1: Subtitle")
|
||||
.arg(QString::number(params.stream_index()));
|
||||
}
|
||||
|
||||
void Footage::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const
|
||||
{
|
||||
Q_UNUSED(globals)
|
||||
@@ -440,6 +467,16 @@ void Footage::UpdateTooltip()
|
||||
}
|
||||
}
|
||||
|
||||
int sp_sz = GetSubtitleStreamCount();
|
||||
for (int i=0; i<sp_sz; i++) {
|
||||
SubtitleParams p = GetSubtitleParams(i);
|
||||
|
||||
if (p.enabled()) {
|
||||
tip.append("\n");
|
||||
tip.append(DescribeSubtitleStream(p));
|
||||
}
|
||||
}
|
||||
|
||||
SetToolTip(tip);
|
||||
} else {
|
||||
SetToolTip(tr("Invalid"));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -173,6 +173,7 @@ public:
|
||||
|
||||
static QString DescribeVideoStream(const VideoParams& params);
|
||||
static QString DescribeAudioStream(const AudioParams& params);
|
||||
static QString DescribeSubtitleStream(const SubtitleParams& params);
|
||||
|
||||
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -40,6 +40,20 @@ bool FootageDescription::Load(const QString &filename)
|
||||
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("streamcache")) {
|
||||
// Default to first version of metadata (which wasn't versioned at all)
|
||||
unsigned version = 1;
|
||||
|
||||
XMLAttributeLoop((&reader), attr) {
|
||||
if (attr.name() == QStringLiteral("version")) {
|
||||
version = attr.value().toUInt();
|
||||
}
|
||||
}
|
||||
|
||||
if (version != kFootageMetaVersion) {
|
||||
// If this is a different version, discard so we can probe new data
|
||||
return false;
|
||||
}
|
||||
|
||||
while (XMLReadNextStartElement(&reader)) {
|
||||
if (reader.name() == QStringLiteral("decoder")) {
|
||||
decoder_ = reader.readElementText();
|
||||
@@ -53,6 +67,10 @@ bool FootageDescription::Load(const QString &filename)
|
||||
AudioParams ap;
|
||||
ap.Load(&reader);
|
||||
AddAudioStream(ap);
|
||||
} else if (reader.name() == QStringLiteral("subtitle")) {
|
||||
SubtitleParams sp;
|
||||
sp.Load(&reader);
|
||||
AddSubtitleStream(sp);
|
||||
} else {
|
||||
reader.skipCurrentElement();
|
||||
}
|
||||
@@ -68,7 +86,11 @@ bool FootageDescription::Load(const QString &filename)
|
||||
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
if (reader.hasError()) {
|
||||
qWarning() << "Failed to load footage description for" << filename << reader.errorString();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -88,6 +110,8 @@ bool FootageDescription::Save(const QString &filename) const
|
||||
|
||||
writer.writeStartElement(QStringLiteral("streamcache"));
|
||||
|
||||
writer.writeAttribute(QStringLiteral("version"), QString::number(kFootageMetaVersion));
|
||||
|
||||
writer.writeTextElement(QStringLiteral("decoder"), decoder_);
|
||||
|
||||
writer.writeStartElement(QStringLiteral("streams"));
|
||||
@@ -104,6 +128,12 @@ bool FootageDescription::Save(const QString &filename) const
|
||||
writer.writeEndElement(); // audio
|
||||
}
|
||||
|
||||
foreach (const SubtitleParams& sp, subtitle_streams_) {
|
||||
writer.writeStartElement(QStringLiteral("subtitle"));
|
||||
sp.Save(&writer);
|
||||
writer.writeEndElement(); // audio
|
||||
}
|
||||
|
||||
writer.writeEndElement(); // streams
|
||||
|
||||
writer.writeEndElement(); // streamcache
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "node/output/track/track.h"
|
||||
#include "render/audioparams.h"
|
||||
#include "render/subtitleparams.h"
|
||||
#include "render/videoparams.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -37,7 +38,7 @@ public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return !decoder_.isEmpty() && (!video_streams_.isEmpty() || !audio_streams_.isEmpty());
|
||||
return !decoder_.isEmpty() && (!video_streams_.isEmpty() || !audio_streams_.isEmpty() || !subtitle_streams_.isEmpty());
|
||||
}
|
||||
|
||||
const QString& decoder() const
|
||||
@@ -59,12 +60,21 @@ public:
|
||||
audio_streams_.append(audio_params);
|
||||
}
|
||||
|
||||
void AddSubtitleStream(const SubtitleParams& sub_params)
|
||||
{
|
||||
Q_ASSERT(!HasStreamIndex(sub_params.stream_index()));
|
||||
|
||||
subtitle_streams_.append(sub_params);
|
||||
}
|
||||
|
||||
Track::Type GetTypeOfStream(int index)
|
||||
{
|
||||
if (StreamIsVideo(index)) {
|
||||
return Track::kVideo;
|
||||
} else if (StreamIsAudio(index)) {
|
||||
return Track::kAudio;
|
||||
} else if (StreamIsSubtitle(index)) {
|
||||
return Track::kSubtitle;
|
||||
} else {
|
||||
return Track::kNone;
|
||||
}
|
||||
@@ -92,9 +102,20 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StreamIsSubtitle(int index) const
|
||||
{
|
||||
foreach (const SubtitleParams& sp, subtitle_streams_) {
|
||||
if (sp.stream_index() == index) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasStreamIndex(int index) const
|
||||
{
|
||||
return StreamIsVideo(index) || StreamIsAudio(index);
|
||||
return StreamIsVideo(index) || StreamIsAudio(index) || StreamIsSubtitle(index);
|
||||
}
|
||||
|
||||
bool Load(const QString& filename);
|
||||
@@ -111,13 +132,22 @@ public:
|
||||
return audio_streams_;
|
||||
}
|
||||
|
||||
const QVector<SubtitleParams>& GetSubtitleStreams() const
|
||||
{
|
||||
return subtitle_streams_;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr unsigned kFootageMetaVersion = 2;
|
||||
|
||||
QString decoder_;
|
||||
|
||||
QVector<VideoParams> video_streams_;
|
||||
|
||||
QVector<AudioParams> audio_streams_;
|
||||
|
||||
QVector<SubtitleParams> subtitle_streams_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
namespace olive {
|
||||
|
||||
const QString Project::kItemMimeType = QStringLiteral("application/x-oliveprojectitemdata");
|
||||
|
||||
Project::Project() :
|
||||
is_modified_(false),
|
||||
autorecovery_saved_(true)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -117,6 +117,8 @@ public:
|
||||
*/
|
||||
static Project *GetProjectFromObject(const QObject *o);
|
||||
|
||||
static const QString kItemMimeType;
|
||||
|
||||
signals:
|
||||
void NameChanged();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2021 Olive Team
|
||||
# Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -271,7 +271,7 @@ Qt::ItemFlags ProjectViewModel::flags(const QModelIndex &index) const
|
||||
QStringList ProjectViewModel::mimeTypes() const
|
||||
{
|
||||
// Allow data from this model and a file list from external sources
|
||||
return {QStringLiteral("application/x-oliveprojectitemdata"), QStringLiteral("text/uri-list")};
|
||||
return {Project::kItemMimeType, QStringLiteral("text/uri-list")};
|
||||
}
|
||||
|
||||
QMimeData *ProjectViewModel::mimeData(const QModelIndexList &indexes) const
|
||||
@@ -312,7 +312,7 @@ QMimeData *ProjectViewModel::mimeData(const QModelIndexList &indexes) const
|
||||
}
|
||||
|
||||
// Set byte array as the mime data and return the mime data
|
||||
data->setData(QStringLiteral("application/x-oliveprojectitemdata"), encoded_data);
|
||||
data->setData(Project::kItemMimeType, encoded_data);
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -331,9 +331,9 @@ bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action
|
||||
// Probe mime data for its format
|
||||
QStringList mime_formats = data->formats();
|
||||
|
||||
if (mime_formats.contains(QStringLiteral("application/x-oliveprojectitemdata"))) {
|
||||
if (mime_formats.contains(Project::kItemMimeType)) {
|
||||
// Data is drag/drop data from this model
|
||||
QByteArray model_data = data->data(QStringLiteral("application/x-oliveprojectitemdata"));
|
||||
QByteArray model_data = data->data(Project::kItemMimeType);
|
||||
|
||||
// Use QDataStream to deserialize the data
|
||||
QDataStream stream(&model_data, QIODevice::ReadOnly);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2021 Olive Team
|
||||
# Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Olive - Non-Linear Video Editor
|
||||
# Copyright (C) 2021 Olive Team
|
||||
# Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
};
|
||||
|
||||
using SerializedProperties = QHash<Node*, QMap<QString, QString> >;
|
||||
using SerializedKeyframes = QHash<QString, QVector<NodeKeyframe*> >;
|
||||
|
||||
class LoadData
|
||||
{
|
||||
@@ -65,6 +66,8 @@ public:
|
||||
|
||||
std::vector<TimelineMarker*> markers;
|
||||
|
||||
SerializedKeyframes keyframes;
|
||||
|
||||
};
|
||||
|
||||
class Result
|
||||
@@ -105,7 +108,7 @@ public:
|
||||
class SaveData
|
||||
{
|
||||
public:
|
||||
SaveData(Project *project, const QString &filename = QString())
|
||||
SaveData(Project *project = nullptr, const QString &filename = QString())
|
||||
{
|
||||
project_ = project;
|
||||
filename_ = filename;
|
||||
@@ -128,6 +131,9 @@ public:
|
||||
const std::vector<TimelineMarker*> &GetOnlySerializeMarkers() const { return only_serialize_markers_; }
|
||||
void SetOnlySerializeMarkers(const std::vector<TimelineMarker*> &only) { only_serialize_markers_ = only; }
|
||||
|
||||
const std::vector<NodeKeyframe*> &GetOnlySerializeKeyframes() const { return only_serialize_keyframes_; }
|
||||
void SetOnlySerializeKeyframes(const std::vector<NodeKeyframe*> &only) { only_serialize_keyframes_ = only; }
|
||||
|
||||
const SerializedProperties &GetProperties() const { return properties_; }
|
||||
void SetProperties(const SerializedProperties &p) { properties_ = p; }
|
||||
|
||||
@@ -142,6 +148,8 @@ public:
|
||||
|
||||
std::vector<TimelineMarker*> only_serialize_markers_;
|
||||
|
||||
std::vector<NodeKeyframe*> only_serialize_keyframes_;
|
||||
|
||||
};
|
||||
|
||||
static void Initialize();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -99,6 +99,102 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("keyframes")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("node")) {
|
||||
QString node_id;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
node_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Node *n = nullptr;
|
||||
if (!node_id.isEmpty()) {
|
||||
n = NodeFactory::CreateFromID(node_id);
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("input")) {
|
||||
QString input_id;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
input_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (input_id.isEmpty()) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("element")) {
|
||||
QString element_id;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
element_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (element_id.isEmpty()) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("track")) {
|
||||
QString track_id;
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (attr.name() == QStringLiteral("id")) {
|
||||
track_id = attr.value().toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (track_id.isEmpty()) {
|
||||
reader->skipCurrentElement();
|
||||
} else {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("key")) {
|
||||
NodeKeyframe *key = new NodeKeyframe();
|
||||
key->set_input(input_id);
|
||||
key->set_element(element_id.toInt());
|
||||
key->set_track(track_id.toInt());
|
||||
|
||||
LoadKeyframe(reader, key, n->GetInputDataType(input_id));
|
||||
|
||||
load_data.keyframes[node_id].append(key);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete n;
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reader->name() == QStringLiteral("markers")) {
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
@@ -221,8 +317,6 @@ ProjectSerializer220403::LoadData ProjectSerializer220403::Load(Project *project
|
||||
|
||||
void ProjectSerializer220403::Save(QXmlStreamWriter *writer, const SaveData &data, void *reserved) const
|
||||
{
|
||||
Project *project = data.GetProject();
|
||||
|
||||
if (!data.GetOnlySerializeMarkers().empty()) {
|
||||
|
||||
writer->writeStartElement(QStringLiteral("markers"));
|
||||
@@ -239,9 +333,63 @@ void ProjectSerializer220403::Save(QXmlStreamWriter *writer, const SaveData &dat
|
||||
|
||||
writer->writeEndElement(); // markers
|
||||
|
||||
} else {
|
||||
} else if (!data.GetOnlySerializeKeyframes().empty()) {
|
||||
|
||||
writer->writeTextElement(QStringLiteral("uuid"), data.GetProject()->GetUuid().toString());
|
||||
writer->writeStartElement(QStringLiteral("keyframes"));
|
||||
|
||||
// Organize keyframes into node+input
|
||||
QHash<QString, QHash<QString, QMap<int, QMap<int, QVector<NodeKeyframe*> > > > > organized;
|
||||
|
||||
for (auto it=data.GetOnlySerializeKeyframes().cbegin(); it!=data.GetOnlySerializeKeyframes().cend(); it++) {
|
||||
NodeKeyframe *key = *it;
|
||||
organized[key->parent()->id()][key->input()][key->element()][key->track()].append(key);
|
||||
}
|
||||
|
||||
for (auto it=organized.cbegin(); it!=organized.cend(); it++) {
|
||||
writer->writeStartElement(QStringLiteral("node"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), it.key());
|
||||
|
||||
for (auto jt=it.value().cbegin(); jt!=it.value().cend(); jt++) {
|
||||
writer->writeStartElement(QStringLiteral("input"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), jt.key());
|
||||
|
||||
for (auto kt=jt.value().cbegin(); kt!=jt.value().cend(); kt++) {
|
||||
writer->writeStartElement(QStringLiteral("element"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), QString::number(kt.key()));
|
||||
|
||||
for (auto lt=kt.value().cbegin(); lt!=kt.value().cend(); lt++) {
|
||||
const QVector<NodeKeyframe *> &keys = lt.value();
|
||||
|
||||
writer->writeStartElement(QStringLiteral("track"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("id"), QString::number(lt.key()));
|
||||
|
||||
for (NodeKeyframe *key : keys) {
|
||||
writer->writeStartElement(QStringLiteral("key"));
|
||||
SaveKeyframe(writer, key, key->parent()->GetInputDataType(key->input()));
|
||||
writer->writeEndElement(); // key
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // track
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // element
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // input
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // node;
|
||||
}
|
||||
|
||||
writer->writeEndElement(); // keyframes
|
||||
|
||||
} else if (Project *project = data.GetProject()) {
|
||||
|
||||
writer->writeTextElement(QStringLiteral("uuid"), project->GetUuid().toString());
|
||||
|
||||
writer->writeStartElement(QStringLiteral("nodes"));
|
||||
|
||||
@@ -310,6 +458,10 @@ void ProjectSerializer220403::Save(QXmlStreamWriter *writer, const SaveData &dat
|
||||
// Save main window project layout
|
||||
project->GetLayoutInfo().toXml(writer);
|
||||
|
||||
} else {
|
||||
|
||||
qCritical() << "Cannot save nodes without project object";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,6 +700,14 @@ void ProjectSerializer220403::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
|
||||
NodeValue::Type data_type = node->GetInputDataType(input);
|
||||
|
||||
// HACK: SubtitleParams contain the actual subtitle data, so loading/replacing it will overwrite
|
||||
// the valid subtitles. We hack around it by simply skipping loading subtitles, we'll see
|
||||
// if this ends up being an issue in the future.
|
||||
if (data_type == NodeValue::kSubtitleParams) {
|
||||
reader->skipCurrentElement();
|
||||
return;
|
||||
}
|
||||
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("standard")) {
|
||||
// Load standard value
|
||||
@@ -601,40 +761,13 @@ void ProjectSerializer220403::LoadImmediate(QXmlStreamReader *reader, Node *node
|
||||
}
|
||||
|
||||
if (reader->name() == QStringLiteral("key")) {
|
||||
QString key_input;
|
||||
rational key_time;
|
||||
NodeKeyframe::Type key_type = NodeKeyframe::kLinear;
|
||||
QVariant key_value;
|
||||
QPointF key_in_handle;
|
||||
QPointF key_out_handle;
|
||||
NodeKeyframe* key = new NodeKeyframe();
|
||||
key->set_input(input);
|
||||
key->set_element(element);
|
||||
key->set_track(track);
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (IsCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (attr.name() == QStringLiteral("input")) {
|
||||
key_input = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("time")) {
|
||||
key_time = rational::fromString(attr.value().toString());
|
||||
} else if (attr.name() == QStringLiteral("type")) {
|
||||
key_type = static_cast<NodeKeyframe::Type>(attr.value().toInt());
|
||||
} else if (attr.name() == QStringLiteral("inhandlex")) {
|
||||
key_in_handle.setX(attr.value().toDouble());
|
||||
} else if (attr.name() == QStringLiteral("inhandley")) {
|
||||
key_in_handle.setY(attr.value().toDouble());
|
||||
} else if (attr.name() == QStringLiteral("outhandlex")) {
|
||||
key_out_handle.setX(attr.value().toDouble());
|
||||
} else if (attr.name() == QStringLiteral("outhandley")) {
|
||||
key_out_handle.setY(attr.value().toDouble());
|
||||
}
|
||||
}
|
||||
|
||||
key_value = NodeValue::StringToValue(data_type, reader->readElementText(), true);
|
||||
|
||||
NodeKeyframe* key = new NodeKeyframe(key_time, key_value, key_type, track, element, key_input, node);
|
||||
key->set_bezier_control_in(key_in_handle);
|
||||
key->set_bezier_control_out(key_out_handle);
|
||||
LoadKeyframe(reader, key, data_type);
|
||||
key->setParent(node);
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
@@ -695,15 +828,7 @@ void ProjectSerializer220403::SaveImmediate(QXmlStreamWriter *writer, Node *node
|
||||
for (NodeKeyframe* key : track) {
|
||||
writer->writeStartElement(QStringLiteral("key"));
|
||||
|
||||
writer->writeAttribute(QStringLiteral("input"), key->input());
|
||||
writer->writeAttribute(QStringLiteral("time"), key->time().toString());
|
||||
writer->writeAttribute(QStringLiteral("type"), QString::number(key->type()));
|
||||
writer->writeAttribute(QStringLiteral("inhandlex"), QString::number(key->bezier_control_in().x()));
|
||||
writer->writeAttribute(QStringLiteral("inhandley"), QString::number(key->bezier_control_in().y()));
|
||||
writer->writeAttribute(QStringLiteral("outhandlex"), QString::number(key->bezier_control_out().x()));
|
||||
writer->writeAttribute(QStringLiteral("outhandley"), QString::number(key->bezier_control_out().y()));
|
||||
|
||||
writer->writeCharacters(NodeValue::ValueToString(data_type, key->value(), true));
|
||||
SaveKeyframe(writer, key, data_type);
|
||||
|
||||
writer->writeEndElement(); // key
|
||||
}
|
||||
@@ -722,6 +847,53 @@ void ProjectSerializer220403::SaveImmediate(QXmlStreamWriter *writer, Node *node
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSerializer220403::LoadKeyframe(QXmlStreamReader *reader, NodeKeyframe *key, NodeValue::Type data_type) const
|
||||
{
|
||||
QString key_input;
|
||||
QPointF key_in_handle;
|
||||
QPointF key_out_handle;
|
||||
|
||||
XMLAttributeLoop(reader, attr) {
|
||||
if (IsCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (attr.name() == QStringLiteral("input")) {
|
||||
key_input = attr.value().toString();
|
||||
} else if (attr.name() == QStringLiteral("time")) {
|
||||
key->set_time(rational::fromString(attr.value().toString()));
|
||||
} else if (attr.name() == QStringLiteral("type")) {
|
||||
key->set_type(static_cast<NodeKeyframe::Type>(attr.value().toInt()));
|
||||
} else if (attr.name() == QStringLiteral("inhandlex")) {
|
||||
key_in_handle.setX(attr.value().toDouble());
|
||||
} else if (attr.name() == QStringLiteral("inhandley")) {
|
||||
key_in_handle.setY(attr.value().toDouble());
|
||||
} else if (attr.name() == QStringLiteral("outhandlex")) {
|
||||
key_out_handle.setX(attr.value().toDouble());
|
||||
} else if (attr.name() == QStringLiteral("outhandley")) {
|
||||
key_out_handle.setY(attr.value().toDouble());
|
||||
}
|
||||
}
|
||||
|
||||
key->set_value(NodeValue::StringToValue(data_type, reader->readElementText(), true));
|
||||
|
||||
key->set_bezier_control_in(key_in_handle);
|
||||
key->set_bezier_control_out(key_out_handle);
|
||||
}
|
||||
|
||||
void ProjectSerializer220403::SaveKeyframe(QXmlStreamWriter *writer, NodeKeyframe *key, NodeValue::Type data_type) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("input"), key->input());
|
||||
writer->writeAttribute(QStringLiteral("time"), key->time().toString());
|
||||
writer->writeAttribute(QStringLiteral("type"), QString::number(key->type()));
|
||||
writer->writeAttribute(QStringLiteral("inhandlex"), QString::number(key->bezier_control_in().x()));
|
||||
writer->writeAttribute(QStringLiteral("inhandley"), QString::number(key->bezier_control_in().y()));
|
||||
writer->writeAttribute(QStringLiteral("outhandlex"), QString::number(key->bezier_control_out().x()));
|
||||
writer->writeAttribute(QStringLiteral("outhandley"), QString::number(key->bezier_control_out().y()));
|
||||
|
||||
writer->writeCharacters(NodeValue::ValueToString(data_type, key->value(), true));
|
||||
}
|
||||
|
||||
bool ProjectSerializer220403::LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr, Node::Position *pos) const
|
||||
{
|
||||
bool got_node_ptr = false;
|
||||
@@ -1011,8 +1183,8 @@ void ProjectSerializer220403::LoadMarker(QXmlStreamReader *reader, TimelineMarke
|
||||
void ProjectSerializer220403::SaveMarker(QXmlStreamWriter *writer, TimelineMarker *marker) const
|
||||
{
|
||||
writer->writeAttribute(QStringLiteral("name"), marker->name());
|
||||
writer->writeAttribute(QStringLiteral("in"), marker->time_range().in().toString());
|
||||
writer->writeAttribute(QStringLiteral("out"), marker->time_range().out().toString());
|
||||
writer->writeAttribute(QStringLiteral("in"), marker->time().in().toString());
|
||||
writer->writeAttribute(QStringLiteral("out"), marker->time().out().toString());
|
||||
writer->writeAttribute(QStringLiteral("color"), QString::number(marker->color()));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2021 Olive Team
|
||||
Copyright (C) 2022 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
|
||||
@@ -86,6 +86,10 @@ private:
|
||||
|
||||
void SaveImmediate(QXmlStreamWriter *writer, Node *node, const QString &input, int element) const;
|
||||
|
||||
void LoadKeyframe(QXmlStreamReader *reader, NodeKeyframe *key, NodeValue::Type data_type) const;
|
||||
|
||||
void SaveKeyframe(QXmlStreamWriter *writer, NodeKeyframe *key, NodeValue::Type data_type) const;
|
||||
|
||||
bool LoadPosition(QXmlStreamReader *reader, quintptr *node_ptr, Node::Position *pos) const;
|
||||
|
||||
void SavePosition(QXmlStreamWriter *writer, Node *node, const Node::Position &pos) const;
|
||||
|
||||
Reference in New Issue
Block a user