render one frame per thread for increased parallelism

If the nodes are now stateless, there's nothing stopping the renderer from
rendering multiple frames at once. Earlier since the nodes held some of their
input/output data (and that data could change per frame), it was not possible
to render multiple frames at once without conflicts. Now that the node state is
held in render threads, they can do whatever they want at any time.
This commit is contained in:
itsmattkc
2019-12-06 15:37:31 +11:00
parent 33f73e0e90
commit 5227e10f39
29 changed files with 201 additions and 182 deletions
+2 -2
View File
@@ -283,7 +283,7 @@ void NodeInput::set_maximum(const QVariant &max)
has_maximum_ = true;
}
void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_connections)
void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_connections, bool lock_connections)
{
Q_ASSERT(source->id() == dest->id());
@@ -295,7 +295,7 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn
// Copy connections
if (include_connections && source->get_connected_output() != nullptr) {
ConnectEdge(source->get_connected_output(), dest);
ConnectEdge(source->get_connected_output(), dest, lock_connections);
}
// If these inputs are an array, copy the subparams too
+1 -1
View File
@@ -121,7 +121,7 @@ public:
/**
* @brief Copy all values including keyframe information and connections from another NodeInput
*/
static void CopyValues(NodeInput* source, NodeInput* dest, bool include_connections = true);
static void CopyValues(NodeInput* source, NodeInput* dest, bool include_connections = true, bool lock_connections = true);
signals:
void ValueChanged(const rational& start, const rational& end);
+1 -1
View File
@@ -182,7 +182,7 @@ void Node::CopyInputs(Node *source, Node *destination, bool include_connections)
if (src->dependent()) {
NodeInput* dst = static_cast<NodeInput*>(dst_param.at(i));
NodeInput::CopyValues(src, dst, include_connections);
NodeInput::CopyValues(src, dst, include_connections, false);
}
}
}
+9 -5
View File
@@ -103,7 +103,7 @@ void NodeParam::DisconnectAll()
}
}
NodeEdgePtr NodeParam::ConnectEdge(NodeOutput *output, NodeInput *input)
NodeEdgePtr NodeParam::ConnectEdge(NodeOutput *output, NodeInput *input, bool lock)
{
// If the input can only accept one input (the default) and has one already, disconnect it
DisconnectForNewOutput(input);
@@ -127,14 +127,18 @@ NodeEdgePtr NodeParam::ConnectEdge(NodeOutput *output, NodeInput *input)
// that's difficult to diagnose. This makes that issue very clear.
Q_ASSERT(output->parentNode() != input->parentNode());
output->parentNode()->LockUserInput();
input->parentNode()->LockUserInput();
if (lock) {
output->parentNode()->LockUserInput();
input->parentNode()->LockUserInput();
}
output->edges_.append(edge);
input->edges_.append(edge);
output->parentNode()->UnlockUserInput();
input->parentNode()->UnlockUserInput();
if (lock) {
output->parentNode()->UnlockUserInput();
input->parentNode()->UnlockUserInput();
}
// Emit a signal than an edge was added (only one signal needs emitting)
emit input->EdgeAdded(edge);
+1 -1
View File
@@ -292,7 +292,7 @@ public:
*
* This function emits EdgeAdded().
*/
static NodeEdgePtr ConnectEdge(NodeOutput *output, NodeInput *input);
static NodeEdgePtr ConnectEdge(NodeOutput *output, NodeInput *input, bool lock = true);
/**
* @brief Disconnect an edge
+1 -3
View File
@@ -37,7 +37,7 @@ bool AudioBackend::InitInternal()
// Initiate one thread per CPU core
for (int i=0;i<threads().size();i++) {
// Create one processor object for each thread
AudioWorker* processor = new AudioWorker(decoder_cache());
AudioWorker* processor = new AudioWorker();
processor->SetParameters(params());
processors_.append(processor);
}
@@ -67,8 +67,6 @@ void AudioBackend::ConnectWorkerToThis(RenderWorker *worker)
void AudioBackend::ThreadCompletedCache(NodeDependency dep, NodeValueTable data)
{
caching_ = false;
QByteArray cached_samples = data.Get(NodeParam::kSamples).toByteArray();
int offset = params().time_to_bytes(dep.in());
+3 -2
View File
@@ -1,12 +1,13 @@
#include "audioworker.h"
AudioWorker::AudioWorker(DecoderCache *decoder_cache, QObject *parent) :
AudioRenderWorker(decoder_cache, parent)
AudioWorker::AudioWorker(QObject *parent) :
AudioRenderWorker(parent)
{
}
void AudioWorker::FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable *table)
{
Q_UNUSED(stream)
table->Push(NodeParam::kSamples, frame->ToByteArray());
}
+1 -1
View File
@@ -6,7 +6,7 @@
class AudioWorker : public AudioRenderWorker
{
public:
AudioWorker(DecoderCache* decoder_cache, QObject* parent = nullptr);
AudioWorker(QObject* parent = nullptr);
protected:
virtual void FrameToValue(StreamPtr stream, FramePtr frame, NodeValueTable* table) override;
@@ -29,6 +29,8 @@ void AudioRenderBackend::SetParameters(const AudioRenderingParams &params)
void AudioRenderBackend::InvalidateCache(const rational &start_range, const rational &end_range)
{
RenderBackend::InvalidateCache(start_range, end_range);
rational start_range_adj = qMax(rational(0), start_range);
rational end_range_adj = qMin(SequenceLength(), end_range);
+2 -2
View File
@@ -2,8 +2,8 @@
#include "audio/audiomanager.h"
AudioRenderWorker::AudioRenderWorker(DecoderCache *decoder_cache, QObject *parent) :
RenderWorker(decoder_cache, parent)
AudioRenderWorker::AudioRenderWorker(QObject *parent) :
RenderWorker(parent)
{
}
+1 -1
View File
@@ -7,7 +7,7 @@ class AudioRenderWorker : public RenderWorker
{
Q_OBJECT
public:
AudioRenderWorker(DecoderCache* decoder_cache, QObject* parent = nullptr);
AudioRenderWorker(QObject* parent = nullptr);
void SetParameters(const AudioRenderingParams& audio_params);
+1 -1
View File
@@ -5,6 +5,6 @@
#include "project/item/footage/stream.h"
#include "rendercache.h"
using DecoderCache = RenderCache<Stream*, DecoderPtr>;
using DecoderCache = ThreadSafeRenderCache<Stream*, DecoderPtr>;
#endif // DECODERCACHE_H
-1
View File
@@ -27,7 +27,6 @@ set(OLIVE_SOURCES
render/backend/opengl/openglshader.h
render/backend/opengl/openglshader.cpp
render/backend/opengl/openglshadercache.h
render/backend/opengl/openglshadercache.cpp
render/backend/opengl/opengltexture.h
render/backend/opengl/opengltexture.cpp
render/backend/opengl/openglworker.h
+15 -8
View File
@@ -31,7 +31,7 @@ bool OpenGLBackend::InitInternal()
// Initiate one thread per CPU core
for (int i=0;i<threads().size();i++) {
// Create one processor object for each thread
OpenGLWorker* processor = new OpenGLWorker(share_ctx, &shader_cache_, decoder_cache(), color_cache(), frame_cache());
OpenGLWorker* processor = new OpenGLWorker(share_ctx, &shader_cache_, frame_cache());
processor->SetParameters(params());
processors_.append(processor);
}
@@ -76,14 +76,14 @@ bool OpenGLBackend::CompileInternal()
foreach (Node* n, nodes) {
// Check if we have a shader or not
if (!shader_cache_.HasShader(n)) {
if (!shader_cache_.Has(n->id())) {
// Since we don't have a shader, compile one now
QString node_code = n->Code();
// If the node has no code, it mustn't be GPU accelerated
if (node_code.isEmpty()) {
// We enter a null shader so we don't try to compile this again
shader_cache_.AddShader(n, nullptr);
shader_cache_.Add(n->id(), nullptr);
} else {
// Since we have shader code, compile it now
OpenGLShaderPtr program;
@@ -113,7 +113,7 @@ bool OpenGLBackend::CompileInternal()
return false;
}
shader_cache_.AddShader(n, program);
shader_cache_.Add(n->id(), program);
//qDebug() << "Compiled" << connected_output->parent()->id() << "->" << connected_output->id();
}
@@ -166,26 +166,33 @@ void OpenGLBackend::ThreadCompletedFrame(NodeDependency path, QByteArray hash, N
emit CachedFrameReady(path.in(), value);
}
CompletedFrame();
// Queue up a new frame for this worker
CacheNext();
}
void OpenGLBackend::ThreadCompletedDownload(NodeDependency dep, QByteArray hash)
{
frame_cache()->SetHash(dep.in(), hash);
emit CachedTimeReady(dep.in());
// Emit for each frame that has this hash (some may have been added in ThreadSkippedFrame)
QList<rational> times_with_this_hash = frame_cache()->TimesWithHash(hash);
foreach (const rational& t, times_with_this_hash) {
emit CachedTimeReady(t);
}
}
void OpenGLBackend::ThreadSkippedFrame(NodeDependency dep, QByteArray hash)
{
frame_cache()->SetHash(dep.in(), hash);
CompletedFrame();
// Queue up a new frame for this worker
CacheNext();
}
void OpenGLBackend::ThreadHashAlreadyExists(NodeDependency dep, QByteArray hash)
{
ThreadCompletedDownload(dep, hash);
CompletedFrame();
// Queue up a new frame for this worker
CacheNext();
}
@@ -1,28 +0,0 @@
#include "openglshadercache.h"
#include "node/node.h"
void OpenGLShaderCache::Clear()
{
compiled_nodes_.clear();
}
void OpenGLShaderCache::AddShader(Node *output, OpenGLShaderPtr shader)
{
compiled_nodes_.insert(GenerateShaderID(output), shader);
}
OpenGLShaderPtr OpenGLShaderCache::GetShader(Node *output)
{
return compiled_nodes_.value(GenerateShaderID(output));
}
QString OpenGLShaderCache::GenerateShaderID(Node *output)
{
return output->id();
}
bool OpenGLShaderCache::HasShader(Node *output)
{
return compiled_nodes_.contains(GenerateShaderID(output));
}
+3 -24
View File
@@ -1,32 +1,11 @@
#ifndef OPENGLSHADERCACHE_H
#define OPENGLSHADERCACHE_H
#include <QMutex>
#include <QString>
#include "node/output.h"
#include "openglshader.h"
#include "render/backend/rendercache.h"
/**
* @brief Thread-safe cache of OpenGL shaders
*/
class OpenGLShaderCache
{
public:
OpenGLShaderCache() = default;
void Clear();
void AddShader(Node* output, OpenGLShaderPtr shader);
OpenGLShaderPtr GetShader(Node* output);
bool HasShader(Node* output);
private:
QString GenerateShaderID(Node *output);
QMap<QString, OpenGLShaderPtr> compiled_nodes_;
};
using OpenGLShaderCache = RenderCache<QString, OpenGLShaderPtr>;
#endif // OPENGLSHADERCACHE_H
+3 -3
View File
@@ -7,8 +7,8 @@
#include "render/colormanager.h"
#include "render/pixelservice.h"
OpenGLWorker::OpenGLWorker(QOpenGLContext *share_ctx, OpenGLShaderCache *shader_cache, DecoderCache *decoder_cache, ColorProcessorCache *color_cache, VideoRenderFrameCache *frame_cache, QObject *parent) :
VideoRenderWorker(decoder_cache, color_cache, frame_cache, parent),
OpenGLWorker::OpenGLWorker(QOpenGLContext *share_ctx, OpenGLShaderCache *shader_cache, VideoRenderFrameCache *frame_cache, QObject *parent) :
VideoRenderWorker(frame_cache, parent),
share_ctx_(share_ctx),
ctx_(nullptr),
functions_(nullptr),
@@ -143,7 +143,7 @@ void OpenGLWorker::ParametersChangedEvent()
void OpenGLWorker::RunNodeAccelerated(Node *node, const NodeValueDatabase *input_params, NodeValueTable *output_params)
{
OpenGLShaderPtr shader = shader_cache_->GetShader(node);
OpenGLShaderPtr shader = shader_cache_->Get(node->id());
if (!shader) {
return;
-2
View File
@@ -13,8 +13,6 @@ class OpenGLWorker : public VideoRenderWorker {
public:
OpenGLWorker(QOpenGLContext* share_ctx,
OpenGLShaderCache* shader_cache,
DecoderCache* decoder_cache,
ColorProcessorCache *color_cache,
VideoRenderFrameCache* frame_cache,
QObject* parent = nullptr);
+64 -39
View File
@@ -6,12 +6,12 @@
RenderBackend::RenderBackend(QObject *parent) :
QObject(parent),
compiled_(false),
caching_(false),
started_(false),
viewer_node_(nullptr),
copied_viewer_node_(nullptr),
value_update_queued_(false),
recompile_queued_(false)
recompile_queued_(false),
input_update_queued_(false)
{
}
@@ -53,17 +53,22 @@ void RenderBackend::Close()
CloseInternal();
decoder_cache_.Clear();
for (int i=0;i<processors_.size();i++) {
// Invoke close and quit signals on processor and thred
QMetaObject::invokeMethod(processors_.at(i),
"Close",
Qt::QueuedConnection);
foreach (QThread* thread, threads_) {
thread->quit();
thread->wait(); // FIXME: Maximum time in case a thread is stuck?
threads_.at(i)->quit();
}
for (int i=0;i<processors_.size();i++) {
threads_.at(i)->wait(); // FIXME: Maximum time in case a thread is stuck?
delete threads_.at(i);
delete processors_.at(i);
}
threads_.clear();
foreach (RenderWorker* processor, processors_) {
delete processor;
}
processors_.clear();
}
@@ -100,12 +105,17 @@ bool RenderBackend::IsInitiated()
return started_;
}
void RenderBackend::InvalidateCache(const rational &start_range, const rational &end_range)
{
Q_UNUSED(start_range)
Q_UNUSED(end_range)
input_update_queued_ = true;
}
bool RenderBackend::Compile()
{
if (recompile_queued_) {
Decompile();
recompile_queued_ = false;
} else if (compiled_) {
if (compiled_) {
return true;
}
@@ -199,39 +209,48 @@ void RenderBackend::DisconnectViewer(ViewerOutput *node)
void RenderBackend::CacheNext()
{
if (!Init() || cache_queue_.isEmpty() || !ViewerIsConnected() || caching_) {
if (!Init()
|| cache_queue_.isEmpty()
|| !ViewerIsConnected()) {
return;
}
UpdateNodeInputs();
TimeRange cache_frame = cache_queue_.takeFirst();
//qDebug() << "Caching" << cache_frame.in();
caching_ = GenerateData(cache_frame);
}
bool RenderBackend::GenerateData(const TimeRange &range)
{
if (!Compile()) {
qDebug() << "Graph remains uncompiled, nothing to be done";
return false;
if ((input_update_queued_ || recompile_queued_) && !AllProcessorsAreAvailable()) {
qDebug() << "Blocking render while we wait for all workers to finish...";
return;
}
NodeDependency dep = NodeDependency(GetDependentInput()->get_connected_node(), range.in(), range.out());
if (input_update_queued_) {
UpdateNodeInputs();
input_update_queued_ = false;
}
if (recompile_queued_) {
Decompile();
recompile_queued_ = false;
}
if (!compiled_ && !Compile()) {
qDebug() << "Graph remains uncompiled, nothing to be done";
return;
}
foreach (RenderWorker* worker, processors_) {
if (worker->IsAvailable() || worker == processors_.last()) {
if (cache_queue_.isEmpty()) {
break;
}
if (worker->IsAvailable()) {
TimeRange cache_frame = cache_queue_.takeFirst();
NodeDependency dep = NodeDependency(GetDependentInput()->get_connected_node(), cache_frame.in(), cache_frame.out());
QMetaObject::invokeMethod(worker,
"Render",
Qt::QueuedConnection,
Q_ARG(NodeDependency, dep));
return true;
}
}
return false;
}
ViewerOutput *RenderBackend::viewer_node() const
@@ -244,11 +263,6 @@ bool RenderBackend::ViewerIsConnected() const
return viewer_node_ != nullptr;
}
DecoderCache *RenderBackend::decoder_cache()
{
return &decoder_cache_;
}
const QString &RenderBackend::cache_id() const
{
return cache_id_;
@@ -274,6 +288,17 @@ void RenderBackend::UpdateNodeInputs()
}
}
bool RenderBackend::AllProcessorsAreAvailable() const
{
foreach (RenderWorker* worker, processors_) {
if (!worker->IsAvailable()) {
return false;
}
}
return true;
}
const QVector<QThread *> &RenderBackend::threads()
{
return threads_;
+4 -9
View File
@@ -30,7 +30,7 @@ public:
bool IsInitiated();
public slots:
virtual void InvalidateCache(const rational &start_range, const rational &end_range) = 0;
virtual void InvalidateCache(const rational &start_range, const rational &end_range);
bool Compile();
@@ -70,8 +70,6 @@ protected:
*/
void CacheNext();
bool GenerateData(const TimeRange& range);
void InitWorkers();
virtual NodeInput* GetDependentInput() = 0;
@@ -82,8 +80,6 @@ protected:
bool ViewerIsConnected() const;
DecoderCache* decoder_cache();
const QString& cache_id() const;
void QueueValueUpdate(const TimeRange& range);
@@ -96,9 +92,9 @@ protected:
bool compiled_;
bool caching_;
private:
bool AllProcessorsAreAvailable() const;
/**
* @brief Internal list of RenderProcessThreads
*/
@@ -124,8 +120,6 @@ private:
*/
QString error_;
DecoderCache decoder_cache_;
QString cache_name_;
qint64 cache_time_;
QString cache_id_;
@@ -137,6 +131,7 @@ private:
TimeRange value_update_range_;
bool recompile_queued_;
bool input_update_queued_;
private slots:
void ThreadRequestedSibling(NodeDependency dep);
+44 -2
View File
@@ -2,6 +2,7 @@
#define RENDERCACHE_H
#include <QMap>
#include <QMutex>
template<class K, class V>
class RenderCache
@@ -11,12 +12,53 @@ public:
void Clear(){values_.clear();}
void Add(K stream, V shader){values_.insert(stream, shader);}
void Add(K key, V val){values_.insert(key, val);}
V Get(K stream){return values_.value(stream);}
V Get(K key) const {return values_.value(key);}
bool Has(K key) const {return values_.contains(key);}
private:
QMap<K, V> values_;
};
template<class K, class V>
class ThreadSafeRenderCache
{
public:
ThreadSafeRenderCache() = default;
void Clear() {
lock_.lock();
values_.clear();
lock_.unlock();
}
void Add(K key, V val) {
lock_.lock();
values_.insert(key, val);
lock_.unlock();
}
V Get(K key) {
lock_.lock();
V val = values_.value(key);
lock_.unlock();
return val;
}
bool Has(K key) {
lock_.lock();
bool has = values_.contains(key);
lock_.unlock();
return has;
}
private:
QMap<K, V> values_;
QMutex lock_;
};
#endif // RENDERCACHE_H
+8 -12
View File
@@ -4,17 +4,16 @@
#include "node/block/block.h"
RenderWorker::RenderWorker(DecoderCache *decoder_cache, QObject *parent) :
RenderWorker::RenderWorker(QObject *parent) :
QObject(parent),
working_(0),
started_(false),
decoder_cache_(decoder_cache)
started_(false)
{
}
bool RenderWorker::IsAvailable()
{
return (working_ == 0);
return !working_;
}
bool RenderWorker::Init()
@@ -34,6 +33,8 @@ void RenderWorker::Close()
{
CloseInternal();
decoder_cache_.Clear();
started_ = false;
}
@@ -70,11 +71,6 @@ NodeValueTable RenderWorker::RenderAsSibling(NodeDependency dep)
return value;
}
DecoderCache *RenderWorker::decoder_cache()
{
return decoder_cache_;
}
NodeValueTable RenderWorker::RenderInternal(const NodeDependency &path)
{
return RenderAsSibling(path);
@@ -101,13 +97,13 @@ StreamPtr RenderWorker::ResolveStreamFromInput(NodeInput *input)
DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream)
{
// Access a map of Node inputs and decoder instances and retrieve a frame!
DecoderPtr decoder = decoder_cache()->Get(stream.get());
DecoderPtr decoder = decoder_cache_.Get(stream.get());
if (decoder == nullptr && stream != nullptr) {
// Create a new Decoder here
DecoderPtr decoder = Decoder::CreateFromID(stream->footage()->decoder());
decoder = Decoder::CreateFromID(stream->footage()->decoder());
decoder->set_stream(stream);
decoder_cache()->Add(stream.get(), decoder);
decoder_cache_.Add(stream.get(), decoder);
}
return decoder;
+2 -4
View File
@@ -12,7 +12,7 @@ class RenderWorker : public QObject
{
Q_OBJECT
public:
RenderWorker(DecoderCache* decoder_cache, QObject* parent = nullptr);
RenderWorker(QObject* parent = nullptr);
DISABLE_COPY_MOVE(RenderWorker)
@@ -56,14 +56,12 @@ protected:
virtual NodeValueTable RenderBlock(TrackOutput *track, const TimeRange& range) = 0;
DecoderCache* decoder_cache();
QAtomicInt working_;
private:
bool started_;
DecoderCache* decoder_cache_;
DecoderCache decoder_cache_;
};
+2 -11
View File
@@ -43,6 +43,8 @@ void VideoRenderBackend::InvalidateCache(const rational &start_range, const rati
return;
}
RenderBackend::InvalidateCache(start_range, end_range);
// Adjust range to min/max values
rational start_range_adj = qMax(rational(0), start_range);
rational end_range_adj = qMin(SequenceLength(), end_range);
@@ -185,11 +187,6 @@ VideoRenderFrameCache *VideoRenderBackend::frame_cache()
return &frame_cache_;
}
ColorProcessorCache *VideoRenderBackend::color_cache()
{
return &color_cache_;
}
const char *VideoRenderBackend::GetCachedFrame(const rational &time)
{
last_time_requested_ = time;
@@ -237,9 +234,3 @@ NodeInput *VideoRenderBackend::GetDependentInput()
{
return viewer_node()->texture_input();
}
void VideoRenderBackend::CompletedFrame()
{
caching_ = false;
CacheNext();
}
-6
View File
@@ -82,8 +82,6 @@ protected:
VideoRenderFrameCache* frame_cache();
ColorProcessorCache* color_cache();
const VideoRenderingParams& params() const;
/**
@@ -95,8 +93,6 @@ protected:
virtual void ConnectWorkerToThis(RenderWorker* processor) override;
void CompletedFrame();
signals:
void CachedFrameReady(const rational& time, QVariant value);
void CachedTimeReady(const rational& time);
@@ -108,8 +104,6 @@ private:
VideoRenderFrameCache frame_cache_;
ColorProcessorCache color_cache_;
rational last_time_requested_;
private slots:
+17 -2
View File
@@ -46,7 +46,7 @@ void VideoRenderFrameCache::SetCacheID(const QString &id)
cache_id_ = id;
}
QByteArray VideoRenderFrameCache::TimeToHash(const rational &time)
QByteArray VideoRenderFrameCache::TimeToHash(const rational &time) const
{
return time_hash_map_.value(time);
}
@@ -80,6 +80,21 @@ void VideoRenderFrameCache::Truncate(const rational &time)
}
}
QList<rational> VideoRenderFrameCache::TimesWithHash(const QByteArray &hash)
{
QList<rational> list;
QMap<rational, QByteArray>::const_iterator iterator;
for (iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) {
if (iterator.value() == hash) {
list.append(iterator.key());
}
}
return list;
}
void VideoRenderFrameCache::RemoveHashFromCurrentlyCaching(const QByteArray &hash)
{
currently_caching_lock_.lock();
@@ -87,7 +102,7 @@ void VideoRenderFrameCache::RemoveHashFromCurrentlyCaching(const QByteArray &has
currently_caching_lock_.unlock();
}
QString VideoRenderFrameCache::CachePathName(const QByteArray &hash)
QString VideoRenderFrameCache::CachePathName(const QByteArray &hash) const
{
QDir this_cache_dir = QDir(GetMediaCacheLocation()).filePath(cache_id_);
this_cache_dir.mkpath(".");
+4 -2
View File
@@ -28,17 +28,19 @@ public:
/**
* @brief Return the path of the cached image at this time
*/
QString CachePathName(const QByteArray &hash);
QString CachePathName(const QByteArray &hash) const;
void SetCacheID(const QString& id);
QByteArray TimeToHash(const rational& time);
QByteArray TimeToHash(const rational& time) const;
void SetHash(const rational& time, const QByteArray& hash);
void RemoveHash(const rational& time, const QByteArray &hash);
void Truncate(const rational& time);
QList<rational> TimesWithHash(const QByteArray& hash);
private:
void RemoveHashFromCurrentlyCaching(const QByteArray& hash);
+7 -6
View File
@@ -4,10 +4,9 @@
#include "node/node.h"
#include "render/pixelservice.h"
VideoRenderWorker::VideoRenderWorker(DecoderCache *decoder_cache, ColorProcessorCache *color_cache, VideoRenderFrameCache *frame_cache, QObject *parent) :
RenderWorker(decoder_cache, parent),
frame_cache_(frame_cache),
color_cache_(color_cache)
VideoRenderWorker::VideoRenderWorker(VideoRenderFrameCache *frame_cache, QObject *parent) :
RenderWorker(parent),
frame_cache_(frame_cache)
{
}
@@ -19,6 +18,8 @@ const VideoRenderingParams &VideoRenderWorker::video_params()
NodeValueTable VideoRenderWorker::RenderInternal(const NodeDependency& path)
{
qDebug() << "Rendering" << path.in().toDouble() << "on" << this;
// Get hash of node graph
// We use SHA-1 for speed (benchmarks show it's the fastest hash available to us)
QCryptographicHash hasher(QCryptographicHash::Sha1);
@@ -182,7 +183,7 @@ NodeValueTable VideoRenderWorker::RenderBlock(TrackOutput *track, const TimeRang
return table;
}
ColorProcessorCache *VideoRenderWorker::color_cache() const
ColorProcessorCache *VideoRenderWorker::color_cache()
{
return color_cache_;
return &color_cache_;
}
+3 -3
View File
@@ -12,7 +12,7 @@
class VideoRenderWorker : public RenderWorker {
Q_OBJECT
public:
VideoRenderWorker(DecoderCache* decoder_cache, ColorProcessorCache* color_cache, VideoRenderFrameCache* frame_cache, QObject* parent = nullptr);
VideoRenderWorker(VideoRenderFrameCache* frame_cache, QObject* parent = nullptr);
void SetParameters(const VideoRenderingParams& video_params);
@@ -45,7 +45,7 @@ protected:
virtual NodeValueTable RenderBlock(TrackOutput *track, const TimeRange& range) override;
ColorProcessorCache* color_cache() const;
ColorProcessorCache* color_cache();
private:
void ProcessNode();
@@ -56,7 +56,7 @@ private:
VideoRenderFrameCache* frame_cache_;
ColorProcessorCache* color_cache_;
ColorProcessorCache color_cache_;
QByteArray download_buffer_;