base audio renderer classes created

This commit is contained in:
itsmattkc
2019-10-16 13:51:56 +11:00
parent fe2b0f2dc2
commit d6483916ac
33 changed files with 896 additions and 116 deletions
+1 -2
View File
@@ -18,9 +18,8 @@ set(OLIVE_SOURCES
${OLIVE_SOURCES}
audio/audiohybriddevice.h
audio/audiohybriddevice.cpp
audio/audiolayouts.h
audio/audiolayouts.cpp
audio/audiomanager.h
audio/audiomanager.cpp
audio/sampleformat.h
PARENT_SCOPE
)
+6 -6
View File
@@ -22,24 +22,24 @@
#include "config/config.h"
AudioManager* AudioManager::audio_ = nullptr;
AudioManager* AudioManager::instance_ = nullptr;
void AudioManager::CreateInstance()
{
if (audio_ == nullptr) {
audio_ = new AudioManager();
if (instance_ == nullptr) {
instance_ = new AudioManager();
}
}
void AudioManager::DestroyInstance()
{
delete audio_;
audio_ = nullptr;
delete instance_;
instance_ = nullptr;
}
AudioManager *AudioManager::instance()
{
return audio_;
return instance_;
}
void AudioManager::RefreshDevices()
+1 -1
View File
@@ -95,7 +95,7 @@ private:
QList<QAudioDeviceInfo> output_devices_;
static AudioManager* audio_;
static AudioManager* instance_;
AudioHybridDevice output_manager_;
+1 -1
View File
@@ -233,7 +233,7 @@ void SequenceDialog::AddChannelLayout(int layout)
layout_name = tr("7.1");
break;
default:
layout_name = tr("Unknown (%1)").arg(layout);
layout_name = tr("Unknown (0x%1)").arg(layout, 1, 16);
}
audio_channels_field_->addItem(layout_name, layout);
+2 -2
View File
@@ -20,7 +20,7 @@
#include "alphaover.h"
#include "node/processor/renderer/renderer.h"
#include "node/processor/videorenderer/videorenderer.h"
#include "render/gl/functions.h"
#include "render/rendertexture.h"
#include "render/gl/shadergenerators.h"
@@ -52,7 +52,7 @@ void AlphaOverBlend::Release()
QVariant AlphaOverBlend::Value(NodeOutput *param, const rational &time)
{
// Find the current Renderer instance
RenderInstance* renderer = RendererProcessor::CurrentInstance();
RenderInstance* renderer = VideoRendererProcessor::CurrentInstance();
// If nothing is available, don't return a texture
if (renderer == nullptr) {
+1 -1
View File
@@ -20,7 +20,7 @@
#include "clip.h"
#include "node/processor/renderer/renderer.h"
#include "node/processor/videorenderer/videorenderer.h"
ClipBlock::ClipBlock()
{
+2 -2
View File
@@ -20,7 +20,7 @@
#include "opacity.h"
#include "node/processor/renderer/renderer.h"
#include "node/processor/videorenderer/videorenderer.h"
#include "render/gl/functions.h"
#include "render/rendertexture.h"
@@ -65,7 +65,7 @@ QString OpacityNode::id()
QVariant OpacityNode::Value(NodeOutput *output, const rational &time)
{
// Find the current Renderer instance
RenderInstance* renderer = RendererProcessor::CurrentInstance();
RenderInstance* renderer = VideoRendererProcessor::CurrentInstance();
// If nothing is available, don't return a texture
if (renderer == nullptr) {
+2 -2
View File
@@ -25,7 +25,7 @@
#include "core.h"
#include "decoder/ffmpeg/ffmpegdecoder.h"
#include "node/processor/renderer/renderer.h"
#include "node/processor/videorenderer/videorenderer.h"
#include "project/item/footage/footage.h"
#include "render/gl/shadergenerators.h"
#include "render/gl/functions.h"
@@ -136,7 +136,7 @@ QVariant MediaInput::Value(NodeOutput *output, const rational &time)
if (output == texture_output_) {
// Find the current Renderer instance
RenderInstance* renderer = RendererProcessor::CurrentInstance();
RenderInstance* renderer = VideoRendererProcessor::CurrentInstance();
// If nothing is available, don't return a texture
if (renderer == nullptr) {
+2 -1
View File
@@ -14,7 +14,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(renderer)
add_subdirectory(audiorenderer)
add_subdirectory(videorenderer)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
@@ -16,13 +16,13 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/processor/renderer/renderer.h
node/processor/renderer/renderer.cpp
node/processor/renderer/rendererthreadbase.h
node/processor/renderer/rendererthreadbase.cpp
node/processor/renderer/rendererdownloadthread.h
node/processor/renderer/rendererdownloadthread.cpp
node/processor/renderer/rendererprocessthread.h
node/processor/renderer/rendererprocessthread.cpp
node/processor/audiorenderer/audiorenderer.h
node/processor/audiorenderer/audiorenderer.cpp
node/processor/audiorenderer/audiorendererparams.h
node/processor/audiorenderer/audiorendererparams.cpp
node/processor/audiorenderer/audiorendererthread.h
node/processor/audiorenderer/audiorendererthread.cpp
node/processor/audiorenderer/audiorendererthreadbase.h
node/processor/audiorenderer/audiorendererthreadbase.cpp
PARENT_SCOPE
)
@@ -0,0 +1,342 @@
/***
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/>.
***/
#include "audiorenderer.h"
#include <QApplication>
#include <QCryptographicHash>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QtMath>
#include "common/filefunctions.h"
#include "render/pixelservice.h"
AudioRendererProcessor::AudioRendererProcessor() :
started_(false),
caching_(false),
starting_(false)
{
texture_input_ = new NodeInput("tex_in");
texture_input_->add_data_input(NodeInput::kTexture);
AddParameter(texture_input_);
length_input_ = new NodeInput("length_in");
length_input_->add_data_input(NodeInput::kRational);
AddParameter(length_input_);
texture_output_ = new NodeOutput("tex_out");
texture_output_->set_data_type(NodeInput::kTexture);
AddParameter(texture_output_);
}
QString AudioRendererProcessor::Name()
{
return tr("Audio Renderer");
}
QString AudioRendererProcessor::Category()
{
return tr("Processor");
}
QString AudioRendererProcessor::Description()
{
return tr("A multi-threaded PCM audio renderer.");
}
QString AudioRendererProcessor::id()
{
return "org.olivevideoeditor.Olive.rendererneptune";
}
void AudioRendererProcessor::SetCacheName(const QString &s)
{
cache_name_ = s;
cache_time_ = QDateTime::currentMSecsSinceEpoch();
GenerateCacheIDInternal();
}
QVariant AudioRendererProcessor::Value(NodeOutput* output, const rational& time)
{
Q_UNUSED(output)
Q_UNUSED(time)
/*if (output == texture_output_) {
if (!texture_input_->IsConnected()) {
// Nothing is connected - nothing to show or render
return 0;
}
if (cache_id_.isEmpty()) {
qWarning() << "RendererProcessor has no cache ID";
return 0;
}
if (timebase_.isNull()) {
qWarning() << "RendererProcessor has no timebase";
return 0;
}
// Find frame in map
if (time_hash_map_.contains(time)) {
QString fn = CachePathName(time_hash_map_[time]);
if (QFileInfo::exists(fn)) {
auto in = OIIO::ImageInput::open(fn.toStdString());
if (in) {
in->read_image(PixelService::GetPixelFormatInfo(format_).oiio_desc, cache_frame_load_buffer_.data());
in->close();
master_texture_->Upload(cache_frame_load_buffer_.data());
return QVariant::fromValue(master_texture_);
} else {
qWarning() << "OIIO Error:" << OIIO::geterror().c_str();
}
}
}
}*/
return 0;
}
void AudioRendererProcessor::Release()
{
Stop();
}
void AudioRendererProcessor::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
{
Q_UNUSED(from)
if (timebase_.isNull()) {
return;
}
//ClearCachedValuesInParameters(start_range, end_range);
texture_input_->ClearCachedValue();
length_input_->ClearCachedValue();
// Adjust range to min/max values
rational start_range_adj = qMax(rational(0), start_range);
rational end_range_adj = qMin(length_input()->get_value(0).value<rational>(), end_range);
qDebug() << "Cache invalidated between"
<< start_range_adj.toDouble()
<< "and"
<< end_range_adj.toDouble();
// Snap start_range to timebase
double start_range_dbl = start_range_adj.toDouble();
double start_range_numf = start_range_dbl * static_cast<double>(timebase_.denominator());
int64_t start_range_numround = qFloor(start_range_numf/static_cast<double>(timebase_.numerator())) * timebase_.numerator();
rational true_start_range(start_range_numround, timebase_.denominator());
for (rational r=true_start_range;r<=end_range_adj;r+=timebase_) {
// Try to order the queue from closest to the playhead to furthest
rational last_time = texture_output()->LastRequestedTime();
rational diff = r - last_time;
if (diff < 0) {
// FIXME: Hardcoded number
// If the number is before the playhead, we still prioritize its closeness but not nearly as much (5:1 in this
// example)
diff = qAbs(diff) * 5;
}
bool contains = false;
bool added = false;
QLinkedList<rational>::iterator insert_iterator;
for (QLinkedList<rational>::iterator i = cache_queue_.begin();i != cache_queue_.end();i++) {
rational compare = *i;
if (!added) {
rational compare_diff = compare - last_time;
if (compare_diff > diff) {
insert_iterator = i;
added = true;
}
}
if (compare == r) {
contains = true;
break;
}
}
if (!contains) {
if (added) {
cache_queue_.insert(insert_iterator, r);
} else {
cache_queue_.append(r);
}
}
}
CacheNext();
}
void AudioRendererProcessor::SetTimebase(const rational &timebase)
{
timebase_ = timebase;
timebase_dbl_ = timebase_.toDouble();
}
void AudioRendererProcessor::SetParameters(const int &sample_rate,
const uint64_t &channel_layout,
const olive::SampleFormat &format)
{
// Since we're changing parameters, all the existing threads are invalid and must be removed. They will start again
// next time this Node has to process anything.
Stop();
// Set new parameters
sample_rate_ = sample_rate;
channel_layout_ = channel_layout;
format_ = format;
// Regenerate the cache ID
GenerateCacheIDInternal();
}
void AudioRendererProcessor::Start()
{
if (started_) {
return;
}
int background_thread_count = QThread::idealThreadCount();
threads_.resize(background_thread_count);
for (int i=0;i<threads_.size();i++) {
threads_[i] = std::make_shared<AudioRendererThread>(sample_rate_, channel_layout_, format_);
threads_[i]->StartThread(QThread::LowPriority);
// Ensure this connection is "Queued" so that it always runs in this object's threaded rather than any of the
// other threads
connect(threads_.at(i).get(),
SIGNAL(RequestSibling(NodeDependency)),
this,
SLOT(ThreadRequestSibling(NodeDependency)),
Qt::QueuedConnection);
}
// Connect first thread (master thread) to the callback
connect(threads_.first().get(),
SIGNAL(CachedFrame(RenderTexturePtr, const rational&, const QByteArray&)),
this,
SLOT(ThreadCallback(RenderTexturePtr, const rational&, const QByteArray&)),
Qt::QueuedConnection);
connect(threads_.first().get(),
SIGNAL(FrameSkipped(const rational&, const QByteArray&)),
this,
SLOT(ThreadSkippedFrame(const rational&, const QByteArray&)),
Qt::QueuedConnection);
started_ = true;
}
void AudioRendererProcessor::Stop()
{
if (!started_) {
return;
}
started_ = false;
foreach (AudioRendererThreadPtr process_thread, threads_) {
process_thread->Cancel();
}
threads_.clear();
}
void AudioRendererProcessor::GenerateCacheIDInternal()
{
if (cache_name_.isEmpty() || sample_rate_ == 0 || channel_layout_ == 0) {
return;
}
// Generate an ID that is more or less guaranteed to be unique to this Sequence
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(cache_name_.toUtf8());
hash.addData(QString::number(cache_time_).toUtf8());
hash.addData(QString::number(sample_rate_).toUtf8());
hash.addData(QString::number(channel_layout_).toUtf8());
hash.addData(QString::number(format_).toUtf8());
QByteArray bytes = hash.result();
cache_id_ = bytes.toHex();
}
void AudioRendererProcessor::CacheNext()
{
if (cache_queue_.isEmpty() || !texture_input_->IsConnected() || caching_) {
return;
}
// Make sure cache has started
Start();
rational cache_frame = cache_queue_.takeFirst();
qDebug() << "Caching" << cache_frame.toDouble();
caching_ = true;
}
AudioRendererThreadBase *AudioRendererProcessor::CurrentThread()
{
return dynamic_cast<AudioRendererThreadBase*>(QThread::currentThread());
}
AudioRendererParams *AudioRendererProcessor::CurrentInstance()
{
AudioRendererThreadBase* thread = CurrentThread();
if (thread != nullptr) {
return thread->params();
}
return nullptr;
}
NodeInput *AudioRendererProcessor::texture_input()
{
return texture_input_;
}
NodeInput *AudioRendererProcessor::length_input()
{
return length_input_;
}
NodeOutput *AudioRendererProcessor::texture_output()
{
return texture_output_;
}
@@ -0,0 +1,177 @@
/***
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 AUDIORENDERER_H
#define AUDIORENDERER_H
#include <QLinkedList>
#include <QOpenGLTexture>
#include "node/node.h"
#include "render/pixelformat.h"
#include "render/rendermodes.h"
#include "audiorendererthread.h"
/**
* @brief A multithreaded PCM audio renderer
*/
class AudioRendererProcessor : public Node
{
Q_OBJECT
public:
/**
* @brief Renderer Constructor
*
* Constructing a Renderer object will not start any threads/backend on its own. Use Start() to do this and Stop()
* when the Renderer is about to be destroyed.
*/
AudioRendererProcessor();
virtual QString Name() override;
virtual QString Category() override;
virtual QString Description() override;
virtual QString id() override;
void SetCacheName(const QString& s);
virtual void Release() override;
virtual void InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from = nullptr) override;
void SetTimebase(const rational& timebase);
/**
* @brief Set parameters of the Renderer
*
* The Renderer owns the buffers that are used in the rendering process and this function sets the kind of buffers
* to use. The Renderer must be stopped when calling this function.
*
* @param width
*
* Buffer width
*
* @param height
*
* Buffer height
*
* @param format
*
* Buffer pixel format
*/
void SetParameters(const int& sample_rate,
const uint64_t& channel_layout,
const olive::SampleFormat& format);
/**
* @brief Return whether a frame is currently being cached
*/
bool IsCaching(const QByteArray& hash);
/**
* @brief Check if a frame is currently being cached, and if not reserve it
*/
bool TryCache(const QByteArray& hash);
/**
* @brief Return current instance of a RenderThread (or nullptr if there is none)
*
* This function attempts a dynamic_cast on QThread::currentThread() to RendererThread, which will return nullptr if
* the cast fails (e.g. if this function is called from the main thread rather than a RendererThread).
*/
static AudioRendererThreadBase* CurrentThread();
static AudioRendererParams* CurrentInstance();
NodeInput* texture_input();
NodeInput* length_input();
NodeOutput* texture_output();
protected:
virtual QVariant Value(NodeOutput* output, const rational& time) override;
private:
struct HashTimeMapping {
rational time;
QByteArray hash;
};
/**
* @brief Allocate and start the multithreaded backend
*/
void Start();
/**
* @brief Terminate and deallocate the multithreaded backend
*/
void Stop();
/**
* @brief Internal function for generating the cache ID
*/
void GenerateCacheIDInternal();
/**
* @brief Function called when there are frames in the queue to cache
*
* This function is NOT thread-safe and should only be called in the main thread.
*/
void CacheNext();
bool ShouldPushTexture(const rational &time);
/**
* @brief Internal list of RenderProcessThreads
*/
QVector<AudioRendererThreadPtr> threads_;
/**
* @brief Internal variable that contains whether the Renderer has started or not
*/
bool started_;
NodeInput* texture_input_;
NodeInput* length_input_;
NodeOutput* texture_output_;
rational timebase_;
double timebase_dbl_;
int sample_rate_;
uint64_t channel_layout_;
olive::SampleFormat format_;
QLinkedList<rational> cache_queue_;
QString cache_name_;
qint64 cache_time_;
QString cache_id_;
bool caching_;
bool starting_;
private slots:
};
#endif // AUDIORENDERER_H
@@ -0,0 +1,23 @@
#include "audiorendererparams.h"
AudioRendererParams::AudioRendererParams(const int &sample_rate, const uint64_t &channel_layout, const olive::SampleFormat &format) :
sample_rate_(sample_rate),
channel_layout_(channel_layout),
format_(format)
{
}
const int &AudioRendererParams::sample_rate()
{
return sample_rate_;
}
const uint64_t &AudioRendererParams::channel_layout()
{
return channel_layout_;
}
const olive::SampleFormat &AudioRendererParams::format()
{
return format_;
}
@@ -0,0 +1,28 @@
#ifndef AUDIORENDERERPARAMS_H
#define AUDIORENDERERPARAMS_H
#include <QtGlobal>
#include "audio/sampleformat.h"
class AudioRendererParams
{
public:
AudioRendererParams(const int& sample_rate, const uint64_t& channel_layout, const olive::SampleFormat& format);
const int& sample_rate();
const uint64_t& channel_layout();
const olive::SampleFormat& format();
private:
int sample_rate_;
uint64_t channel_layout_;
olive::SampleFormat format_;
};
#endif // AUDIORENDERERPARAMS_H
@@ -0,0 +1,23 @@
#include "audiorendererthread.h"
AudioRendererThread::AudioRendererThread(const int &sample_rate, const uint64_t &channel_layout, const olive::SampleFormat &format) :
AudioRendererThreadBase(sample_rate, channel_layout, format),
cancelled_(false)
{
}
void AudioRendererThread::Cancel()
{
cancelled_ = true;
mutex_.lock();
wait_cond_.wakeAll();
mutex_.unlock();
wait();
}
void AudioRendererThread::ProcessLoop()
{
}
@@ -0,0 +1,26 @@
#ifndef AUDIORENDERERTHREAD_H
#define AUDIORENDERERTHREAD_H
#include "audiorendererthreadbase.h"
class AudioRendererThread : public AudioRendererThreadBase
{
Q_OBJECT
public:
AudioRendererThread(const int& sample_rate,
const uint64_t& channel_layout,
const olive::SampleFormat& format);
public slots:
virtual void Cancel() override;
protected:
virtual void ProcessLoop() override;
private:
bool cancelled_;
};
using AudioRendererThreadPtr = std::shared_ptr<AudioRendererThread>;
#endif // AUDIORENDERERTHREAD_H
@@ -0,0 +1,69 @@
/***
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/>.
***/
#include "audiorendererthreadbase.h"
#include <QDebug>
AudioRendererThreadBase::AudioRendererThreadBase(const int &sample_rate, const uint64_t &channel_layout, const olive::SampleFormat &format) :
audio_params_(sample_rate, channel_layout, format)
{
}
AudioRendererParams *AudioRendererThreadBase::params()
{
return &audio_params_;
}
void AudioRendererThreadBase::run()
{
// Lock mutex for main loop
mutex_.lock();
// Signal that main thread can continue now
WakeCaller();
// Main loop (use Cancel() to exit it)
ProcessLoop();
// Unlock mutex before exiting
mutex_.unlock();
}
void AudioRendererThreadBase::WakeCaller()
{
// Signal that main thread can continue now
caller_mutex_.lock();
wait_cond_.wakeAll();
caller_mutex_.unlock();
}
void AudioRendererThreadBase::StartThread(QThread::Priority priority)
{
caller_mutex_.lock();
// Start the thread
QThread::start(priority);
// Wait for thread to finish completion
wait_cond_.wait(&caller_mutex_);
caller_mutex_.unlock();
}
@@ -0,0 +1,65 @@
/***
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 AUDIORENDERTHREADBASE_H
#define AUDIORENDERTHREADBASE_H
#include <memory>
#include <QMutex>
#include <QThread>
#include <QWaitCondition>
#include "audiorendererparams.h"
#include "node/node.h"
class AudioRendererThreadBase : public QThread
{
Q_OBJECT
public:
AudioRendererThreadBase(const int& sample_rate,
const uint64_t& channel_layout,
const olive::SampleFormat& format);
AudioRendererParams* params();
void StartThread(Priority priority = InheritPriority);
virtual void run() override;
public slots:
virtual void Cancel() = 0;
protected:
virtual void ProcessLoop() = 0;
QWaitCondition wait_cond_;
QMutex mutex_;
QMutex caller_mutex_;
private:
void WakeCaller();
AudioRendererParams audio_params_;
};
#endif // RENDERTHREAD_H
@@ -0,0 +1,28 @@
# 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/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
node/processor/videorenderer/videorenderer.h
node/processor/videorenderer/videorenderer.cpp
node/processor/videorenderer/videorendererthreadbase.h
node/processor/videorenderer/videorendererthreadbase.cpp
node/processor/videorenderer/videorendererdownloadthread.h
node/processor/videorenderer/videorendererdownloadthread.cpp
node/processor/videorenderer/videorendererprocessthread.h
node/processor/videorenderer/videorendererprocessthread.cpp
PARENT_SCOPE
)
@@ -18,7 +18,7 @@
***/
#include "renderer.h"
#include "videorenderer.h"
#include <OpenImageIO/imageio.h>
#include <QApplication>
@@ -31,7 +31,7 @@
#include "common/filefunctions.h"
#include "render/pixelservice.h"
RendererProcessor::RendererProcessor() :
VideoRendererProcessor::VideoRendererProcessor() :
started_(false),
width_(0),
height_(0),
@@ -52,27 +52,27 @@ RendererProcessor::RendererProcessor() :
AddParameter(texture_output_);
}
QString RendererProcessor::Name()
QString VideoRendererProcessor::Name()
{
return tr("Renderer");
return tr("Video Renderer");
}
QString RendererProcessor::Category()
QString VideoRendererProcessor::Category()
{
return tr("Processor");
}
QString RendererProcessor::Description()
QString VideoRendererProcessor::Description()
{
return tr("A multi-threaded OpenGL hardware-accelerated node compositor.");
}
QString RendererProcessor::id()
QString VideoRendererProcessor::id()
{
return "org.olivevideoeditor.Olive.renderervenus";
}
void RendererProcessor::SetCacheName(const QString &s)
void VideoRendererProcessor::SetCacheName(const QString &s)
{
cache_name_ = s;
cache_time_ = QDateTime::currentMSecsSinceEpoch();
@@ -80,7 +80,7 @@ void RendererProcessor::SetCacheName(const QString &s)
GenerateCacheIDInternal();
}
QVariant RendererProcessor::Value(NodeOutput* output, const rational& time)
QVariant VideoRendererProcessor::Value(NodeOutput* output, const rational& time)
{
if (output == texture_output_) {
if (!texture_input_->IsConnected()) {
@@ -123,12 +123,12 @@ QVariant RendererProcessor::Value(NodeOutput* output, const rational& time)
return 0;
}
void RendererProcessor::Release()
void VideoRendererProcessor::Release()
{
Stop();
}
void RendererProcessor::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
void VideoRendererProcessor::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from)
{
Q_UNUSED(from)
@@ -202,13 +202,13 @@ void RendererProcessor::InvalidateCache(const rational &start_range, const ratio
CacheNext();
}
void RendererProcessor::SetTimebase(const rational &timebase)
void VideoRendererProcessor::SetTimebase(const rational &timebase)
{
timebase_ = timebase;
timebase_dbl_ = timebase_.toDouble();
}
void RendererProcessor::SetParameters(const int &width,
void VideoRendererProcessor::SetParameters(const int &width,
const int &height,
const olive::PixelFormat &format,
const olive::RenderMode &mode,
@@ -235,7 +235,7 @@ void RendererProcessor::SetParameters(const int &width,
GenerateCacheIDInternal();
}
void RendererProcessor::SetDivider(const int &divider)
void VideoRendererProcessor::SetDivider(const int &divider)
{
Q_ASSERT(divider_ > 0);
@@ -249,7 +249,7 @@ void RendererProcessor::SetDivider(const int &divider)
GenerateCacheIDInternal();
}
void RendererProcessor::Start()
void VideoRendererProcessor::Start()
{
if (started_) {
return;
@@ -294,7 +294,7 @@ void RendererProcessor::Start()
for (int i=0;i<download_threads_.size();i++) {
// Create download thread
download_threads_[i] = std::make_shared<RendererDownloadThread>(ctx, effective_width_, effective_height_, divider_, format_, mode_);
download_threads_[i] = std::make_shared<VideoRendererDownloadThread>(ctx, effective_width_, effective_height_, divider_, format_, mode_);
download_threads_[i]->StartThread(QThread::LowPriority);
connect(download_threads_[i].get(),
@@ -318,7 +318,7 @@ void RendererProcessor::Start()
started_ = true;
}
void RendererProcessor::Stop()
void VideoRendererProcessor::Stop()
{
if (!started_) {
return;
@@ -341,7 +341,7 @@ void RendererProcessor::Stop()
cache_frame_load_buffer_.clear();
}
void RendererProcessor::GenerateCacheIDInternal()
void VideoRendererProcessor::GenerateCacheIDInternal()
{
if (cache_name_.isEmpty() || effective_width_ == 0 || effective_height_ == 0) {
return;
@@ -360,7 +360,7 @@ void RendererProcessor::GenerateCacheIDInternal()
cache_id_ = bytes.toHex();
}
void RendererProcessor::CacheNext()
void VideoRendererProcessor::CacheNext()
{
if (cache_queue_.isEmpty() || !texture_input_->IsConnected() || caching_) {
return;
@@ -378,7 +378,7 @@ void RendererProcessor::CacheNext()
caching_ = true;
}
QString RendererProcessor::CachePathName(const QByteArray &hash)
QString VideoRendererProcessor::CachePathName(const QByteArray &hash)
{
QDir this_cache_dir = QDir(GetMediaCacheLocation()).filePath(cache_id_);
this_cache_dir.mkpath(".");
@@ -388,17 +388,17 @@ QString RendererProcessor::CachePathName(const QByteArray &hash)
return this_cache_dir.filePath(filename);
}
void RendererProcessor::DeferMap(const rational &time, const QByteArray &hash)
void VideoRendererProcessor::DeferMap(const rational &time, const QByteArray &hash)
{
deferred_maps_.append({time, hash});
}
bool RendererProcessor::HasHash(const QByteArray &hash)
bool VideoRendererProcessor::HasHash(const QByteArray &hash)
{
return QFileInfo::exists(CachePathName(hash));
}
bool RendererProcessor::IsCaching(const QByteArray &hash)
bool VideoRendererProcessor::IsCaching(const QByteArray &hash)
{
cache_hash_list_mutex_.lock();
@@ -409,7 +409,7 @@ bool RendererProcessor::IsCaching(const QByteArray &hash)
return is_caching;
}
bool RendererProcessor::TryCache(const QByteArray &hash)
bool VideoRendererProcessor::TryCache(const QByteArray &hash)
{
cache_hash_list_mutex_.lock();
@@ -424,13 +424,13 @@ bool RendererProcessor::TryCache(const QByteArray &hash)
return !is_caching;
}
void RendererProcessor::CalculateEffectiveDimensions()
void VideoRendererProcessor::CalculateEffectiveDimensions()
{
effective_width_ = width_ / divider_;
effective_height_ = height_ / divider_;
}
void RendererProcessor::ThreadCallback(RenderTexturePtr texture, const rational& time, const QByteArray& hash)
void VideoRendererProcessor::ThreadCallback(RenderTexturePtr texture, const rational& time, const QByteArray& hash)
{
// Threads are all done now, time to proceed
caching_ = false;
@@ -461,7 +461,7 @@ void RendererProcessor::ThreadCallback(RenderTexturePtr texture, const rational&
CacheNext();
}
void RendererProcessor::ThreadRequestSibling(NodeDependency dep)
void VideoRendererProcessor::ThreadRequestSibling(NodeDependency dep)
{
// Try to queue another thread to run this dep in advance
for (int i=1;i<threads_.size();i++) {
@@ -471,7 +471,7 @@ void RendererProcessor::ThreadRequestSibling(NodeDependency dep)
}
}
void RendererProcessor::ThreadSkippedFrame(const rational& time, const QByteArray& hash)
void VideoRendererProcessor::ThreadSkippedFrame(const rational& time, const QByteArray& hash)
{
caching_ = false;
@@ -491,7 +491,7 @@ void RendererProcessor::ThreadSkippedFrame(const rational& time, const QByteArra
CacheNext();
}
void RendererProcessor::DownloadThreadComplete(const QByteArray &hash)
void VideoRendererProcessor::DownloadThreadComplete(const QByteArray &hash)
{
cache_hash_list_mutex_.lock();
cache_hash_list_.removeAll(hash);
@@ -510,14 +510,14 @@ void RendererProcessor::DownloadThreadComplete(const QByteArray &hash)
}
}
RendererThreadBase* RendererProcessor::CurrentThread()
VideoRendererThreadBase* VideoRendererProcessor::CurrentThread()
{
return dynamic_cast<RendererThreadBase*>(QThread::currentThread());
return dynamic_cast<VideoRendererThreadBase*>(QThread::currentThread());
}
RenderInstance *RendererProcessor::CurrentInstance()
RenderInstance *VideoRendererProcessor::CurrentInstance()
{
RendererThreadBase* thread = CurrentThread();
VideoRendererThreadBase* thread = CurrentThread();
if (thread != nullptr) {
return thread->render_instance();
@@ -526,17 +526,17 @@ RenderInstance *RendererProcessor::CurrentInstance()
return nullptr;
}
NodeInput *RendererProcessor::texture_input()
NodeInput *VideoRendererProcessor::texture_input()
{
return texture_input_;
}
NodeInput *RendererProcessor::length_input()
NodeInput *VideoRendererProcessor::length_input()
{
return length_input_;
}
NodeOutput *RendererProcessor::texture_output()
NodeOutput *VideoRendererProcessor::texture_output()
{
return texture_output_;
}
@@ -27,13 +27,13 @@
#include "node/node.h"
#include "render/pixelformat.h"
#include "render/rendermodes.h"
#include "rendererdownloadthread.h"
#include "rendererprocessthread.h"
#include "videorendererdownloadthread.h"
#include "videorendererprocessthread.h"
/**
* @brief A multithreaded OpenGL based renderer for node systems
*/
class RendererProcessor : public Node
class VideoRendererProcessor : public Node
{
Q_OBJECT
public:
@@ -43,7 +43,7 @@ public:
* Constructing a Renderer object will not start any threads/backend on its own. Use Start() to do this and Stop()
* when the Renderer is about to be destroyed.
*/
RendererProcessor();
VideoRendererProcessor();
virtual QString Name() override;
virtual QString Category() override;
@@ -105,7 +105,7 @@ public:
* This function attempts a dynamic_cast on QThread::currentThread() to RendererThread, which will return nullptr if
* the cast fails (e.g. if this function is called from the main thread rather than a RendererThread).
*/
static RendererThreadBase* CurrentThread();
static VideoRendererThreadBase* CurrentThread();
static RenderInstance* CurrentInstance();
@@ -1,4 +1,4 @@
#include "rendererdownloadthread.h"
#include "videorendererdownloadthread.h"
#include <QFile>
#include <QFloat16>
@@ -7,18 +7,18 @@
#include "common/define.h"
#include "render/pixelservice.h"
RendererDownloadThread::RendererDownloadThread(QOpenGLContext *share_ctx,
const int &width,
const int &height,
const int &divider,
const olive::PixelFormat &format,
const olive::RenderMode &mode) :
RendererThreadBase(share_ctx, width, height, divider, format, mode),
VideoRendererDownloadThread::VideoRendererDownloadThread(QOpenGLContext *share_ctx,
const int &width,
const int &height,
const int &divider,
const olive::PixelFormat &format,
const olive::RenderMode &mode) :
VideoRendererThreadBase(share_ctx, width, height, divider, format, mode),
cancelled_(false)
{
}
void RendererDownloadThread::Queue(RenderTexturePtr texture, const QString& fn, const QByteArray &hash)
void VideoRendererDownloadThread::Queue(RenderTexturePtr texture, const QString& fn, const QByteArray &hash)
{
texture_queue_lock_.lock();
@@ -29,7 +29,7 @@ void RendererDownloadThread::Queue(RenderTexturePtr texture, const QString& fn,
texture_queue_lock_.unlock();
}
void RendererDownloadThread::Cancel()
void VideoRendererDownloadThread::Cancel()
{
cancelled_ = true;
@@ -40,7 +40,7 @@ void RendererDownloadThread::Cancel()
wait();
}
void RendererDownloadThread::ProcessLoop()
void VideoRendererDownloadThread::ProcessLoop()
{
QOpenGLFunctions* f = render_instance()->context()->functions();
QOpenGLExtraFunctions* xf = render_instance()->context()->extraFunctions();
@@ -1,13 +1,13 @@
#ifndef RENDERERDOWNLOADTHREAD_H
#define RENDERERDOWNLOADTHREAD_H
#include "rendererthreadbase.h"
#include "videorendererthreadbase.h"
class RendererDownloadThread : public RendererThreadBase
class VideoRendererDownloadThread : public VideoRendererThreadBase
{
Q_OBJECT
public:
RendererDownloadThread(QOpenGLContext* share_ctx,
VideoRendererDownloadThread(QOpenGLContext* share_ctx,
const int& width,
const int& height,
const int &divider,
@@ -44,6 +44,6 @@ private:
};
using RendererDownloadThreadPtr = std::shared_ptr<RendererDownloadThread>;
using RendererDownloadThreadPtr = std::shared_ptr<VideoRendererDownloadThread>;
#endif // RENDERERDOWNLOADTHREAD_H
@@ -18,18 +18,18 @@
***/
#include "rendererprocessthread.h"
#include "videorendererprocessthread.h"
#include "renderer.h"
#include "videorenderer.h"
RendererProcessThread::RendererProcessThread(RendererProcessor* parent,
RendererProcessThread::RendererProcessThread(VideoRendererProcessor* parent,
QOpenGLContext *share_ctx,
const int &width,
const int &height,
const int &divider,
const olive::PixelFormat &format,
const olive::RenderMode &mode) :
RendererThreadBase(share_ctx, width, height, divider, format, mode),
VideoRendererThreadBase(share_ctx, width, height, divider, format, mode),
parent_(parent),
cancelled_(false)
{
@@ -21,15 +21,15 @@
#ifndef RENDERERPROCESSTHREAD_H
#define RENDERERPROCESSTHREAD_H
#include "rendererthreadbase.h"
#include "videorendererthreadbase.h"
class RendererProcessor;
class VideoRendererProcessor;
class RendererProcessThread : public RendererThreadBase
class RendererProcessThread : public VideoRendererThreadBase
{
Q_OBJECT
public:
RendererProcessThread(RendererProcessor* parent,
RendererProcessThread(VideoRendererProcessor* parent,
QOpenGLContext* share_ctx,
const int& width,
const int& height, const int &divider,
@@ -52,7 +52,7 @@ signals:
void FrameSkipped(const rational& time, const QByteArray& hash);
private:
RendererProcessor* parent_;
VideoRendererProcessor* parent_;
NodeDependency path_;
@@ -18,23 +18,23 @@
***/
#include "rendererthreadbase.h"
#include "videorendererthreadbase.h"
#include <QDebug>
RendererThreadBase::RendererThreadBase(QOpenGLContext *share_ctx, const int &width, const int &height, const int &divider, const olive::PixelFormat &format, const olive::RenderMode &mode) :
VideoRendererThreadBase::VideoRendererThreadBase(QOpenGLContext *share_ctx, const int &width, const int &height, const int &divider, const olive::PixelFormat &format, const olive::RenderMode &mode) :
share_ctx_(share_ctx),
render_instance_(width, height, divider, format, mode)
{
connect(share_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Cancel()));
}
RenderInstance *RendererThreadBase::render_instance()
RenderInstance *VideoRendererThreadBase::render_instance()
{
return &render_instance_;
}
void RendererThreadBase::run()
void VideoRendererThreadBase::run()
{
// Lock mutex for main loop
mutex_.lock();
@@ -61,7 +61,7 @@ void RendererThreadBase::run()
mutex_.unlock();
}
void RendererThreadBase::WakeCaller()
void VideoRendererThreadBase::WakeCaller()
{
// Signal that main thread can continue now
caller_mutex_.lock();
@@ -69,7 +69,7 @@ void RendererThreadBase::WakeCaller()
caller_mutex_.unlock();
}
void RendererThreadBase::StartThread(QThread::Priority priority)
void VideoRendererThreadBase::StartThread(QThread::Priority priority)
{
caller_mutex_.lock();
@@ -29,11 +29,11 @@
#include "node/node.h"
#include "render/renderinstance.h"
class RendererThreadBase : public QThread
class VideoRendererThreadBase : public QThread
{
Q_OBJECT
public:
RendererThreadBase(QOpenGLContext* share_ctx,
VideoRendererThreadBase(QOpenGLContext* share_ctx,
const int& width,
const int& height,
const int& divider,
@@ -67,6 +67,6 @@ private:
};
using RendererThreadPtr = std::shared_ptr<RendererThreadBase>;
using RendererThreadPtr = std::shared_ptr<VideoRendererThreadBase>;
#endif // RENDERTHREAD_H
+13 -13
View File
@@ -32,7 +32,7 @@
Sequence::Sequence() :
timeline_output_(nullptr),
renderer_processor_(nullptr),
video_renderer_processor_(nullptr),
viewer_output_(nullptr),
video_track_output_(nullptr),
audio_track_output_(nullptr)
@@ -61,9 +61,9 @@ void Sequence::AddDefaultNodes()
timeline_output_->SetCanBeDeleted(false);
AddNode(timeline_output_);
renderer_processor_ = new RendererProcessor();
renderer_processor_->SetCanBeDeleted(false);
AddNode(renderer_processor_);
video_renderer_processor_ = new VideoRendererProcessor();
video_renderer_processor_->SetCanBeDeleted(false);
AddNode(video_renderer_processor_);
viewer_output_ = new ViewerOutput();
viewer_output_->SetCanBeDeleted(false);
@@ -78,20 +78,20 @@ void Sequence::AddDefaultNodes()
AddNode(audio_track_output_);
// Connect track to renderer
NodeParam::ConnectEdge(video_track_output_->texture_output(), renderer_processor_->texture_input());
NodeParam::ConnectEdge(video_track_output_->texture_output(), video_renderer_processor_->texture_input());
// Connect renderer to viewer
NodeParam::ConnectEdge(renderer_processor_->texture_output(), viewer_output_->texture_input());
NodeParam::ConnectEdge(video_renderer_processor_->texture_output(), viewer_output_->texture_input());
// Connect track to timeline
NodeParam::ConnectEdge(video_track_output_->track_output(), timeline_output_->track_input(kTrackTypeVideo));
NodeParam::ConnectEdge(audio_track_output_->track_output(), timeline_output_->track_input(kTrackTypeAudio));
// Connect timeline end point to renderer
NodeParam::ConnectEdge(timeline_output_->length_output(), renderer_processor_->length_input());
NodeParam::ConnectEdge(timeline_output_->length_output(), video_renderer_processor_->length_input());
// Update the timebase on these nodes
renderer_processor_->SetCacheName(name());
video_renderer_processor_->SetCacheName(name());
set_video_time_base(video_time_base_);
update_video_parameters();
}
@@ -163,8 +163,8 @@ void Sequence::set_video_time_base(const rational &time_base)
if (viewer_output_ != nullptr)
viewer_output_->SetTimebase(video_time_base_);
if (renderer_processor_ != nullptr)
renderer_processor_->SetTimebase(video_time_base_);
if (video_renderer_processor_ != nullptr)
video_renderer_processor_->SetTimebase(video_time_base_);
}
const rational &Sequence::audio_time_base()
@@ -200,16 +200,16 @@ void Sequence::SetDefaultParameters()
void Sequence::update_video_parameters()
{
if (renderer_processor_ != nullptr) {
if (video_renderer_processor_ != nullptr) {
// Set renderer's parameters based on sequence's parameters
renderer_processor_->SetParameters(video_width_,
video_renderer_processor_->SetParameters(video_width_,
video_height_,
olive::PIX_FMT_RGBA16F, // FIXME: Make this configurable
olive::RenderMode::kOffline,
2);
// Set the "cache name" only here to aid the cache ID's uniqueness
renderer_processor_->SetCacheName(name());
video_renderer_processor_->SetCacheName(name());
}
if (viewer_output_ != nullptr) {
+2 -2
View File
@@ -25,7 +25,7 @@
#include "node/graph.h"
#include "node/output/timeline/timeline.h"
#include "node/output/viewer/viewer.h"
#include "node/processor/renderer/renderer.h"
#include "node/processor/videorenderer/videorenderer.h"
#include "project/item/item.h"
class Sequence;
@@ -78,7 +78,7 @@ private:
void update_video_parameters();
TimelineOutput* timeline_output_;
RendererProcessor* renderer_processor_;
VideoRendererProcessor* video_renderer_processor_;
ViewerOutput* viewer_output_;
TrackOutput* video_track_output_;
TrackOutput* audio_track_output_;
-1
View File
@@ -33,6 +33,5 @@ set(OLIVE_SOURCES
render/renderframebuffer.cpp
render/rendertexture.h
render/rendertexture.cpp
render/sampleformat.h
PARENT_SCOPE
)