implement audio device to pull directly from renderer

This commit is contained in:
itsmattkc
2021-09-25 12:44:58 -07:00
parent 35873dce01
commit 4c9863a696
14 changed files with 336 additions and 145 deletions
+2
View File
@@ -39,6 +39,8 @@ set(OLIVE_SOURCES
render/managedcolor.h
render/playbackcache.cpp
render/playbackcache.h
render/previewaudiodevice.cpp
render/previewaudiodevice.h
render/previewautocacher.cpp
render/previewautocacher.h
render/renderer.cpp
+111
View File
@@ -0,0 +1,111 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 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 "previewaudiodevice.h"
namespace olive {
PreviewAudioDevice::PreviewAudioDevice(QObject *parent)
{
// These pointers are always valid
using_ = &internal_buffer_[0];
pushing_ = &internal_buffer_[1];
// Default to swap being true because we'll have nothing in the main buffer at first
swap_requested_ = true;
}
PreviewAudioDevice::~PreviewAudioDevice()
{
close();
}
bool PreviewAudioDevice::isSequential() const
{
return true;
}
qint64 PreviewAudioDevice::readData(char *data, qint64 maxSize)
{
if (swap_requested_) {
SwapBuffers(kFullLock);
swap_requested_ = false;
}
// This function should NEVER touch the buffer in `pushing_`
qint64 copy_length = qMin(maxSize, qint64(using_->size()));
if (copy_length) {
memcpy(data, using_->constData(), copy_length);
*using_ = using_->mid(copy_length);
if (using_->isEmpty() && !SwapBuffers(kTryLock)) {
// Ask push function to swap if it can. If it can't, we'll catch it next read.
swap_requested_ = true;
}
}
return copy_length;
}
qint64 PreviewAudioDevice::writeData(const char *, qint64)
{
// No writing to this device
return -1;
}
void PreviewAudioDevice::Push(const QByteArray &b)
{
// This function should NEVER touch the buffer in `using_`
QMutexLocker locker(&lock_);
pushing_->append(b);
// If swap requested, do this now
if (swap_requested_) {
SwapBuffers(kDontLock);
swap_requested_ = false;
}
}
bool PreviewAudioDevice::SwapBuffers(LockMethod m)
{
switch (m) {
case kDontLock:
break;
case kTryLock:
if (!lock_.tryLock()) {
return false;
}
break;
case kFullLock:
lock_.lock();
break;
}
std::swap(using_, pushing_);
if (m != kDontLock) {
lock_.unlock();
}
return true;
}
}
+68
View File
@@ -0,0 +1,68 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 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 PREVIEWAUDIODEVICE_H
#define PREVIEWAUDIODEVICE_H
#include "previewautocacher.h"
namespace olive {
class PreviewAudioDevice : public QIODevice
{
Q_OBJECT
public:
PreviewAudioDevice(QObject *parent = nullptr);
virtual ~PreviewAudioDevice() override;
void StartQueuing();
virtual bool isSequential() const override;
virtual qint64 readData(char *data, qint64 maxSize) override;
virtual qint64 writeData(const char *, qint64) override;
void Push(const QByteArray &b);
private:
enum LockMethod {
kDontLock,
kTryLock,
kFullLock
};
bool SwapBuffers(LockMethod m);
QMutex lock_;
QByteArray internal_buffer_[2];
QByteArray *using_;
QByteArray *pushing_;
QAtomicInt swap_requested_;
};
}
#endif // PREVIEWAUDIODEVICE_H
+38 -32
View File
@@ -1,3 +1,23 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 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 "previewautocacher.h"
#include <QApplication>
@@ -61,6 +81,11 @@ RenderTicketPtr PreviewAutoCacher::GetSingleFrame(const rational &t, bool priori
return sfr;
}
RenderTicketPtr PreviewAutoCacher::GetRangeOfAudio(TimeRange range, bool prioritize)
{
return RenderAudio(range, false, prioritize);
}
QVector<PreviewAutoCacher::HashData> PreviewAutoCacher::GenerateHashes(ViewerOutput *viewer, FrameHashCache* cache, const QVector<rational> &times)
{
QVector<HashData> hash_data(times.size());
@@ -631,11 +656,7 @@ void PreviewAutoCacher::TryRender()
r.set_out(qMin(r.out(), r.in() + 1));
// Start job
RenderTicketWatcher* watcher = new RenderTicketWatcher();
watcher->setProperty("job", QVariant::fromValue(last_update_time_));
connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::AudioRendered);
audio_tasks_.insert(watcher, r);
watcher->SetTicket(RenderManager::instance()->RenderAudio(copied_viewer_node_, r, RenderMode::kOffline, true));
RenderAudio(r, true, false);
audio_iterator_.remove(r);
}
@@ -658,6 +679,18 @@ RenderTicketWatcher* PreviewAutoCacher::RenderFrame(const QByteArray &hash, cons
return watcher;
}
RenderTicketPtr PreviewAutoCacher::RenderAudio(const TimeRange &r, bool generate_waveforms, bool prioritize)
{
RenderTicketWatcher* watcher = new RenderTicketWatcher();
watcher->setProperty("job", QVariant::fromValue(last_update_time_));
connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::AudioRendered);
audio_tasks_.insert(watcher, r);
RenderTicketPtr ticket = RenderManager::instance()->RenderAudio(copied_viewer_node_, r, RenderMode::kOffline, generate_waveforms, prioritize);
watcher->SetTicket(ticket);
return ticket;
}
void PreviewAutoCacher::RequeueFrames()
{
delayed_requeue_timer_.stop();
@@ -887,31 +920,4 @@ void PreviewAutoCacher::SetViewerNode(ViewerOutput *viewer_node)
}
}
PreviewAutoCacher::PlaybackDevice::PlaybackDevice(PreviewAutoCacher *cacher, QObject *parent) :
cacher_(cacher),
current_time_(0)
{
audio_params_ = viewer()->GetAudioParams();
}
bool PreviewAutoCacher::PlaybackDevice::seek(qint64 pos)
{
// Call super function
if (QIODevice::seek(pos)) {
// Convert bytes to time
current_time_ = audio_params_.bytes_to_time(pos);
return true;
}
return false;
}
qint64 PreviewAutoCacher::PlaybackDevice::size() const
{
rational audio_length = cacher_->copied_viewer_node_->GetAudioLength();
return audio_params_.time_to_bytes(audio_length);
}
}
+23 -31
View File
@@ -1,3 +1,23 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 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 AUTOCACHER_H
#define AUTOCACHER_H
@@ -30,6 +50,8 @@ public:
RenderTicketPtr GetSingleFrame(const rational& t, bool prioritize);
RenderTicketPtr GetRangeOfAudio(TimeRange range, bool prioritize);
/**
* @brief Set the viewer node to auto-cache
*/
@@ -72,41 +94,11 @@ public:
void CancelVideoTasks(bool and_wait_for_them_to_finish = false);
void CancelAudioTasks(bool and_wait_for_them_to_finish = false);
class PlaybackDevice : public QIODevice
{
public:
PlaybackDevice(PreviewAutoCacher *cacher, QObject *parent = nullptr);
virtual ~PlaybackDevice() override;
virtual bool isSequential() const override;
virtual bool seek(qint64 pos) override;
virtual qint64 size() const override;
virtual qint64 readData(char *data, qint64 maxSize) override;
virtual qint64 writeData(const char *, qint64) override;
ViewerOutput *viewer() const
{
return cacher_->copied_viewer_node_;
}
private:
PreviewAutoCacher *cacher_;
rational current_time_;
AudioParams audio_params_;
};
private:
void TryRender();
RenderTicketWatcher *RenderFrame(const QByteArray& hash, const rational &time, bool prioritize, bool texture_only);
RenderTicketPtr RenderAudio(const TimeRange &range, bool generate_waveforms, bool prioritize);
/**
* @brief Process all changes to internal NodeGraph copy