decoder/renderer: no longer index automatically as part of the retrieve

functions

Indexing is a lengthy process and had a high chance of getting RenderWorkers
stuck doing it rather than being responsive to cache requests. This commit
introduces a system where workers never index media, but instead signal that
media is not ready to their RenderBackends which ensure that the media gets
indexed and re-queues the affected frames when those indexes are ready.
This commit is contained in:
itsmattkc
2020-02-19 11:44:29 +11:00
parent 5e75e9b3b0
commit 03bdf01357
28 changed files with 461 additions and 197 deletions
+106 -21
View File
@@ -4,6 +4,7 @@
#include <QThread>
#include "core.h"
#include "render/indexmanager.h"
#include "window/mainwindow/mainwindow.h"
RenderBackend::RenderBackend(QObject *parent) :
@@ -17,6 +18,8 @@ RenderBackend::RenderBackend(QObject *parent) :
{
// FIXME: Don't create in CLI mode
cancel_dialog_ = new RenderCancelDialog(Core::instance()->main_window());
connect(IndexManager::instance(), &IndexManager::StreamIndexUpdated, this, &RenderBackend::IndexUpdated);
}
bool RenderBackend::Init()
@@ -111,27 +114,6 @@ bool RenderBackend::IsInitiated()
return started_;
}
void RenderBackend::InvalidateCache(const rational &start_range, const rational &end_range)
{
if (!CanRender()) {
return;
}
// Adjust range to min/max values
rational start_range_adj = qMax(rational(0), start_range);
rational end_range_adj = qMin(GetSequenceLength(), end_range);
qDebug() << "Cache invalidated between"
<< start_range_adj.toDouble()
<< "and"
<< end_range_adj.toDouble();
// Queue value update
QueueValueUpdate();
InvalidateCacheInternal(start_range_adj, end_range_adj);
}
bool RenderBackend::Compile()
{
if (compiled_) {
@@ -347,6 +329,27 @@ void RenderBackend::CancelQueue()
cancel_dialog_->RunIfWorkersAreBusy();
}
void RenderBackend::InvalidateCache(const TimeRange &range)
{
if (!CanRender()) {
return;
}
// Adjust range to min/max values
rational start_range_adj = qMax(rational(0), range.in());
rational end_range_adj = qMin(GetSequenceLength(), range.out());
qDebug() << "Cache invalidated between"
<< start_range_adj.toDouble()
<< "and"
<< end_range_adj.toDouble();
// Queue value update
QueueValueUpdate();
InvalidateCacheInternal(start_range_adj, end_range_adj);
}
bool RenderBackend::ViewerIsConnected() const
{
return viewer_node_ != nullptr;
@@ -412,6 +415,7 @@ void RenderBackend::InitWorkers()
// Connect cancel dialog to it
connect(processor, &RenderWorker::CompletedCache, cancel_dialog_, &RenderCancelDialog::WorkerDone, Qt::QueuedConnection);
connect(processor, &RenderWorker::FootageUnavailable, this, &RenderBackend::FootageUnavailable, Qt::QueuedConnection);
// Finally, we can move it to its own thread
processor->moveToThread(thread);
@@ -428,3 +432,84 @@ void RenderBackend::QueueRecompile()
{
recompile_queued_ = true;
}
void RenderBackend::FootageUnavailable(StreamPtr stream, Decoder::RetrieveState state, const TimeRange &range, const rational &stream_time)
{
if (state == Decoder::kFailedToOpen){
qWarning() << "For range" << range.in() << "-" << range.out() << stream->footage()->filename() << "stream" << stream->index() << "failed to open";
} else if (state == Decoder::kIndexUnavailable) {
FootageWaitInfo info = {stream, range, stream_time};
foreach (const FootageWaitInfo& compare, footage_wait_info_) {
if (info.stream == compare.stream
&& info.stream_time == compare.stream_time
&& info.affected_range == compare.affected_range) {
return;
}
}
qDebug() << "Waiting for" << stream.get() << "time" << stream_time.toDouble() << "for frame" << range.in();
if (IndexManager::instance()->IsIndexing(stream)) {
footage_wait_info_.append(info);
} else if ((stream->type() == Stream::kVideo && std::static_pointer_cast<VideoStream>(stream)->is_frame_index_ready())
|| (stream->type() == Stream::kAudio && std::static_pointer_cast<AudioStream>(stream)->index_done())) {
// Index JUST finished, requeue this time
InvalidateCache(range);
} else {
// Start indexing process
footage_wait_info_.append(info);
IndexManager::instance()->StartIndexingStream(stream);
}
}
}
void RenderBackend::IndexUpdated(Stream* stream)
{
for (int i=0;i<footage_wait_info_.size();i++) {
const FootageWaitInfo& info = footage_wait_info_.at(i);
if (info.stream.get() == stream) {
bool footage_ready = false;
// See if this stream now has an index for the requested time
if (stream->type() == Stream::kVideo) {
VideoStream* video_stream = static_cast<VideoStream*>(stream);
if (video_stream->get_closest_timestamp_in_frame_index(info.stream_time) >= 0) {
// This index now has this frame, we can re-render it
qDebug() << "Re-ICing video" << info.affected_range.in().toDouble() << "to" << info.affected_range.out().toDouble();
footage_ready = true;
}
} else if (stream->type() == Stream::kAudio) {
AudioStream* audio_stream = static_cast<AudioStream*>(stream);
if (audio_stream->index_length() >= info.stream_time) {
// The index now has this audio, we can re-render it
qDebug() << "Re-ICing audio" << info.affected_range.in().toDouble() << "to" << info.affected_range.out().toDouble();
footage_ready = true;
}
}
if (footage_ready) {
InvalidateCache(info.affected_range);
footage_wait_info_.removeAt(i);
i--;
}
}
}
}