use a system of deferred maps to keep track of frames that don't need to be rendered twice

Mostly used for exporting to ensure all frames get accounted for when being
sent from the renderer to the exporter through signals/slots.
This commit is contained in:
itsmattkc
2019-12-22 03:03:08 +11:00
parent 8514590c83
commit 46855adea7
5 changed files with 39 additions and 29 deletions
+19 -19
View File
@@ -27,6 +27,7 @@
#include <QDir>
#include <QtMath>
#include "common/timecodefunctions.h"
#include "render/pixelservice.h"
#include "videorenderworker.h"
@@ -55,12 +56,10 @@ void VideoRenderBackend::InvalidateCache(const rational &start_range, const rati
<< 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>(params_.time_base().denominator());
int64_t start_range_numround = qFloor(start_range_numf/static_cast<double>(params_.time_base().numerator())) * params_.time_base().numerator();
rational true_start_range(start_range_numround, params_.time_base().denominator());
int64_t timestamp = olive::time_to_timestamp(start_range_adj, params_.time_base());
rational true_start = olive::timestamp_to_time(timestamp, params_.time_base());
for (rational r=true_start_range;r<=end_range_adj;r+=params_.time_base()) {
for (rational r=true_start;r<end_range_adj;r+=params_.time_base()) {
// Try to order the queue from closest to the playhead to furthest
rational last_time = last_time_requested_;
@@ -248,6 +247,18 @@ void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, QByteArray ha
QVariant texture = table.Get(NodeParam::kTexture);
// Check if this frame has changed once again, in which case we may not want to draw it (it'll look jittery to the user)
if (!TimeIsQueued(TimeRange(path.in(), path.in()))) {
EmitCachedFrameReady(path.in(), texture);
if (export_mode_) {
QList<rational> times_with_this_hash = frame_cache()->DeferredMapsWithHash(hash);
foreach (const rational& t, times_with_this_hash) {
EmitCachedFrameReady(t, texture);
}
}
}
if (!export_mode_) {
if (texture.isNull()) {
// No frame received, we set hash to an empty
@@ -268,18 +279,6 @@ void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, QByteArray ha
}
}
// Check if this frame has changed once again, in which case we may not want to draw it (it'll look jittery to the user)
if (!TimeIsQueued(TimeRange(path.in(), path.in()))) {
EmitCachedFrameReady(path.in(), texture);
if (export_mode_) {
QList<rational> times_with_this_hash = frame_cache()->TimesWithHash(hash);
foreach (const rational& t, times_with_this_hash) {
EmitCachedFrameReady(t, texture);
}
}
}
// Queue up a new frame for this worker
CacheNext();
}
@@ -287,17 +286,18 @@ void VideoRenderBackend::ThreadCompletedFrame(NodeDependency path, QByteArray ha
void VideoRenderBackend::ThreadCompletedDownload(NodeDependency dep, QByteArray hash)
{
frame_cache()->SetHash(dep.in(), hash);
emit CachedTimeReady(dep.in());
// Emit for each frame that has this hash (some may have been added in ThreadSkippedFrame)
QList<rational> times_with_this_hash = frame_cache()->TimesWithHash(hash);
QList<rational> times_with_this_hash = frame_cache()->DeferredMapsWithHash(hash);
foreach (const rational& t, times_with_this_hash) {
frame_cache()->SetHash(t, hash);
emit CachedTimeReady(t);
}
}
void VideoRenderBackend::ThreadSkippedFrame(NodeDependency dep, QByteArray hash)
{
frame_cache()->SetHash(dep.in(), hash);
SetWorkerBusyState(static_cast<RenderWorker*>(sender()), false);
// Queue up a new frame for this worker