renderer: move conform to task
Improved rendering system and user interface Fixes #1375
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <QApplication>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
#include "codec/conformmanager.h"
|
||||
#include "node/project/project.h"
|
||||
#include "render/rendermanager.h"
|
||||
#include "render/renderprocessor.h"
|
||||
@@ -15,7 +16,8 @@ PreviewAutoCacher::PreviewAutoCacher() :
|
||||
use_custom_range_(false),
|
||||
single_frame_render_(nullptr),
|
||||
last_update_time_(0),
|
||||
ignore_next_mouse_button_(false)
|
||||
ignore_next_mouse_button_(false),
|
||||
last_conform_task_(0)
|
||||
{
|
||||
paused_ = !Config::Current()[QStringLiteral("AutoCacheEnabled")].toBool(),
|
||||
|
||||
@@ -24,6 +26,8 @@ PreviewAutoCacher::PreviewAutoCacher() :
|
||||
delayed_requeue_timer_.setInterval(Config::Current()[QStringLiteral("AutoCacheDelay")].toInt());
|
||||
delayed_requeue_timer_.setSingleShot(true);
|
||||
connect(&delayed_requeue_timer_, &QTimer::timeout, this, &PreviewAutoCacher::RequeueFrames);
|
||||
|
||||
connect(ConformManager::instance(), &ConformManager::ConformReady, this, &PreviewAutoCacher::ConformFinished);
|
||||
}
|
||||
|
||||
PreviewAutoCacher::~PreviewAutoCacher()
|
||||
@@ -131,7 +135,7 @@ void PreviewAutoCacher::VideoInvalidated(const TimeRange &range)
|
||||
|
||||
void PreviewAutoCacher::AudioInvalidated(const TimeRange &range)
|
||||
{
|
||||
ClearAudioQueue();
|
||||
// ClearAudioQueue();
|
||||
|
||||
// Start jobs to re-render the audio at this range, split into 2 second chunks
|
||||
invalidated_audio_.insert(range);
|
||||
@@ -165,35 +169,52 @@ void PreviewAutoCacher::AudioRendered()
|
||||
|
||||
if (audio_tasks_.contains(watcher)) {
|
||||
if (watcher->HasResult()) {
|
||||
viewer_node_->audio_playback_cache()->WritePCM(audio_tasks_.value(watcher),
|
||||
const TimeRange &range = audio_tasks_.value(watcher);
|
||||
|
||||
viewer_node_->audio_playback_cache()->WritePCM(range,
|
||||
watcher->Get().value<SampleBufferPtr>(),
|
||||
watcher->GetTicket()->GetJobTime());
|
||||
|
||||
// Retrieve visual waveforms
|
||||
QVector<RenderProcessor::RenderedWaveform> waveform_list = watcher->GetTicket()->property("waveforms").value< QVector<RenderProcessor::RenderedWaveform> >();
|
||||
foreach (const RenderProcessor::RenderedWaveform& waveform_info, waveform_list) {
|
||||
// Find original track
|
||||
Track* track = nullptr;
|
||||
bool pcm_is_usable = true;
|
||||
|
||||
for (auto it=copy_map_.cbegin(); it!=copy_map_.cend(); it++) {
|
||||
if (it.value() == waveform_info.track) {
|
||||
track = static_cast<Track*>(it.key());
|
||||
break;
|
||||
}
|
||||
if (watcher->GetTicket()->property("incomplete").toBool()) {
|
||||
if (last_conform_task_ > watcher->GetTicket()->GetJobTime()) {
|
||||
// Requeue now
|
||||
viewer_node_->audio_playback_cache()->Invalidate(range, QDateTime::currentMSecsSinceEpoch());
|
||||
pcm_is_usable = false;
|
||||
} else {
|
||||
// Wait for conform
|
||||
audio_needing_conform_.insert(range);
|
||||
}
|
||||
}
|
||||
|
||||
if (track) {
|
||||
QList<TimeRange> valid_ranges = viewer_node_->audio_playback_cache()->GetValidRanges(waveform_info.range,
|
||||
watcher->GetTicket()->GetJobTime());
|
||||
if (!valid_ranges.isEmpty()) {
|
||||
// Generate visual waveform in this background thread
|
||||
track->waveform().set_channel_count(viewer_node_->GetAudioParams().channel_count());
|
||||
if (pcm_is_usable) {
|
||||
// Retrieve visual waveforms
|
||||
QVector<RenderProcessor::RenderedWaveform> waveform_list = watcher->GetTicket()->property("waveforms").value< QVector<RenderProcessor::RenderedWaveform> >();
|
||||
foreach (const RenderProcessor::RenderedWaveform& waveform_info, waveform_list) {
|
||||
// Find original track
|
||||
Track* track = nullptr;
|
||||
|
||||
foreach (const TimeRange& r, valid_ranges) {
|
||||
track->waveform().OverwriteSums(waveform_info.waveform, r.in(), r.in() - waveform_info.range.in(), r.length());
|
||||
for (auto it=copy_map_.cbegin(); it!=copy_map_.cend(); it++) {
|
||||
if (it.value() == waveform_info.track) {
|
||||
track = static_cast<Track*>(it.key());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit track->PreviewChanged();
|
||||
if (track) {
|
||||
QList<TimeRange> valid_ranges = viewer_node_->audio_playback_cache()->GetValidRanges(waveform_info.range,
|
||||
watcher->GetTicket()->GetJobTime());
|
||||
if (!valid_ranges.isEmpty()) {
|
||||
// Generate visual waveform in this background thread
|
||||
track->waveform().set_channel_count(viewer_node_->GetAudioParams().channel_count());
|
||||
|
||||
foreach (const TimeRange& r, valid_ranges) {
|
||||
track->waveform().OverwriteSums(waveform_info.waveform, r.in(), r.in() - waveform_info.range.in(), r.length());
|
||||
}
|
||||
|
||||
emit track->PreviewChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,7 +512,7 @@ void PreviewAutoCacher::TryRender()
|
||||
RenderTicketWatcher* watcher = new RenderTicketWatcher();
|
||||
connect(watcher, &RenderTicketWatcher::Finished, this, &PreviewAutoCacher::AudioRendered);
|
||||
audio_tasks_.insert(watcher, r);
|
||||
watcher->SetTicket(RenderManager::instance()->RenderAudio(copied_viewer_node_, r, true));
|
||||
watcher->SetTicket(RenderManager::instance()->RenderAudio(copied_viewer_node_, r, RenderMode::kOffline, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,6 +602,18 @@ void PreviewAutoCacher::RequeueFrames()
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::ConformFinished()
|
||||
{
|
||||
last_conform_task_ = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
if (viewer_node_) {
|
||||
foreach (const TimeRange &range, audio_needing_conform_) {
|
||||
viewer_node_->audio_playback_cache()->Invalidate(range, QDateTime::currentMSecsSinceEpoch());
|
||||
}
|
||||
audio_needing_conform_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::IgnoreNextMouseButton()
|
||||
{
|
||||
ignore_next_mouse_button_ = true;
|
||||
@@ -624,6 +657,9 @@ void PreviewAutoCacher::SetViewerNode(ViewerOutput *viewer_node)
|
||||
// No more immediate passthroughts
|
||||
video_immediate_passthroughs_.clear();
|
||||
|
||||
// No more audio conforms
|
||||
audio_needing_conform_.clear();
|
||||
|
||||
// Delete all of our copied nodes
|
||||
qDeleteAll(created_nodes_);
|
||||
created_nodes_.clear();
|
||||
|
||||
@@ -167,6 +167,10 @@ private:
|
||||
|
||||
QTimer delayed_requeue_timer_;
|
||||
|
||||
TimeRangeList audio_needing_conform_;
|
||||
|
||||
qint64 last_conform_task_;
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Handler for when the NodeGraph reports a video change over a certain time range
|
||||
@@ -213,6 +217,8 @@ private slots:
|
||||
*/
|
||||
void RequeueFrames();
|
||||
|
||||
void ConformFinished();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -181,12 +181,12 @@ RenderTicketPtr RenderManager::RenderFrame(ViewerOutput *viewer, ColorManager* c
|
||||
return ticket;
|
||||
}
|
||||
|
||||
RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange& r, bool generate_waveforms, bool prioritize)
|
||||
RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange& r, RenderMode::Mode mode, bool generate_waveforms, bool prioritize)
|
||||
{
|
||||
return RenderAudio(viewer, r, viewer->GetAudioParams(), generate_waveforms, prioritize);
|
||||
return RenderAudio(viewer, r, viewer->GetAudioParams(), mode, generate_waveforms, prioritize);
|
||||
}
|
||||
|
||||
RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange &r, const AudioParams ¶ms, bool generate_waveforms, bool prioritize)
|
||||
RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange &r, const AudioParams ¶ms, RenderMode::Mode mode, bool generate_waveforms, bool prioritize)
|
||||
{
|
||||
// Create ticket
|
||||
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
|
||||
@@ -194,6 +194,7 @@ RenderTicketPtr RenderManager::RenderAudio(ViewerOutput* viewer, const TimeRange
|
||||
ticket->setProperty("viewer", Node::PtrToValue(viewer));
|
||||
ticket->setProperty("time", QVariant::fromValue(r));
|
||||
ticket->setProperty("type", kTypeAudio);
|
||||
ticket->setProperty("mode", mode);
|
||||
ticket->setProperty("enablewaveforms", generate_waveforms);
|
||||
ticket->setProperty("aparam", QVariant::fromValue(params));
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ public:
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*/
|
||||
RenderTicketPtr RenderAudio(ViewerOutput* viewer, const TimeRange& r, const AudioParams& params, bool generate_waveforms, bool prioritize = false);
|
||||
RenderTicketPtr RenderAudio(ViewerOutput *viewer, const TimeRange& r, bool generate_waveforms, bool prioritize = false);
|
||||
RenderTicketPtr RenderAudio(ViewerOutput* viewer, const TimeRange& r, const AudioParams& params, RenderMode::Mode mode, bool generate_waveforms, bool prioritize = false);
|
||||
RenderTicketPtr RenderAudio(ViewerOutput *viewer, const TimeRange& r, RenderMode::Mode mode, bool generate_waveforms, bool prioritize = false);
|
||||
|
||||
RenderTicketPtr SaveFrameToCache(FrameHashCache* cache, FramePtr frame, const QByteArray& hash, bool prioritize = false);
|
||||
|
||||
|
||||
@@ -443,13 +443,15 @@ QVariant RenderProcessor::ProcessAudioFootage(const FootageJob &stream, const Ti
|
||||
if (decoder) {
|
||||
const AudioParams& audio_params = ticket_->property("aparam").value<AudioParams>();
|
||||
|
||||
SampleBufferPtr frame = decoder->RetrieveAudio(input_time, audio_params,
|
||||
stream.cache_path(),
|
||||
stream.loop_mode(),
|
||||
&IsCancelled());
|
||||
Decoder::RetrieveAudioData status = decoder->RetrieveAudio(input_time, audio_params,
|
||||
stream.cache_path(),
|
||||
stream.loop_mode(),
|
||||
static_cast<RenderMode::Mode>(ticket_->property("mode").toInt()));
|
||||
|
||||
if (frame) {
|
||||
value = QVariant::fromValue(frame);
|
||||
if (status.status == Decoder::kOK && status.samples) {
|
||||
value = QVariant::fromValue(status.samples);
|
||||
} else if (status.status == Decoder::kWaitingForConform) {
|
||||
ticket_->setProperty("incomplete", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user