fixed various segfaults in decoder and renderer
This commit is contained in:
@@ -30,7 +30,6 @@ set(OLIVE_SOURCES
|
||||
render/backend/renderworker.h
|
||||
render/backend/renderworker.cpp
|
||||
|
||||
render/backend/rendercache.h
|
||||
render/backend/colorprocessorcache.h
|
||||
render/backend/decodercache.h
|
||||
|
||||
|
||||
@@ -23,11 +23,10 @@
|
||||
|
||||
#include "project/item/footage/stream.h"
|
||||
#include "render/colorprocessor.h"
|
||||
#include "rendercache.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
using ColorProcessorCache = RenderCache<QString, ColorProcessorPtr>;
|
||||
using ColorProcessorCache = QHash<QString, ColorProcessorPtr>;
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
|
||||
@@ -23,21 +23,10 @@
|
||||
|
||||
#include "codec/decoder.h"
|
||||
#include "project/item/footage/stream.h"
|
||||
#include "rendercache.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class DecoderCache : public RenderCache<Stream*, DecoderPtr>
|
||||
{
|
||||
public:
|
||||
DecoderCache() = default;
|
||||
|
||||
QMutex* lock() {return &lock_;}
|
||||
|
||||
private:
|
||||
QMutex lock_;
|
||||
|
||||
};
|
||||
using DecoderCache = QHash<Stream*, DecoderPtr>;
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ RenderWorker *OpenGLBackend::CreateNewWorker()
|
||||
}
|
||||
}
|
||||
|
||||
return new OpenGLWorker(proxy_);
|
||||
return new OpenGLWorker(this, proxy_);
|
||||
}
|
||||
|
||||
void OpenGLBackend::ClearProxy()
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define OPENGLCOLORPROCESSOR_H
|
||||
|
||||
#include "openglshader.h"
|
||||
#include "render/backend/rendercache.h"
|
||||
#include "render/colorprocessor.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
@@ -63,7 +62,7 @@ private slots:
|
||||
|
||||
};
|
||||
|
||||
using OpenGLColorProcessorCache = RenderCache<QString, OpenGLColorProcessorPtr>;
|
||||
using OpenGLColorProcessorCache = QHash<QString, OpenGLColorProcessorPtr>;
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
|
||||
@@ -74,13 +74,13 @@ NodeValue OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, const Vide
|
||||
// Set up OCIO context
|
||||
QString colorspace_match = video_stream->get_colorspace_match_string();
|
||||
|
||||
OpenGLColorProcessorPtr color_processor = std::static_pointer_cast<OpenGLColorProcessor>(color_cache_.Get(colorspace_match));
|
||||
OpenGLColorProcessorPtr color_processor = std::static_pointer_cast<OpenGLColorProcessor>(color_cache_.value(colorspace_match));
|
||||
|
||||
if (!color_processor) {
|
||||
color_processor = OpenGLColorProcessor::Create(video_stream->footage()->project()->color_manager(),
|
||||
video_stream->colorspace(),
|
||||
video_stream->footage()->project()->color_manager()->GetReferenceColorSpace());
|
||||
color_cache_.Add(colorspace_match, color_processor);
|
||||
color_cache_.insert(colorspace_match, color_processor);
|
||||
}
|
||||
|
||||
ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(params.mode());
|
||||
@@ -172,7 +172,7 @@ NodeValue OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, const Vide
|
||||
|
||||
void OpenGLProxy::Close()
|
||||
{
|
||||
shader_cache_.Clear();
|
||||
shader_cache_.clear();
|
||||
buffer_.Destroy();
|
||||
copy_pipeline_ = nullptr;
|
||||
functions_ = nullptr;
|
||||
@@ -186,7 +186,7 @@ void OpenGLProxy::RunNodeAccelerated(const Node *node,
|
||||
NodeValueTable &output_params,
|
||||
const VideoRenderingParams& params)
|
||||
{
|
||||
OpenGLShaderPtr shader = shader_cache_.Get(node->ShaderID(input_params));
|
||||
OpenGLShaderPtr shader = shader_cache_.value(node->ShaderID(input_params));
|
||||
|
||||
if (!shader) {
|
||||
// Since we have shader code, compile it now
|
||||
@@ -208,7 +208,7 @@ void OpenGLProxy::RunNodeAccelerated(const Node *node,
|
||||
shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code);
|
||||
shader->link();
|
||||
|
||||
shader_cache_.Add(node->id(), shader);
|
||||
shader_cache_.insert(node->id(), shader);
|
||||
}
|
||||
|
||||
// Create the output textures
|
||||
|
||||
@@ -24,11 +24,10 @@
|
||||
#include <QString>
|
||||
|
||||
#include "openglshader.h"
|
||||
#include "render/backend/rendercache.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
using OpenGLShaderCache = RenderCache<QString, OpenGLShaderPtr>;
|
||||
using OpenGLShaderCache = QHash<QString, OpenGLShaderPtr>;
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
OpenGLWorker::OpenGLWorker(OpenGLProxy* proxy) :
|
||||
OpenGLWorker::OpenGLWorker(RenderBackend *parent, OpenGLProxy* proxy) :
|
||||
RenderWorker(parent),
|
||||
proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ OLIVE_NAMESPACE_ENTER
|
||||
class OpenGLWorker : public RenderWorker
|
||||
{
|
||||
public:
|
||||
OpenGLWorker(OpenGLProxy* proxy);
|
||||
OpenGLWorker(RenderBackend* parent, OpenGLProxy* proxy);
|
||||
|
||||
protected:
|
||||
virtual void TextureToFrame(const QVariant& texture, FramePtr frame, const QMatrix4x4 &mat) const override;
|
||||
|
||||
@@ -32,6 +32,8 @@ OLIVE_NAMESPACE_ENTER
|
||||
RenderBackend::RenderBackend(QObject *parent) :
|
||||
QObject(parent),
|
||||
viewer_node_(nullptr),
|
||||
video_instance_queuer_(0),
|
||||
audio_instance_queuer_(0),
|
||||
divider_(1),
|
||||
render_mode_(RenderMode::kOnline),
|
||||
pix_fmt_(PixelFormat::PIX_FMT_RGBA32F),
|
||||
@@ -57,7 +59,7 @@ void RenderBackend::SetViewerNode(ViewerOutput *viewer_node)
|
||||
CancelQueue();
|
||||
|
||||
// Delete all of our copied nodes
|
||||
foreach (RenderWorker* instance, instance_pool_) {
|
||||
foreach (RenderWorker* instance, video_instance_pool_) {
|
||||
instance->Close();
|
||||
}
|
||||
|
||||
@@ -69,7 +71,7 @@ void RenderBackend::SetViewerNode(ViewerOutput *viewer_node)
|
||||
disconnect(viewer_node_->audio_playback_cache(),
|
||||
&AudioPlaybackCache::Invalidated,
|
||||
this,
|
||||
&RenderBackend::AudioCallback);
|
||||
&RenderBackend::AudioInvalidated);
|
||||
}
|
||||
|
||||
// Set viewer node
|
||||
@@ -77,7 +79,7 @@ void RenderBackend::SetViewerNode(ViewerOutput *viewer_node)
|
||||
|
||||
if (viewer_node_) {
|
||||
// Initiate instances with new node
|
||||
foreach (RenderWorker* instance, instance_pool_) {
|
||||
foreach (RenderWorker* instance, video_instance_pool_) {
|
||||
instance->Init(viewer_node_);
|
||||
}
|
||||
|
||||
@@ -89,34 +91,36 @@ void RenderBackend::SetViewerNode(ViewerOutput *viewer_node)
|
||||
connect(viewer_node_->audio_playback_cache(),
|
||||
&AudioPlaybackCache::Invalidated,
|
||||
this,
|
||||
&RenderBackend::AudioCallback);
|
||||
&RenderBackend::AudioInvalidated);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderBackend::CancelQueue()
|
||||
{
|
||||
// FIXME: Implement something better than this...
|
||||
thread_pool_.waitForDone();
|
||||
video_thread_pool_.waitForDone();
|
||||
}
|
||||
|
||||
QFuture<QByteArray> RenderBackend::Hash(const rational &time)
|
||||
QFuture<QByteArray> RenderBackend::Hash(const rational &time, bool block_for_update)
|
||||
{
|
||||
return QtConcurrent::run(&thread_pool_,
|
||||
GetInstanceFromPool(),
|
||||
return QtConcurrent::run(&video_thread_pool_,
|
||||
GetInstanceFromPool(video_instance_pool_, video_thread_pool_, video_instance_queuer_),
|
||||
&RenderWorker::Hash,
|
||||
time);
|
||||
time,
|
||||
block_for_update);
|
||||
}
|
||||
|
||||
QFuture<FramePtr> RenderBackend::RenderFrame(const rational &time, bool clear_queue)
|
||||
QFuture<FramePtr> RenderBackend::RenderFrame(const rational &time, bool clear_queue, bool block_for_update)
|
||||
{
|
||||
if (clear_queue) {
|
||||
thread_pool_.clear();
|
||||
video_thread_pool_.clear();
|
||||
}
|
||||
|
||||
return QtConcurrent::run(&thread_pool_,
|
||||
GetInstanceFromPool(),
|
||||
return QtConcurrent::run(&video_thread_pool_,
|
||||
GetInstanceFromPool(video_instance_pool_, video_thread_pool_, video_instance_queuer_),
|
||||
&RenderWorker::RenderFrame,
|
||||
time);
|
||||
time,
|
||||
block_for_update);
|
||||
}
|
||||
|
||||
void RenderBackend::SetDivider(const int ÷r)
|
||||
@@ -146,19 +150,26 @@ void RenderBackend::SetVideoDownloadMatrix(const QMatrix4x4 &mat)
|
||||
|
||||
void RenderBackend::NodeGraphChanged(NodeInput *source)
|
||||
{
|
||||
QLinkedList<RenderWorker*>::iterator i;
|
||||
|
||||
for (i=instance_pool_.begin(); i!=instance_pool_.end(); i++) {
|
||||
(*i)->Queue(source);
|
||||
foreach (RenderWorker* worker, video_instance_pool_) {
|
||||
worker->Queue(source);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderBackend::UpdateInstance(RenderWorker *instance)
|
||||
{
|
||||
instance->SetAvailable(false);
|
||||
instance->ProcessQueue();
|
||||
instance->SetVideoParams(video_params());
|
||||
instance->SetAudioParams(audio_params());
|
||||
instance->SetVideoDownloadMatrix(video_download_matrix_);
|
||||
}
|
||||
|
||||
void RenderBackend::Close()
|
||||
{
|
||||
CancelQueue();
|
||||
|
||||
qDeleteAll(instance_pool_);
|
||||
instance_pool_.clear();
|
||||
qDeleteAll(video_instance_pool_);
|
||||
video_instance_pool_.clear();
|
||||
}
|
||||
|
||||
VideoRenderingParams RenderBackend::video_params() const
|
||||
@@ -171,60 +182,63 @@ AudioRenderingParams RenderBackend::audio_params() const
|
||||
return AudioRenderingParams(viewer_node_->audio_params(), sample_fmt_);
|
||||
}
|
||||
|
||||
RenderWorker *RenderBackend::GetInstanceFromPool()
|
||||
RenderWorker *RenderBackend::GetInstanceFromPool(QVector<RenderWorker *> &worker_pool, QThreadPool &thread_pool, int &instance_queuer)
|
||||
{
|
||||
RenderWorker* instance = nullptr;
|
||||
|
||||
QLinkedList<RenderWorker*>::iterator i;
|
||||
|
||||
for (i=instance_pool_.begin(); i!=instance_pool_.end(); i++) {
|
||||
if ((*i)->IsAvailable()) {
|
||||
instance = *i;
|
||||
foreach (RenderWorker* worker, worker_pool) {
|
||||
if (worker->IsAvailable()) {
|
||||
instance = worker;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!instance) {
|
||||
instance = CreateNewWorker();
|
||||
instance_pool_.append(instance);
|
||||
if (worker_pool.size() < thread_pool.maxThreadCount()) {
|
||||
// Can create another instance
|
||||
instance = CreateNewWorker();
|
||||
worker_pool.append(instance);
|
||||
|
||||
if (viewer_node_) {
|
||||
instance->Init(viewer_node_);
|
||||
if (viewer_node_) {
|
||||
instance->Init(viewer_node_);
|
||||
}
|
||||
|
||||
connect(instance,
|
||||
&RenderWorker::FinishedJob,
|
||||
this,
|
||||
&RenderBackend::WorkerFinished,
|
||||
Qt::QueuedConnection);
|
||||
} else {
|
||||
instance = worker_pool.at(instance_queuer % worker_pool.size());
|
||||
instance_queuer++;
|
||||
}
|
||||
|
||||
connect(instance,
|
||||
&RenderWorker::FinishedJob,
|
||||
this,
|
||||
&RenderBackend::WorkerFinished,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
instance->SetAvailable(false);
|
||||
instance->ProcessQueue();
|
||||
instance->SetVideoParams(video_params());
|
||||
instance->SetAudioParams(audio_params());
|
||||
instance->SetVideoDownloadMatrix(video_download_matrix_);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void RenderBackend::AudioCallback()
|
||||
void RenderBackend::AudioInvalidated(const TimeRange& r)
|
||||
{
|
||||
qDebug() << "STUB";
|
||||
/*
|
||||
AudioPlaybackCache* pb_cache = viewer_node_->audio_playback_cache();
|
||||
QThreadPool* thread_pool = audio_copy_map_.thread_pool();
|
||||
QFutureWatcher<SampleBufferPtr>* watcher = new QFutureWatcher<SampleBufferPtr>();
|
||||
connect(watcher, &QFutureWatcher<SampleBufferPtr>::finished, this, &RenderBackend::AudioRendered);
|
||||
|
||||
while (!pb_cache->IsFullyValidated()
|
||||
&& thread_pool->activeThreadCount() < thread_pool->maxThreadCount()) {
|
||||
// FIXME: Trigger a background audio thread
|
||||
TimeRange r = viewer_node_->audio_playback_cache()->GetInvalidatedRanges().first();
|
||||
watcher->setFuture(QtConcurrent::run(&video_thread_pool_,
|
||||
GetInstanceFromPool(audio_instance_pool_, audio_thread_pool_, audio_instance_queuer_),
|
||||
&RenderWorker::RenderAudio,
|
||||
r));
|
||||
}
|
||||
|
||||
qDebug() << "FIXME: Start rendering audio at:" << r;
|
||||
void RenderBackend::AudioRendered()
|
||||
{
|
||||
QFutureWatcher<SampleBufferPtr>* watcher = static_cast<QFutureWatcher<SampleBufferPtr>*>(sender());
|
||||
|
||||
break;
|
||||
if (watcher->result()) {
|
||||
qDebug() << "AUDIO: Received" << watcher->result()->sample_count_per_channel() << "samples!";
|
||||
} else {
|
||||
qDebug() << "AUDIO: Received null";
|
||||
}
|
||||
*/
|
||||
|
||||
watcher->deleteLater();
|
||||
}
|
||||
|
||||
void RenderBackend::WorkerFinished()
|
||||
|
||||
@@ -47,12 +47,12 @@ public:
|
||||
/**
|
||||
* @brief Asynchronously generate a hash at a given time
|
||||
*/
|
||||
QFuture<QByteArray> Hash(const rational& time);
|
||||
QFuture<QByteArray> Hash(const rational& time, bool block_for_update);
|
||||
|
||||
/**
|
||||
* @brief Asynchronously generate a frame at a given time
|
||||
*/
|
||||
QFuture<FramePtr> RenderFrame(const rational& time, bool clear_queue);
|
||||
QFuture<FramePtr> RenderFrame(const rational& time, bool clear_queue, bool block_for_update);
|
||||
|
||||
void SetDivider(const int& divider);
|
||||
|
||||
@@ -67,6 +67,8 @@ public:
|
||||
public slots:
|
||||
void NodeGraphChanged(NodeInput *source);
|
||||
|
||||
void UpdateInstance(OLIVE_NAMESPACE::RenderWorker* instance);
|
||||
|
||||
protected:
|
||||
virtual RenderWorker* CreateNewWorker() = 0;
|
||||
|
||||
@@ -77,15 +79,22 @@ protected:
|
||||
AudioRenderingParams audio_params() const;
|
||||
|
||||
private:
|
||||
RenderWorker *GetInstanceFromPool();
|
||||
RenderWorker *GetInstanceFromPool(QVector<RenderWorker*>& worker_pool,
|
||||
QThreadPool& thread_pool,
|
||||
int& instance_queuer);
|
||||
|
||||
ViewerOutput* viewer_node_;
|
||||
|
||||
RenderCancelDialog* cancel_dialog_;
|
||||
|
||||
QLinkedList<RenderWorker*> instance_pool_;
|
||||
QVector<RenderWorker*> video_instance_pool_;
|
||||
QVector<RenderWorker*> audio_instance_pool_;
|
||||
|
||||
QThreadPool thread_pool_;
|
||||
QThreadPool video_thread_pool_;
|
||||
QThreadPool audio_thread_pool_;
|
||||
|
||||
int video_instance_queuer_;
|
||||
int audio_instance_queuer_;
|
||||
|
||||
// VIDEO MEMBERS
|
||||
int divider_;
|
||||
@@ -107,7 +116,9 @@ private:
|
||||
QList<ConformWaitInfo> footage_wait_info_;
|
||||
|
||||
private slots:
|
||||
void AudioCallback();
|
||||
void AudioInvalidated(const TimeRange &r);
|
||||
|
||||
void AudioRendered();
|
||||
|
||||
void WorkerFinished();
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2019 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 RENDERCACHE_H
|
||||
#define RENDERCACHE_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
template<class K, class V>
|
||||
class RenderCache
|
||||
{
|
||||
public:
|
||||
RenderCache() = default;
|
||||
|
||||
void Clear(){values_.clear();}
|
||||
|
||||
void Add(K key, V val){values_.insert(key, val);}
|
||||
|
||||
V Get(K key) const {return values_.value(key);}
|
||||
|
||||
bool Has(K key) const {return values_.contains(key);}
|
||||
|
||||
void Remove(K key) {values_.remove(key);}
|
||||
|
||||
private:
|
||||
QHash<K, V> values_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
#endif // RENDERCACHE_H
|
||||
@@ -25,10 +25,12 @@
|
||||
#include "audio/sumsamples.h"
|
||||
#include "config/config.h"
|
||||
#include "node/block/clip/clip.h"
|
||||
#include "renderbackend.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
RenderWorker::RenderWorker() :
|
||||
RenderWorker::RenderWorker(RenderBackend* parent) :
|
||||
parent_(parent),
|
||||
viewer_(nullptr),
|
||||
available_(true)
|
||||
{
|
||||
@@ -39,12 +41,16 @@ RenderWorker::~RenderWorker()
|
||||
Close();
|
||||
}
|
||||
|
||||
QByteArray RenderWorker::Hash(const rational &time)
|
||||
QByteArray RenderWorker::Hash(const rational &time, bool block_for_update)
|
||||
{
|
||||
if (!viewer_) {
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QMutexLocker locker(&lock_);
|
||||
|
||||
UpdateData(block_for_update);
|
||||
|
||||
QCryptographicHash hasher(QCryptographicHash::Sha1);
|
||||
|
||||
// Embed video parameters into this hash
|
||||
@@ -60,14 +66,18 @@ QByteArray RenderWorker::Hash(const rational &time)
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
FramePtr RenderWorker::RenderFrame(const rational &time)
|
||||
FramePtr RenderWorker::RenderFrame(const rational &time, bool block_for_update)
|
||||
{
|
||||
if (!viewer_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NodeValueTable table = GenerateTable(viewer_,
|
||||
TimeRange(time, time + video_params_.time_base()));
|
||||
QMutexLocker locker(&lock_);
|
||||
|
||||
UpdateData(block_for_update);
|
||||
|
||||
NodeValueTable table = ProcessInput(viewer_->texture_input(),
|
||||
TimeRange(time, time + video_params_.time_base()));
|
||||
|
||||
QVariant texture = table.Get(NodeParam::kTexture);
|
||||
|
||||
@@ -89,10 +99,45 @@ FramePtr RenderWorker::RenderFrame(const rational &time)
|
||||
return frame;
|
||||
}
|
||||
|
||||
SampleBufferPtr RenderWorker::RenderAudio(const TimeRange &range)
|
||||
{
|
||||
if (!viewer_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMutexLocker locker(&lock_);
|
||||
|
||||
UpdateData(true);
|
||||
|
||||
NodeValueTable table = ProcessInput(viewer_->samples_input(), range);
|
||||
|
||||
QVariant samples = table.Get(NodeParam::kSamples);
|
||||
|
||||
return samples.value<SampleBufferPtr>();
|
||||
}
|
||||
|
||||
void RenderWorker::UpdateData(bool block_for_update)
|
||||
{
|
||||
// FIXME: This is pretty trashy. It works, but it's not good. Should probably be changed at some
|
||||
// point.
|
||||
if (block_for_update) {
|
||||
QMetaObject::invokeMethod(parent_,
|
||||
"UpdateInstance",
|
||||
Qt::BlockingQueuedConnection,
|
||||
OLIVE_NS_ARG(RenderWorker*, this));
|
||||
} else {
|
||||
parent_->UpdateInstance(this);
|
||||
}
|
||||
}
|
||||
|
||||
NodeValueTable RenderWorker::GenerateBlockTable(const TrackOutput *track, const TimeRange &range)
|
||||
{
|
||||
qDebug() << "Hello from track" << track << "type" << track->track_type();
|
||||
|
||||
if (track->track_type() == Timeline::kTrackTypeAudio) {
|
||||
|
||||
qDebug() << "Hello?";
|
||||
|
||||
QList<Block*> active_blocks = track->BlocksAtTimeRange(range);
|
||||
|
||||
// All these blocks will need to output to a buffer so we create one here
|
||||
@@ -273,8 +318,8 @@ void RenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange &inp
|
||||
NodeValue value;
|
||||
bool found_cache = false;
|
||||
|
||||
if (still_image_cache_.Has(stream.get())) {
|
||||
CachedStill cs = still_image_cache_.Get(stream.get());
|
||||
if (still_image_cache_.contains(stream.get())) {
|
||||
const CachedStill& cs = still_image_cache_[stream.get()];
|
||||
|
||||
if (cs.colorspace == colorspace_match
|
||||
&& cs.alpha_is_associated == video_stream->premultiplied_alpha()
|
||||
@@ -283,7 +328,7 @@ void RenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange &inp
|
||||
value = cs.texture;
|
||||
found_cache = true;
|
||||
} else {
|
||||
still_image_cache_.Remove(stream.get());
|
||||
still_image_cache_.remove(stream.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,11 +336,11 @@ void RenderWorker::FootageProcessingEvent(StreamPtr stream, const TimeRange &inp
|
||||
|
||||
value = GetDataFromStream(stream, input_time);
|
||||
|
||||
still_image_cache_.Add(stream.get(), {value,
|
||||
colorspace_match,
|
||||
video_stream->premultiplied_alpha(),
|
||||
video_params_.divider(),
|
||||
time_match});
|
||||
still_image_cache_.insert(stream.get(), {value,
|
||||
colorspace_match,
|
||||
video_stream->premultiplied_alpha(),
|
||||
video_params_.divider(),
|
||||
time_match});
|
||||
|
||||
}
|
||||
|
||||
@@ -323,7 +368,7 @@ 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_.value(stream.get());
|
||||
|
||||
if (!decoder && stream) {
|
||||
// Create a new Decoder here
|
||||
@@ -331,7 +376,7 @@ DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream)
|
||||
decoder->set_stream(stream);
|
||||
|
||||
if (decoder->Open()) {
|
||||
decoder_cache_.Add(stream.get(), decoder);
|
||||
decoder_cache_.insert(stream.get(), decoder);
|
||||
} else {
|
||||
decoder = nullptr;
|
||||
qWarning() << "Failed to open decoder for" << stream->footage()->filename()
|
||||
|
||||
@@ -26,15 +26,16 @@
|
||||
#include "decodercache.h"
|
||||
#include "node/traverser.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
#include "render/backend/rendercache.h"
|
||||
|
||||
OLIVE_NAMESPACE_ENTER
|
||||
|
||||
class RenderBackend;
|
||||
|
||||
class RenderWorker : public QObject, public NodeTraverser
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RenderWorker();
|
||||
RenderWorker(RenderBackend* parent);
|
||||
|
||||
virtual ~RenderWorker() override;
|
||||
|
||||
@@ -84,7 +85,7 @@ public:
|
||||
*
|
||||
* SHA-1 hash or empty QByteArray if no viewer node is set.
|
||||
*/
|
||||
QByteArray Hash(const rational &time);
|
||||
QByteArray Hash(const rational &time, bool block_for_update);
|
||||
|
||||
/**
|
||||
* @brief Render the frame at this time
|
||||
@@ -97,11 +98,9 @@ public:
|
||||
* function will still return a blank frame with the same parameters. If no viewer node is set,
|
||||
* nullptr is returned.
|
||||
*/
|
||||
FramePtr RenderFrame(const rational& time);
|
||||
FramePtr RenderFrame(const rational& time, bool block_for_update);
|
||||
|
||||
SampleBufferPtr RenderAudio(ViewerOutput* viewer,
|
||||
const TimeRange& range,
|
||||
const SampleFormat::Format& sample_fmt);
|
||||
SampleBufferPtr RenderAudio(const TimeRange& range);
|
||||
|
||||
protected:
|
||||
virtual void TextureToFrame(const QVariant& texture, FramePtr frame, const QMatrix4x4 &mat) const = 0;
|
||||
@@ -130,6 +129,8 @@ signals:
|
||||
void FinishedJob();
|
||||
|
||||
private:
|
||||
void UpdateData(bool block_for_update);
|
||||
|
||||
NodeValue GetDataFromStream(StreamPtr stream, const TimeRange& input_time);
|
||||
|
||||
DecoderPtr ResolveDecoderFromInput(StreamPtr stream);
|
||||
@@ -138,6 +139,8 @@ private:
|
||||
Node *CopyNodeConnections(Node *src_node);
|
||||
void CopyNodeMakeConnection(NodeInput *src_input, NodeInput *dst_input);
|
||||
|
||||
RenderBackend* parent_;
|
||||
|
||||
VideoRenderingParams video_params_;
|
||||
|
||||
AudioRenderingParams audio_params_;
|
||||
@@ -150,7 +153,7 @@ private:
|
||||
rational time;
|
||||
};
|
||||
|
||||
RenderCache<Stream*, CachedStill> still_image_cache_;
|
||||
QHash<Stream*, CachedStill> still_image_cache_;
|
||||
|
||||
QMatrix4x4 video_download_matrix_;
|
||||
|
||||
@@ -161,6 +164,8 @@ private:
|
||||
QHash<Node*, Node*> copy_map_;
|
||||
bool available_;
|
||||
|
||||
QMutex lock_;
|
||||
|
||||
};
|
||||
|
||||
OLIVE_NAMESPACE_EXIT
|
||||
|
||||
Reference in New Issue
Block a user