viewer: implement lookahead to ensure footage is ready in advance

This commit is contained in:
itsmattkc
2022-07-26 14:49:19 -07:00
parent d1ec2b909b
commit 25e94112f8
9 changed files with 137 additions and 62 deletions
+57 -50
View File
@@ -151,53 +151,57 @@ void RenderProcessor::Run()
TexturePtr texture = GenerateTexture(time, frame_length);
if (GetCacheVideoParams().interlacing() != VideoParams::kInterlaceNone) {
// Get next between frame and interlace it
TexturePtr top = texture;
TexturePtr bottom = GenerateTexture(time + frame_length, frame_length);
if (GetCacheVideoParams().interlacing() == VideoParams::kInterlacedBottomFirst) {
std::swap(top, bottom);
}
texture = render_ctx_->InterlaceTexture(top, bottom, GetCacheVideoParams());
}
if (HeardCancel()) {
// Finish cancelled ticket with nothing since we can't guarantee the frame we generated
// is actually "complete
if (!render_ctx_) {
ticket_->Finish();
} else {
RenderManager::ReturnType return_type = RenderManager::ReturnType(ticket_->property("return").toInt());
if (GetCacheVideoParams().interlacing() != VideoParams::kInterlaceNone) {
// Get next between frame and interlace it
TexturePtr top = texture;
TexturePtr bottom = GenerateTexture(time + frame_length, frame_length);
FramePtr frame;
QString cache = ticket_->property("cache").toString();
if (return_type == RenderManager::kFrame || !cache.isEmpty()) {
// Convert to CPU frame
frame = GenerateFrame(texture, time);
// Save to cache if requested
if (!cache.isEmpty()) {
rational timebase = ticket_->property("cachetimebase").value<rational>();
QUuid uuid = ticket_->property("cacheuuid").value<QUuid>();
bool cache_result = FrameHashCache::SaveCacheFrame(cache, uuid, time, timebase, frame);
ticket_->setProperty("cached", cache_result);
if (GetCacheVideoParams().interlacing() == VideoParams::kInterlacedBottomFirst) {
std::swap(top, bottom);
}
texture = render_ctx_->InterlaceTexture(top, bottom, GetCacheVideoParams());
}
if (return_type == RenderManager::kTexture) {
// Return GPU texture
if (!texture) {
texture = render_ctx_->CreateTexture(GetCacheVideoParams());
render_ctx_->ClearDestination(texture.get());
if (HeardCancel()) {
// Finish cancelled ticket with nothing since we can't guarantee the frame we generated
// is actually "complete
ticket_->Finish();
} else {
RenderManager::ReturnType return_type = RenderManager::ReturnType(ticket_->property("return").toInt());
FramePtr frame;
QString cache = ticket_->property("cache").toString();
if (return_type == RenderManager::kFrame || !cache.isEmpty()) {
// Convert to CPU frame
frame = GenerateFrame(texture, time);
// Save to cache if requested
if (!cache.isEmpty()) {
rational timebase = ticket_->property("cachetimebase").value<rational>();
QUuid uuid = ticket_->property("cacheuuid").value<QUuid>();
bool cache_result = FrameHashCache::SaveCacheFrame(cache, uuid, time, timebase, frame);
ticket_->setProperty("cached", cache_result);
}
}
render_ctx_->Flush();
if (return_type == RenderManager::kTexture) {
// Return GPU texture
if (!texture) {
texture = render_ctx_->CreateTexture(GetCacheVideoParams());
render_ctx_->ClearDestination(texture.get());
}
ticket_->Finish(QVariant::fromValue(texture));
} else {
ticket_->Finish(QVariant::fromValue(frame));
render_ctx_->Flush();
ticket_->Finish(QVariant::fromValue(texture));
} else {
ticket_->Finish(QVariant::fromValue(frame));
}
}
}
break;
@@ -265,6 +269,11 @@ DecoderPtr RenderProcessor::ResolveDecoderFromInput(const QString& decoder_id, c
<< "::" << stream.stream();
return nullptr;
}
if (!render_ctx_) {
// Assume dry run and increment access time
decoder.decoder->IncrementAccessTime(RenderManager::kDryRunInterval.toDouble() * 1000);
}
}
return decoder.decoder;
@@ -404,10 +413,6 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJob &stream, const rational &input_time)
{
if (!render_ctx_) {
return;
}
if (ticket_->property("type").value<RenderManager::TicketType>() != RenderManager::kTypeVideo) {
// Video cannot contribute to audio, so we do nothing here
return;
@@ -440,21 +445,23 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
break;
case VideoParams::kVideoTypeImageSequence:
{
// Since image sequences involve multiple files, we don't engage the decoder cache
decoder = Decoder::CreateFromID(decoder_id);
if (render_ctx_) {
// Since image sequences involve multiple files, we don't engage the decoder cache
decoder = Decoder::CreateFromID(decoder_id);
QString frame_filename;
QString frame_filename;
int64_t frame_number = stream_data.get_time_in_timebase_units(input_time);
frame_filename = Decoder::TransformImageSequenceFileName(stream.filename(), frame_number);
int64_t frame_number = stream_data.get_time_in_timebase_units(input_time);
frame_filename = Decoder::TransformImageSequenceFileName(stream.filename(), frame_number);
// Decoder will close automatically since it's a stream_ptr
decoder->Open(Decoder::CodecStream(frame_filename, stream_data.stream_index(), GetCurrentBlock()));
// Decoder will close automatically since it's a stream_ptr
decoder->Open(Decoder::CodecStream(frame_filename, stream_data.stream_index(), GetCurrentBlock()));
}
break;
}
}
if (decoder) {
if (decoder && render_ctx_) {
Decoder::RetrieveVideoParams p;
p.divider = stream.video_params().divider();
p.maximum_format = destination->format();