cache: save states to disk
This commit is contained in:
@@ -311,4 +311,23 @@ void ClipBlock::Retranslate()
|
||||
SetInputName(kMaintainAudioPitchInput, tr("Maintain Audio Pitch"));
|
||||
}
|
||||
|
||||
void ClipBlock::ConnectedToPreviewEvent()
|
||||
{
|
||||
Track::Type type = GetTrackType();
|
||||
|
||||
if (type == Track::kVideo || type == Track::kAudio) {
|
||||
if (Node *connected = GetConnectedOutput(kBufferIn)) {
|
||||
TimeRange max_range = InputTimeAdjustment(kBufferIn, -1, TimeRange(0, length()));
|
||||
if (type == Track::kVideo) {
|
||||
TimeRangeList invalid = connected->thumbnail_cache()->GetInvalidatedRanges(max_range);
|
||||
for (const TimeRange &r : invalid) {
|
||||
emit connected->thumbnail_cache()->Request(r, PlaybackCache::kPreviewsOnly);
|
||||
}
|
||||
} else if (type == Track::kAudio) {
|
||||
//emit connected->audio_playback_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -158,6 +158,8 @@ public:
|
||||
return TimeRange(0, length());
|
||||
}
|
||||
|
||||
virtual void ConnectedToPreviewEvent() override;
|
||||
|
||||
static const QString kBufferIn;
|
||||
static const QString kMediaInInput;
|
||||
static const QString kSpeedInput;
|
||||
|
||||
@@ -991,6 +991,7 @@ public:
|
||||
void SetInputFlags(const QString &input, const InputFlags &f);
|
||||
|
||||
virtual void LoadFinishedEvent(){}
|
||||
virtual void ConnectedToPreviewEvent(){}
|
||||
|
||||
static void SetValueAtTime(const NodeInput &input, const rational &time, const QVariant &value, int track, MultiUndoCommand *command, bool insert_on_all_tracks_if_no_key);
|
||||
|
||||
|
||||
@@ -544,6 +544,18 @@ void ProjectSerializer220403::LoadNode(Node *node, XMLNodeData &xml_node_data, Q
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else if (reader->name() == QStringLiteral("caches")) {
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("audio")) {
|
||||
node->audio_playback_cache()->SetUuid(reader->readElementText());
|
||||
} else if (reader->name() == QStringLiteral("video")) {
|
||||
node->video_frame_cache()->SetUuid(reader->readElementText());
|
||||
} else if (reader->name() == QStringLiteral("thumb")) {
|
||||
node->thumbnail_cache()->SetUuid(reader->readElementText());
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
@@ -599,6 +611,14 @@ void ProjectSerializer220403::SaveNode(Node *node, QXmlStreamWriter *writer) con
|
||||
}
|
||||
writer->writeEndElement();
|
||||
|
||||
writer->writeStartElement(QStringLiteral("caches"));
|
||||
|
||||
writer->writeTextElement(QStringLiteral("audio"), node->audio_playback_cache()->GetUuid().toString());
|
||||
writer->writeTextElement(QStringLiteral("video"), node->video_frame_cache()->GetUuid().toString());
|
||||
writer->writeTextElement(QStringLiteral("thumb"), node->thumbnail_cache()->GetUuid().toString());
|
||||
|
||||
writer->writeEndElement(); // caches
|
||||
|
||||
writer->writeStartElement(QStringLiteral("custom"));
|
||||
|
||||
SaveNodeCustom(writer, node);
|
||||
|
||||
@@ -193,6 +193,32 @@ FramePtr FrameHashCache::LoadCacheFrame(const QString &fn)
|
||||
return frame;
|
||||
}
|
||||
|
||||
void FrameHashCache::LoadStateEvent(QDataStream &stream)
|
||||
{
|
||||
uint32_t version;
|
||||
int num, den;
|
||||
|
||||
stream >> version;
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
stream >> num;
|
||||
stream >> den;
|
||||
timebase_ = rational(num, den);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FrameHashCache::SaveStateEvent(QDataStream &stream)
|
||||
{
|
||||
uint32_t version = 1;
|
||||
|
||||
stream << version;
|
||||
|
||||
stream << timebase_.numerator();
|
||||
stream << timebase_.denominator();
|
||||
}
|
||||
|
||||
rational FrameHashCache::ToTime(const int64_t &ts) const
|
||||
{
|
||||
return Timecode::timestamp_to_time(ts, timebase_);
|
||||
|
||||
@@ -65,6 +65,10 @@ public:
|
||||
FramePtr LoadCacheFrame(const int64_t &time) const;
|
||||
static FramePtr LoadCacheFrame(const QString& fn);
|
||||
|
||||
protected:
|
||||
virtual void LoadStateEvent(QDataStream &stream) override;
|
||||
virtual void SaveStateEvent(QDataStream &stream) override;
|
||||
|
||||
private:
|
||||
rational ToTime(const int64_t &ts) const;
|
||||
int64_t ToTimestamp(const rational &ts, Timecode::Rounding rounding = Timecode::kRound) const;
|
||||
|
||||
@@ -60,6 +60,77 @@ QDir PlaybackCache::GetThisCacheDirectory(const QString &cache_path, const QUuid
|
||||
return QDir(cache_path).filePath(cache_id.toString());
|
||||
}
|
||||
|
||||
void PlaybackCache::LoadState()
|
||||
{
|
||||
QDir cache_dir = GetThisCacheDirectory();
|
||||
QFile f(cache_dir.filePath(QStringLiteral("state")));
|
||||
if (f.open(QFile::ReadOnly)) {
|
||||
QDataStream s(&f);
|
||||
|
||||
uint32_t version;
|
||||
s >> version;
|
||||
|
||||
LoadStateEvent(s);
|
||||
|
||||
int count;
|
||||
s >> count;
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
validated_.clear();
|
||||
|
||||
for (int i=0; i<count; i++) {
|
||||
int in_num, in_den, out_num, out_den;
|
||||
|
||||
s >> in_num;
|
||||
s >> in_den;
|
||||
s >> out_num;
|
||||
s >> out_den;
|
||||
|
||||
validated_.insert(TimeRange(rational(in_num, in_den), rational(out_num, out_den)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
|
||||
void PlaybackCache::SaveState()
|
||||
{
|
||||
QDir cache_dir = GetThisCacheDirectory();
|
||||
QFile f(cache_dir.filePath(QStringLiteral("state")));
|
||||
if (validated_.isEmpty()) {
|
||||
if (f.exists()) {
|
||||
f.remove();
|
||||
}
|
||||
} else {
|
||||
if (FileFunctions::DirectoryIsValid(cache_dir)) {
|
||||
if (f.open(QFile::WriteOnly)) {
|
||||
QDataStream s(&f);
|
||||
|
||||
uint32_t version = 1;
|
||||
s << version;
|
||||
|
||||
SaveStateEvent(s);
|
||||
|
||||
s << validated_.size();
|
||||
|
||||
for (const TimeRange &r : validated_) {
|
||||
s << r.in().numerator();
|
||||
s << r.in().denominator();
|
||||
s << r.out().numerator();
|
||||
s << r.out().denominator();
|
||||
}
|
||||
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlaybackCache::InvalidateAll()
|
||||
{
|
||||
Invalidate(TimeRange(0, RATIONAL_MAX));
|
||||
|
||||
@@ -74,6 +74,9 @@ public:
|
||||
kPreviewsOnly
|
||||
};
|
||||
|
||||
void LoadState();
|
||||
void SaveState();
|
||||
|
||||
public slots:
|
||||
void InvalidateAll();
|
||||
|
||||
@@ -91,6 +94,10 @@ protected:
|
||||
|
||||
virtual void InvalidateEvent(const TimeRange& range);
|
||||
|
||||
virtual void LoadStateEvent(QDataStream &stream){}
|
||||
|
||||
virtual void SaveStateEvent(QDataStream &stream){}
|
||||
|
||||
Project* GetProject() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -345,6 +345,10 @@ void PreviewAutoCacher::ConnectToNodeCache(Node *node)
|
||||
this,
|
||||
&PreviewAutoCacher::AudioInvalidatedFromCache);
|
||||
|
||||
node->video_frame_cache()->LoadState();
|
||||
node->audio_playback_cache()->LoadState();
|
||||
node->thumbnail_cache()->LoadState();
|
||||
|
||||
// Copy invalidated ranges and start rendering if necessary
|
||||
if (node->video_frame_cache()->IsAutomatic()) {
|
||||
VideoAutoCacheEnableChangedFromNode(node, true);
|
||||
@@ -382,6 +386,10 @@ void PreviewAutoCacher::DisconnectFromNodeCache(Node *node)
|
||||
this,
|
||||
&PreviewAutoCacher::AudioInvalidatedFromCache);
|
||||
|
||||
node->video_frame_cache()->SaveState();
|
||||
node->audio_playback_cache()->SaveState();
|
||||
node->thumbnail_cache()->SaveState();
|
||||
|
||||
if (node->video_frame_cache()->IsAutomatic()) {
|
||||
VideoAutoCacheEnableChangedFromNode(node, false);
|
||||
}
|
||||
@@ -841,6 +849,9 @@ void PreviewAutoCacher::SetViewerNode(ViewerOutput *viewer_node)
|
||||
for (int i=copied_project_.nodes().size(); i<graph->nodes().size(); i++) {
|
||||
AddNode(graph->nodes().at(i));
|
||||
}
|
||||
for (int i=0; i<graph->nodes().size(); i++) {
|
||||
graph->nodes().at(i)->ConnectedToPreviewEvent();
|
||||
}
|
||||
|
||||
// Find copied viewer node
|
||||
copied_viewer_node_ = static_cast<ViewerOutput*>(copy_map_.value(viewer_node_));
|
||||
|
||||
@@ -837,7 +837,7 @@ void ViewerWidget::PushScrubbedAudio()
|
||||
{
|
||||
if (!IsPlaying() && GetConnectedNode() && OLIVE_CONFIG("AudioScrubbing").toBool() && enable_audio_scrubbing_) {
|
||||
// Get audio src device from renderer
|
||||
const AudioParams& params = GetConnectedNode()->audio_playback_cache()->GetParameters();
|
||||
const AudioParams& params = GetConnectedNode()->GetAudioParams();
|
||||
|
||||
if (params.is_valid()) {
|
||||
// NOTE: Hardcoded scrubbing interval (20ms)
|
||||
|
||||
Reference in New Issue
Block a user