implement entire project in nodes

Project items are now represented directly in nodes opening up more versatility and possibilities. This is the first iteration of this and will be buggy. Need to test thoroughly.
This commit is contained in:
itsmattkc
2021-02-15 21:31:57 +11:00
parent 155470bec1
commit d7c5ac4b44
174 changed files with 3515 additions and 4658 deletions
-1
View File
@@ -21,7 +21,6 @@
#ifndef COLORPROCESSORCACHE_H
#define COLORPROCESSORCACHE_H
#include "project/item/footage/stream.h"
#include "render/colorprocessor.h"
namespace olive {
+1
View File
@@ -18,6 +18,7 @@ set(OLIVE_SOURCES
${OLIVE_SOURCES}
render/job/acceleratedjob.cpp
render/job/acceleratedjob.h
render/job/footagejob.h
render/job/generatejob.h
render/job/samplejob.h
render/job/shaderjob.h
+60
View File
@@ -0,0 +1,60 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 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 FOOTAGEJOB_H
#define FOOTAGEJOB_H
#include "project/item/footage/footage.h"
namespace olive {
class FootageJob
{
public:
FootageJob() = default;
FootageJob(const Footage::StreamReference& ref, const TimeRange& range) :
footage_(ref),
range_(range)
{
}
const Footage::StreamReference& footage() const
{
return footage_;
}
const TimeRange& range() const
{
return range_;
}
private:
Footage::StreamReference footage_;
TimeRange range_;
};
}
Q_DECLARE_METATYPE(olive::FootageJob)
#endif // FOOTAGEJOB_H
+3 -1
View File
@@ -437,10 +437,12 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
case NodeValue::kRational:
case NodeValue::kFont:
case NodeValue::kFile:
case NodeValue::kVideoStreamProperties:
case NodeValue::kAudioStreamProperties:
case NodeValue::kShaderJob:
case NodeValue::kSampleJob:
case NodeValue::kGenerateJob:
case NodeValue::kFootage:
case NodeValue::kFootageJob:
case NodeValue::kNone:
break;
}
+1 -6
View File
@@ -151,12 +151,7 @@ Project *PlaybackCache::GetProject() const
return nullptr;
}
Sequence* sequence = static_cast<Sequence*>(viewer->parent());
if (!sequence) {
return nullptr;
}
return sequence->project();
return viewer->project();
}
void PlaybackCache::RemoveRangeFromJobs(const TimeRange &remove)
+7 -4
View File
@@ -59,7 +59,7 @@ void PreviewAutoCacher::SetPaused(bool paused)
}
}
void PreviewAutoCacher::GenerateHashes(ViewerOutput *viewer, FrameHashCache* cache, const QVector<rational> &times, qint64 job_time)
void PreviewAutoCacher::GenerateHashes(Sequence *viewer, FrameHashCache* cache, const QVector<rational> &times, qint64 job_time)
{
std::vector<QByteArray> existing_hashes;
@@ -289,6 +289,9 @@ void PreviewAutoCacher::AddNode(Node *node)
// Copy node
Node* copy = node->copy();
// Add to project
copy->setParent(&copied_project_);
// Insert into map
copy_map_.insert(node, copy);
@@ -339,8 +342,8 @@ void PreviewAutoCacher::UpdateAudioParams()
void PreviewAutoCacher::SetPlayhead(const rational &playhead)
{
cache_range_ = TimeRange(playhead - Config::Current()["DiskCacheBehind"].value<rational>(),
playhead + Config::Current()["DiskCacheAhead"].value<rational>());
cache_range_ = TimeRange(playhead - Config::Current()[QStringLiteral("DiskCacheBehind")].value<rational>(),
playhead + Config::Current()[QStringLiteral("DiskCacheAhead")].value<rational>());
has_changed_ = true;
use_custom_range_ = false;
@@ -588,7 +591,7 @@ void PreviewAutoCacher::ForceCacheRange(const TimeRange &range)
RequeueFrames();
}
void PreviewAutoCacher::SetViewerNode(ViewerOutput *viewer_node)
void PreviewAutoCacher::SetViewerNode(Sequence *viewer_node)
{
if (viewer_node_ == viewer_node) {
return;
+7 -4
View File
@@ -7,6 +7,7 @@
#include "node/graph.h"
#include "node/node.h"
#include "node/output/viewer/viewer.h"
#include "project/project.h"
#include "render/colormanager.h"
#include "threading/threadticketwatcher.h"
@@ -28,7 +29,7 @@ public:
/**
* @brief Set the viewer node to auto-cache
*/
void SetViewerNode(ViewerOutput *viewer_node);
void SetViewerNode(Sequence *viewer_node);
/**
* @brief If the mouse is held during the next cache invalidation, cache anyway
@@ -91,7 +92,7 @@ public:
}
private:
static void GenerateHashes(ViewerOutput* viewer, FrameHashCache *cache, const QVector<rational>& times, qint64 job_time);
static void GenerateHashes(Sequence *viewer, FrameHashCache *cache, const QVector<rational>& times, qint64 job_time);
void TryRender();
@@ -131,11 +132,13 @@ private:
NodeOutput output;
};
ViewerOutput* viewer_node_;
Sequence* viewer_node_;
Project copied_project_;
QVector<QueuedJob> graph_update_queue_;
QHash<Node*, Node*> copy_map_;
ViewerOutput* copied_viewer_node_;
Sequence* copied_viewer_node_;
bool paused_;
+1 -2
View File
@@ -22,7 +22,6 @@
#define RENDERCACHE_H
#include "codec/decoder.h"
#include "project/item/footage/stream.h"
namespace olive {
@@ -40,7 +39,7 @@ private:
};
using DecoderCache = RenderCache<Stream*, DecoderPtr>;
using DecoderCache = RenderCache<Decoder::CodecStream, DecoderPtr>;
using ShaderCache = RenderCache<QString, QVariant>;
}
+1
View File
@@ -21,6 +21,7 @@
#ifndef RENDERCONTEXT_H
#define RENDERCONTEXT_H
#include <QMutex>
#include <QObject>
#include <QVariant>
+5 -5
View File
@@ -94,13 +94,13 @@ QByteArray RenderManager::Hash(const Node *n, const VideoParams &params, const r
hasher.addData(reinterpret_cast<const char*>(&format), sizeof(VideoParams::Format));
if (n) {
n->Hash(hasher, time);
n->Hash(Node::kDefaultOutput, hasher, time);
}
return hasher.result();
}
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* color_manager,
RenderTicketPtr RenderManager::RenderFrame(Sequence* viewer, ColorManager* color_manager,
const rational& time, RenderMode::Mode mode,
FrameHashCache* cache, bool prioritize)
{
@@ -118,7 +118,7 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* c
prioritize);
}
RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* color_manager,
RenderTicketPtr RenderManager::RenderFrame(Sequence* viewer, ColorManager* color_manager,
const rational& time, RenderMode::Mode mode,
const VideoParams &video_params, const AudioParams &audio_params,
const QSize& force_size,
@@ -157,12 +157,12 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput* viewer, ColorManager* c
return ticket;
}
RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange& r, bool generate_waveforms, bool prioritize)
RenderTicketPtr RenderManager::RenderAudio(Sequence* viewer, const TimeRange& r, bool generate_waveforms, bool prioritize)
{
return RenderAudio(viewer, r, viewer->audio_params(), generate_waveforms, prioritize);
}
RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange &r, const AudioParams &params, bool generate_waveforms, bool prioritize)
RenderTicketPtr RenderManager::RenderAudio(Sequence* viewer, const TimeRange &r, const AudioParams &params, bool generate_waveforms, bool prioritize)
{
// Create ticket
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
+4 -4
View File
@@ -80,10 +80,10 @@ public:
*
* This function is thread-safe.
*/
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager,
RenderTicketPtr RenderFrame(Sequence *viewer, ColorManager* color_manager,
const rational& time, RenderMode::Mode mode,
FrameHashCache* cache = nullptr, bool prioritize = false);
RenderTicketPtr RenderFrame(ViewerOutput* viewer, ColorManager* color_manager,
RenderTicketPtr RenderFrame(Sequence* viewer, ColorManager* color_manager,
const rational& time, RenderMode::Mode mode,
const VideoParams& video_params, const AudioParams& audio_params,
const QSize& force_size,
@@ -101,8 +101,8 @@ public:
*
* This function is thread-safe.
*/
RenderTicketPtr RenderAudio(ViewerOutput* viewer, const TimeRange& r, const AudioParams& params, bool generate_waveforms, bool prioritize = false);
RenderTicketPtr RenderAudio(ViewerOutput* viewer, const TimeRange& r, bool generate_waveforms, bool prioritize = false);
RenderTicketPtr RenderAudio(Sequence* viewer, const TimeRange& r, const AudioParams& params, bool generate_waveforms, bool prioritize = false);
RenderTicketPtr RenderAudio(Sequence *viewer, const TimeRange& r, bool generate_waveforms, bool prioritize = false);
RenderTicketPtr SaveFrameToCache(FrameHashCache* cache, FramePtr frame, const QByteArray& hash, bool prioritize = false);
+54 -27
View File
@@ -54,11 +54,11 @@ void RenderProcessor::Run()
switch (type) {
case RenderManager::kTypeVideo:
{
ViewerOutput* viewer = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"));
Sequence* viewer = Node::ValueToPtr<Sequence>(ticket_->property("viewer"));
const VideoParams& video_params = ticket_->property("vparam").value<VideoParams>();
rational time = ticket_->property("time").value<rational>();
NodeValueTable table = ProcessInput(viewer, ViewerOutput::kTextureInput,
NodeValueTable table = ProcessInput(viewer, Sequence::kTextureInput,
TimeRange(time, time + video_params.time_base()));
TexturePtr texture = table.Get(NodeValue::kTexture).value<TexturePtr>();
@@ -130,10 +130,10 @@ void RenderProcessor::Run()
}
case RenderManager::kTypeAudio:
{
ViewerOutput* viewer = Node::ValueToPtr<ViewerOutput>(ticket_->property("viewer"));
Sequence* viewer = Node::ValueToPtr<Sequence>(ticket_->property("viewer"));
TimeRange time = ticket_->property("time").value<TimeRange>();
NodeValueTable table = ProcessInput(viewer, ViewerOutput::kSamplesInput, time);
NodeValueTable table = ProcessInput(viewer, Sequence::kSamplesInput, time);
ticket_->Finish(table.Get(NodeValue::kSamples), IsCancelled());
break;
@@ -153,9 +153,9 @@ void RenderProcessor::Run()
}
}
DecoderPtr RenderProcessor::ResolveDecoderFromInput(Stream *stream)
DecoderPtr RenderProcessor::ResolveDecoderFromInput(const QString& decoder_id, const Decoder::CodecStream &stream)
{
if (!stream) {
if (!stream.IsValid()) {
qWarning() << "Attempted to resolve the decoder of a null stream";
return nullptr;
}
@@ -166,13 +166,13 @@ DecoderPtr RenderProcessor::ResolveDecoderFromInput(Stream *stream)
if (!decoder) {
// No decoder
decoder = Decoder::CreateFromID(stream->footage()->decoder());
decoder = Decoder::CreateFromID(decoder_id);
if (decoder->Open(stream)) {
decoder_cache_->insert(stream, decoder);
} else {
qWarning() << "Failed to open decoder for" << stream->footage()->filename()
<< "::" << stream->index();
qWarning() << "Failed to open decoder for" << stream.filename()
<< "::" << stream.stream();
return nullptr;
}
}
@@ -262,32 +262,35 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
}
}
QVariant RenderProcessor::ProcessVideoFootage(VideoStream *video_stream, const rational &input_time)
QVariant RenderProcessor::ProcessVideoFootage(const Footage::StreamReference &stream, const rational &input_time)
{
TexturePtr value = nullptr;
// Check the still frame cache. On large frames such as high resolution still images, uploading
// and color managing them for every frame is a waste of time, so we implement a small cache here
// to optimize such a situation
const VideoParams& video_params = ticket_->property("vparam").value<VideoParams>();
const VideoParams& render_params = ticket_->property("vparam").value<VideoParams>();
VideoParams stream_params = stream.video_params();
ColorManager* color_manager = Node::ValueToPtr<ColorManager>(ticket_->property("colormanager"));
// See if we can make this divider larger (i.e. if the fooage is smaller)
int footage_divider = video_params.divider();
int footage_divider = render_params.divider();
while (footage_divider > 1
&& VideoParams::GetScaledDimension(video_stream->width(), footage_divider-1) < video_params.effective_width()
&& VideoParams::GetScaledDimension(video_stream->height(), footage_divider-1) < video_params.effective_height()) {
&& VideoParams::GetScaledDimension(stream_params.width(), footage_divider-1) < render_params.effective_width()
&& VideoParams::GetScaledDimension(stream_params.height(), footage_divider-1) < render_params.effective_height()) {
footage_divider--;
}
Stream stream_data = stream.GetStream();
StillImageCache::EntryPtr want_entry = std::make_shared<StillImageCache::Entry>(
nullptr,
video_stream,
ColorProcessor::GenerateID(color_manager, video_stream->colorspace(), color_manager->GetReferenceColorSpace()),
video_stream->premultiplied_alpha(),
stream,
ColorProcessor::GenerateID(color_manager, stream.video_colorspace(), color_manager->GetReferenceColorSpace()),
stream_data.premultiplied_alpha(),
footage_divider,
(video_stream->video_type() == VideoStream::kVideoTypeStill) ? 0 : input_time,
(stream_data.video_type() == Stream::kVideoTypeStill) ? 0 : input_time,
true);
bool found_existing = false;
@@ -324,11 +327,31 @@ QVariant RenderProcessor::ProcessVideoFootage(VideoStream *video_stream, const r
still_image_cache_->mutex()->unlock();
DecoderPtr decoder = ResolveDecoderFromInput(video_stream);
QString decoder_id = stream.footage()->decoder();
DecoderPtr decoder = nullptr;
if (stream_data.video_type() == Stream::kVideoTypeVideo) {
decoder = ResolveDecoderFromInput(decoder_id, Decoder::GetCodecStreamFromStreamReference(stream));
} else {
// Since image sequences involve multiple files, we don't engage the decoder cache
decoder = Decoder::CreateFromID(decoder_id);
QString frame_filename;
if (stream_data.video_type() == Stream::kVideoTypeImageSequence) {
int64_t frame_number = stream.GetTimeInTimebaseUnits(input_time);
frame_filename = Decoder::TransformImageSequenceFileName(stream.filename(), frame_number);
} else {
frame_filename = stream.filename();
}
// Decoder will close automatically since it's a stream_ptr
decoder->Open(Decoder::CodecStream(frame_filename, stream.index()));
}
if (decoder) {
FramePtr frame = decoder->RetrieveVideo(input_time,
footage_divider);
FramePtr frame = decoder->RetrieveVideo((stream_data.video_type() == Stream::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, footage_divider);
if (frame) {
// Return a texture from the derived class
@@ -339,15 +362,17 @@ QVariant RenderProcessor::ProcessVideoFootage(VideoStream *video_stream, const r
// We convert to our rendering pixel format, since that will always be float-based which
// is necessary for correct color conversion
VideoParams managed_params = frame->video_params();
managed_params.set_format(video_params.format());
managed_params.set_format(render_params.format());
managed_params.set_pixel_aspect_ratio(stream_data.pixel_aspect_ratio());
managed_params.set_interlacing(stream_data.interlacing());
value = render_ctx_->CreateTexture(managed_params);
ColorProcessorPtr processor = ColorProcessor::Create(color_manager,
video_stream->colorspace(),
stream.video_colorspace(),
color_manager->GetReferenceColorSpace());
render_ctx_->BlitColorManaged(processor, unmanaged_texture,
video_stream->premultiplied_alpha(),
stream_data.premultiplied_alpha(),
value.get());
still_image_cache_->mutex()->lock();
@@ -366,16 +391,18 @@ QVariant RenderProcessor::ProcessVideoFootage(VideoStream *video_stream, const r
return QVariant::fromValue(value);
}
QVariant RenderProcessor::ProcessAudioFootage(AudioStream *stream, const TimeRange &input_time)
QVariant RenderProcessor::ProcessAudioFootage(const Footage::StreamReference &stream, const TimeRange &input_time)
{
QVariant value;
DecoderPtr decoder = ResolveDecoderFromInput(stream);
DecoderPtr decoder = ResolveDecoderFromInput(stream.footage()->decoder(), Decoder::GetCodecStreamFromStreamReference(stream));
if (decoder) {
const AudioParams& audio_params = ticket_->property("aparam").value<AudioParams>();
SampleBufferPtr frame = decoder->RetrieveAudio(input_time, audio_params, &IsCancelled());
SampleBufferPtr frame = decoder->RetrieveAudio(input_time, audio_params,
stream.footage()->project()->cache_path(),
&IsCancelled());
if (frame) {
value = QVariant::fromValue(frame);
+3 -3
View File
@@ -43,9 +43,9 @@ public:
protected:
virtual NodeValueTable GenerateBlockTable(const Track *track, const TimeRange &range) override;
virtual QVariant ProcessVideoFootage(VideoStream* video_stream, const rational &input_time) override;
virtual QVariant ProcessVideoFootage(const Footage::StreamReference &stream, const rational &input_time) override;
virtual QVariant ProcessAudioFootage(AudioStream* stream, const TimeRange &input_time) override;
virtual QVariant ProcessAudioFootage(const Footage::StreamReference &stream, const TimeRange &input_time) override;
virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override;
@@ -62,7 +62,7 @@ private:
void Run();
DecoderPtr ResolveDecoderFromInput(Stream* stream);
DecoderPtr ResolveDecoderFromInput(const QString &decoder_id, const Decoder::CodecStream& stream);
RenderTicketPtr ticket_;
+3 -3
View File
@@ -5,7 +5,7 @@
#include <QWaitCondition>
#include "common/rational.h"
#include "project/item/footage/videostream.h"
#include "project/item/footage/footage.h"
#include "render/texture.h"
namespace olive {
@@ -14,7 +14,7 @@ class StillImageCache
{
public:
struct Entry {
Entry(TexturePtr t, VideoStream* s, const QString& cs, bool a, int d, const rational& i, bool w)
Entry(TexturePtr t, const Footage::StreamReference& s, const QString& cs, bool a, int d, const rational& i, bool w)
{
texture = t;
stream = s;
@@ -26,7 +26,7 @@ public:
}
TexturePtr texture;
VideoStream* stream;
Footage::StreamReference stream;
QString colorspace;
bool alpha_is_associated;
int divider;