nodes: implemented infrastructure for caching any node

Not accessible through UI yet, but ported Footage node to it
(previously we used a hack to ensure Footage textures were
cached, now it's a formal infrastructure).
This commit is contained in:
itsmattkc
2021-04-11 18:56:39 +10:00
parent 210eb86cd2
commit 6c30f8cf46
10 changed files with 129 additions and 39 deletions
+15 -5
View File
@@ -187,14 +187,24 @@ bool FrameHashCache::SaveCacheFrame(const QByteArray& hash,
const VideoParams& vparam,
int linesize_bytes) const
{
QString fn = CachePathName(hash);
return SaveCacheFrame(GetCacheDirectory(), hash, data, vparam, linesize_bytes);
}
bool FrameHashCache::SaveCacheFrame(const QByteArray &hash, FramePtr frame) const
{
return SaveCacheFrame(GetCacheDirectory(), hash, frame);
}
bool FrameHashCache::SaveCacheFrame(const QString &cache_path, const QByteArray &hash, char *data, const VideoParams &vparam, int linesize_bytes)
{
QString fn = CachePathName(cache_path, hash);
if (SaveCacheFrame(fn, data, vparam, linesize_bytes)) {
// Register frame with the disk manager
QMetaObject::invokeMethod(DiskManager::instance(),
"CreatedFile",
Qt::QueuedConnection,
Q_ARG(QString, GetCacheDirectory()),
Q_ARG(QString, cache_path),
Q_ARG(QString, fn),
Q_ARG(QByteArray, hash));
@@ -204,10 +214,10 @@ bool FrameHashCache::SaveCacheFrame(const QByteArray& hash,
}
}
bool FrameHashCache::SaveCacheFrame(const QByteArray &hash, FramePtr frame) const
bool FrameHashCache::SaveCacheFrame(const QString &cache_path, const QByteArray &hash, FramePtr frame)
{
if (frame) {
return SaveCacheFrame(hash, frame->data(), frame->video_params(), frame->linesize_bytes());
return SaveCacheFrame(cache_path, hash, frame->data(), frame->video_params(), frame->linesize_bytes());
} else {
qWarning() << "Attempted to save a NULL frame to the cache. This may or may not be desirable.";
return false;
@@ -394,7 +404,7 @@ QString FrameHashCache::CachePathName(const QString &cache_path, const QByteArra
return cache_dir.filePath(filename);
}
bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const VideoParams &vparam, int linesize_bytes) const
bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const VideoParams &vparam, int linesize_bytes)
{
if (!VideoParams::FormatIsFloat(vparam.format())) {
qCritical() << "Tried to cache frame with non-float pixel format";
+3 -1
View File
@@ -61,9 +61,11 @@ public:
QString CachePathName(const QByteArray &hash) const;
static QString CachePathName(const QString& cache_path, const QByteArray &hash);
bool SaveCacheFrame(const QString& filename, char *data, const VideoParams &vparam, int linesize_bytes) const;
static bool SaveCacheFrame(const QString& filename, char *data, const VideoParams &vparam, int linesize_bytes);
bool SaveCacheFrame(const QByteArray& hash, char *data, const VideoParams &vparam, int linesize_bytes) const;
bool SaveCacheFrame(const QByteArray& hash, FramePtr frame) const;
static bool SaveCacheFrame(const QString& cache_path, const QByteArray& hash, char *data, const VideoParams &vparam, int linesize_bytes);
static bool SaveCacheFrame(const QString& cache_path, const QByteArray& hash, FramePtr frame);
static FramePtr LoadCacheFrame(const QString& cache_path, const QByteArray& hash);
FramePtr LoadCacheFrame(const QByteArray& hash) const;
static FramePtr LoadCacheFrame(const QString& fn);
+1 -1
View File
@@ -189,7 +189,7 @@ RenderTicketPtr RenderManager::SaveFrameToCache(FrameHashCache *cache, FramePtr
// Create ticket
RenderTicketPtr ticket = std::make_shared<RenderTicket>();
ticket->setProperty("cache", Node::PtrToValue(cache));
ticket->setProperty("cache", cache->GetCacheDirectory());
ticket->setProperty("frame", QVariant::fromValue(frame));
ticket->setProperty("hash", hash);
ticket->setProperty("type", kTypeVideoDownload);
+46 -18
View File
@@ -148,11 +148,11 @@ void RenderProcessor::Run()
}
case RenderManager::kTypeVideoDownload:
{
FrameHashCache* cache = Node::ValueToPtr<FrameHashCache>(ticket_->property("cache"));
QString cache = ticket_->property("cache").toString();
FramePtr frame = ticket_->property("frame").value<FramePtr>();
QByteArray hash = ticket_->property("hash").toByteArray();
ticket_->Finish(cache->SaveCacheFrame(hash, frame), false);
ticket_->Finish(FrameHashCache::SaveCacheFrame(cache, hash, frame), false);
break;
}
default:
@@ -534,34 +534,62 @@ QVariant RenderProcessor::ProcessFrameGeneration(const Node *node, const Generat
return QVariant::fromValue(texture);
}
QVariant RenderProcessor::GetCachedFrame(const Node *node, const rational &time)
bool RenderProcessor::CanCacheFrames()
{
if (!ticket_->property("cache").toString().isEmpty()
&& node->id() == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) {
const VideoParams& video_params = ticket_->property("vparam").value<VideoParams>();
return true;
}
QByteArray hash = RenderManager::Hash(node, video_params, time);
QVariant RenderProcessor::GetCachedTexture(const QByteArray& hash)
{
VideoParams video_params = GetCacheVideoParams();
QString cache_dir = ticket_->property("cache").toString();
FramePtr f = FrameHashCache::LoadCacheFrame(ticket_->property("cache").toString(), hash);
FramePtr f = FrameHashCache::LoadCacheFrame(cache_dir, hash);
if (f) {
// The cached frame won't load with the correct divider by default, so we enforce it here
VideoParams p = f->video_params();
if (f) {
// The cached frame won't load with the correct divider by default, so we enforce it here
VideoParams p = f->video_params();
p.set_width(f->width() * video_params.divider());
p.set_height(f->height() * video_params.divider());
p.set_divider(video_params.divider());
p.set_width(f->width() * video_params.divider());
p.set_height(f->height() * video_params.divider());
p.set_divider(video_params.divider());
f->set_video_params(p);
f->set_video_params(p);
TexturePtr texture = render_ctx_->CreateTexture(f->video_params(), f->data(), f->linesize_pixels());
return QVariant::fromValue(texture);
}
TexturePtr texture = render_ctx_->CreateTexture(f->video_params(), f->data(), f->linesize_pixels());
qDebug() << "Loaded mid-render frame from cache";
return QVariant::fromValue(texture);
}
return QVariant();
}
void RenderProcessor::SaveCachedTexture(const QByteArray &hash, const QVariant &tex_var)
{
// FIXME: Temporarily disabled because I don't know how to ensure that the frame saved here is
// not the main frame. If it is, it'll be saved twice which will waste a lot of cycles.
// At least disabled, the frame will still save, and if nothing else alters the hash, it
// will pick up automatically from GetCachedTexture.
/*if (!tex_var.isNull()) {
QString cache_dir = ticket_->property("cache").toString();
if (!cache_dir.isEmpty()) {
TexturePtr texture = tex_var.value<TexturePtr>();
FramePtr frame = Frame::Create();
frame->set_video_params(texture->params());
frame->allocate();
render_ctx_->DownloadFromTexture(texture.get(), frame->data(), frame->linesize_pixels());
FrameHashCache::SaveCacheFrame(cache_dir, hash, frame);
qDebug() << "Saved mid-render frame to cache";
}
}*/
}
VideoParams RenderProcessor::GetCacheVideoParams()
{
return ticket_->property("vparam").value<VideoParams>();
}
QVector2D RenderProcessor::GenerateResolution() const
{
// Set resolution to the destination to the "logical" resolution of the destination
+7 -1
View File
@@ -53,7 +53,13 @@ protected:
virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job) override;
virtual QVariant GetCachedFrame(const Node *node, const rational &time) override;
virtual bool CanCacheFrames() override;
virtual QVariant GetCachedTexture(const QByteArray &hash) override;
virtual void SaveCachedTexture(const QByteArray& hash, const QVariant& texture) override;
virtual VideoParams GetCacheVideoParams() override;
virtual QVector2D GenerateResolution() const override;