export: fixed audio exporting with new renderer system

This commit is contained in:
itsmattkc
2020-05-21 02:18:52 +10:00
parent a2d68f6d9f
commit d5766489e4
15 changed files with 246 additions and 142 deletions
+37 -44
View File
@@ -34,11 +34,7 @@ OLIVE_NAMESPACE_ENTER
RenderBackend::RenderBackend(QObject *parent) :
QObject(parent),
viewer_node_(nullptr),
audio_mode_(kAudioPreview),
divider_(1),
render_mode_(RenderMode::kOnline),
pix_fmt_(PixelFormat::PIX_FMT_RGBA32F),
sample_fmt_(SampleFormat::SAMPLE_FMT_FLT),
auto_audio_(true),
ic_from_conform_(false)
{
// FIXME: Don't create in CLI mode
@@ -91,7 +87,7 @@ void RenderBackend::SetViewerNode(ViewerOutput *viewer_node)
this,
&RenderBackend::NodeGraphChanged);
if (audio_mode_ == kAudioPreview) {
if (auto_audio_) {
// Listen for audio invalidation signals
connect(viewer_node_->audio_playback_cache(),
&AudioPlaybackCache::Invalidated,
@@ -136,24 +132,23 @@ QFuture<FramePtr> RenderBackend::RenderFrame(const rational &time, bool clear_qu
block_for_update);
}
void RenderBackend::SetDivider(const int &divider)
QFuture<SampleBufferPtr> RenderBackend::RenderAudio(const TimeRange &r, bool block_for_update)
{
divider_ = divider;
return QtConcurrent::run(&audio_pool_.threads,
GetInstanceFromPool(audio_pool_),
&RenderWorker::RenderAudio,
r,
block_for_update);
}
void RenderBackend::SetMode(const RenderMode::Mode &mode)
void RenderBackend::SetVideoParams(const VideoRenderingParams &params)
{
render_mode_ = mode;
video_params_ = params;
}
void RenderBackend::SetPixelFormat(const PixelFormat::Format &pix_fmt)
void RenderBackend::SetAudioParams(const AudioRenderingParams &params)
{
pix_fmt_ = pix_fmt;
}
void RenderBackend::SetSampleFormat(const SampleFormat::Format &sample_fmt)
{
sample_fmt_ = sample_fmt;
audio_params_ = params;
}
void RenderBackend::SetVideoDownloadMatrix(const QMatrix4x4 &mat)
@@ -161,9 +156,9 @@ void RenderBackend::SetVideoDownloadMatrix(const QMatrix4x4 &mat)
video_download_matrix_ = mat;
}
void RenderBackend::SetAudioMode(AudioMode e)
void RenderBackend::SetAutomaticAudio(bool e)
{
audio_mode_ = e;
auto_audio_ = e;
}
void RenderBackend::WorkerStartedRenderingAudio(const TimeRange &r)
@@ -173,6 +168,23 @@ void RenderBackend::WorkerStartedRenderingAudio(const TimeRange &r)
queued_audio_lock_.unlock();
}
QList<TimeRange> RenderBackend::SplitRangeIntoChunks(const TimeRange &r)
{
const int chunk_size = 2;
QList<TimeRange> split_ranges;
int start_time = qFloor(r.in().toDouble() / static_cast<double>(chunk_size)) * chunk_size;
int end_time = qCeil(r.out().toDouble() / static_cast<double>(chunk_size)) * chunk_size;
for (int i=start_time; i<end_time; i+=chunk_size) {
split_ranges.append(TimeRange(qMax(r.in(), rational(i)),
qMin(r.out(), rational(i + chunk_size))));
}
return split_ranges;
}
void RenderBackend::NodeGraphChanged(NodeInput *source)
{
video_pool_.Queue(source);
@@ -184,9 +196,10 @@ void RenderBackend::UpdateInstance(RenderWorker *instance)
{
instance->SetAvailable(false);
instance->ProcessQueue();
instance->SetVideoParams(video_params());
instance->SetAudioParams(audio_params());
instance->SetVideoParams(video_params_);
instance->SetAudioParams(audio_params_);
instance->SetVideoDownloadMatrix(video_download_matrix_);
instance->SetAudioModeIsPreview(auto_audio_);
}
void RenderBackend::Close()
@@ -198,16 +211,6 @@ void RenderBackend::Close()
hash_pool_.Destroy();
}
VideoRenderingParams RenderBackend::video_params() const
{
return VideoRenderingParams(viewer_node_->video_params(), pix_fmt_, render_mode_, divider_);
}
AudioRenderingParams RenderBackend::audio_params() const
{
return AudioRenderingParams(viewer_node_->audio_params(), sample_fmt_);
}
RenderWorker *RenderBackend::GetInstanceFromPool(RenderPool& pool)
{
RenderWorker* instance = nullptr;
@@ -361,15 +364,9 @@ void RenderBackend::AudioInvalidated(const TimeRange& r)
}
// Split into 2 second chunks, one for each thread
const int chunk_size = 2;
QList<TimeRange> split_ranges = SplitRangeIntoChunks(r);
QList<TimeRange> split_ranges;
int start_time = qFloor(r.in().toDouble() / static_cast<double>(chunk_size)) * chunk_size;
int end_time = qCeil(r.out().toDouble() / static_cast<double>(chunk_size)) * chunk_size;
for (int i=start_time; i<end_time; i+=chunk_size) {
TimeRange this_range(qMax(r.in(), rational(i)),
qMin(r.out(), rational(i + chunk_size)));
foreach (const TimeRange& this_range, split_ranges) {
{
// Check if this range is already in the queue but hasn't started yet, in which case it'll
@@ -388,11 +385,7 @@ void RenderBackend::AudioInvalidated(const TimeRange& r)
audio_jobs_.insert(watcher, this_range);
watcher->setFuture(QtConcurrent::run(&audio_pool_.threads,
GetInstanceFromPool(audio_pool_),
&RenderWorker::RenderAudio,
this_range,
audio_mode_ == kAudioPreview));
watcher->setFuture(RenderAudio(this_range, auto_audio_));
}
}
+12 -21
View File
@@ -54,26 +54,23 @@ public:
*/
QFuture<FramePtr> RenderFrame(const rational& time, bool clear_queue, bool block_for_update);
void SetDivider(const int& divider);
/**
* @brief Asynchronously generate a chunk of audio
*/
QFuture<SampleBufferPtr> RenderAudio(const TimeRange& r, bool block_for_update);
void SetMode(const RenderMode::Mode& mode);
void SetVideoParams(const VideoRenderingParams& params);
void SetPixelFormat(const PixelFormat::Format& pix_fmt);
void SetSampleFormat(const SampleFormat::Format& sample_fmt);
void SetAudioParams(const AudioRenderingParams& params);
void SetVideoDownloadMatrix(const QMatrix4x4& mat);
enum AudioMode {
kAudioDisabled,
kAudioPreview,
kAudioRender
};
void SetAudioMode(AudioMode e);
void SetAutomaticAudio(bool e);
void WorkerStartedRenderingAudio(const TimeRange& r);
static QList<TimeRange> SplitRangeIntoChunks(const TimeRange& r);
public slots:
void NodeGraphChanged(NodeInput *source);
@@ -84,10 +81,6 @@ protected:
void Close();
VideoRenderingParams video_params() const;
AudioRenderingParams audio_params() const;
private:
struct RenderPool {
QVector<RenderWorker*> instances;
@@ -113,16 +106,14 @@ private:
QMutex queued_audio_lock_;
TimeRangeList queued_audio_;
AudioMode audio_mode_;
bool auto_audio_;
// VIDEO MEMBERS
int divider_;
RenderMode::Mode render_mode_;
PixelFormat::Format pix_fmt_;
VideoRenderingParams video_params_;
QMatrix4x4 video_download_matrix_;
// AUDIO MEMBERS
SampleFormat::Format sample_fmt_;
AudioRenderingParams audio_params_;
QHash< QFutureWatcher<SampleBufferPtr>*, TimeRange > audio_jobs_;
struct ConformWaitInfo {
+46 -4
View File
@@ -25,6 +25,7 @@
#include "audio/sumsamples.h"
#include "config/config.h"
#include "node/block/clip/clip.h"
#include "task/conform/conform.h"
#include "renderbackend.h"
OLIVE_NAMESPACE_ENTER
@@ -32,7 +33,8 @@ OLIVE_NAMESPACE_ENTER
RenderWorker::RenderWorker(RenderBackend* parent) :
parent_(parent),
viewer_(nullptr),
available_(true)
available_(true),
audio_mode_is_preview_(false)
{
}
@@ -359,8 +361,51 @@ NodeValue RenderWorker::GetDataFromStream(StreamPtr stream, const TimeRange &inp
if (decoder) {
if (stream->type() == Stream::kVideo || stream->type() == Stream::kImage) {
// Return a texture from the derived class
return FrameToTexture(decoder, stream, input_time);
} else if (stream->type() == Stream::kAudio) {
// See if we have a conformed version of this audio
if (!decoder->HasConformedVersion(audio_params())) {
// If not, check what audio mode we're in
if (audio_mode_is_preview_) {
// For preview, we report the conform is missing and finish the render without it
// temporarily. The backend that picks up this signal will recache this section once the
// conform is available.
emit AudioConformUnavailable(decoder->stream(),
audio_render_time_,
input_time.out(),
audio_params());
} else {
// For online rendering/export, it's a waste of time to render the audio until we have
// all we need, so we try to handle the conform ourselves
AudioStreamPtr as = std::static_pointer_cast<AudioStream>(stream);
// Check if any other threads are conforming this audio
if (as->try_start_conforming(audio_params())) {
// If not, conform it ourselves
decoder->ConformAudio(&IsCancelled(), audio_params());
} else {
// If another thread is conforming already, hackily try to wait until it's done.
do {
QThread::msleep(1000);
} while (!as->has_conformed_version(audio_params()) && !IsCancelled());
}
}
}
if (decoder->HasConformedVersion(audio_params())) {
SampleBufferPtr frame = decoder->RetrieveAudio(input_time.in(), input_time.length(),
audio_params());
@@ -368,9 +413,6 @@ NodeValue RenderWorker::GetDataFromStream(StreamPtr stream, const TimeRange &inp
if (frame) {
return NodeValue(NodeParam::kSamples, QVariant::fromValue(frame));
}
} else {
emit AudioConformUnavailable(decoder->stream(), audio_render_time_,
input_time.out(), audio_params());
}
}
}
+7
View File
@@ -75,6 +75,11 @@ public:
video_download_matrix_ = mat;
}
void SetAudioModeIsPreview(bool audio_mode_is_preview)
{
audio_mode_is_preview_ = audio_mode_is_preview;
}
/**
* @brief Return a unique ID for the image generated at this time
*
@@ -166,6 +171,8 @@ private:
QHash<Node*, Node*> copy_map_;
bool available_;
bool audio_mode_is_preview_;
QMutex lock_;
};