implemented "value hints" for choosing output values to use
This commit is contained in:
@@ -14,7 +14,6 @@ namespace olive {
|
||||
PreviewAutoCacher::PreviewAutoCacher() :
|
||||
viewer_node_(nullptr),
|
||||
paused_(false),
|
||||
has_changed_(false),
|
||||
use_custom_range_(false),
|
||||
single_frame_render_(nullptr)
|
||||
{
|
||||
@@ -141,7 +140,9 @@ void PreviewAutoCacher::HashesProcessed()
|
||||
// The cacher might be waiting for this job to finish
|
||||
if (!graph_update_queue_.isEmpty()) {
|
||||
TryRender();
|
||||
} else if (hash_iterator_.HasNext()) {
|
||||
}
|
||||
|
||||
if (hash_iterator_.HasNext()) {
|
||||
// Launch next hashes
|
||||
QueueNextHashTask();
|
||||
}
|
||||
@@ -203,7 +204,12 @@ void PreviewAutoCacher::AudioRendered()
|
||||
foreach (TimeRange r, intersections) {
|
||||
// For each range, adjust it relative to the block and write it
|
||||
r -= block->in();
|
||||
block->waveform().OverwriteSums(waveform_info.waveform, r.in(), r.in() - waveform_info.range.in(), r.length());
|
||||
|
||||
if (waveform_info.silence) {
|
||||
block->waveform().OverwriteSilence(r.in(), r.length());
|
||||
} else {
|
||||
block->waveform().OverwriteSums(waveform_info.waveform, r.in(), r.in() - waveform_info.range.in(), r.length());
|
||||
}
|
||||
}
|
||||
|
||||
emit block->PreviewChanged();
|
||||
@@ -316,6 +322,9 @@ void PreviewAutoCacher::ProcessUpdateQueue()
|
||||
case QueuedJob::kValueChanged:
|
||||
CopyValue(job.input);
|
||||
break;
|
||||
case QueuedJob::kValueHintChanged:
|
||||
CopyValueHint(job.input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
graph_update_queue_.clear();
|
||||
@@ -379,6 +388,13 @@ void PreviewAutoCacher::CopyValue(const NodeInput &input)
|
||||
Node::CopyValuesOfElement(input.node(), our_input, input.input(), input.element());
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::CopyValueHint(const NodeInput &input)
|
||||
{
|
||||
Node* our_input = copy_map_.value(input.node());
|
||||
Node::ValueHint hint = input.node()->GetValueHintForInput(input.input(), input.element());
|
||||
our_input->SetValueHintForInput(input.input(), input.element(), hint);
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::InsertIntoCopyMap(Node *node, Node *copy)
|
||||
{
|
||||
// Insert into map
|
||||
@@ -412,7 +428,6 @@ void PreviewAutoCacher::SetPlayhead(const rational &playhead)
|
||||
cache_range_ = TimeRange(playhead - Config::Current()[QStringLiteral("DiskCacheBehind")].value<rational>(),
|
||||
playhead + Config::Current()[QStringLiteral("DiskCacheAhead")].value<rational>());
|
||||
|
||||
has_changed_ = true;
|
||||
use_custom_range_ = false;
|
||||
|
||||
RequeueFrames();
|
||||
@@ -439,7 +454,6 @@ void PreviewAutoCacher::ClearVideoQueue(bool hard)
|
||||
{
|
||||
ClearQueueInternal(video_tasks_, hard, &PreviewAutoCacher::VideoRendered);
|
||||
|
||||
has_changed_ = true;
|
||||
use_custom_range_ = false;
|
||||
queued_frame_iterator_.reset();
|
||||
}
|
||||
@@ -486,6 +500,12 @@ void PreviewAutoCacher::ValueChanged(const NodeInput &input)
|
||||
UpdateGraphChangeValue();
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::ValueHintChanged(const NodeInput &input)
|
||||
{
|
||||
graph_update_queue_.append({QueuedJob::kValueHintChanged, nullptr, input, nullptr});
|
||||
UpdateGraphChangeValue();
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::TryRender()
|
||||
{
|
||||
if (!graph_update_queue_.isEmpty()) {
|
||||
@@ -564,7 +584,6 @@ void PreviewAutoCacher::RequeueFrames()
|
||||
if (viewer_node_
|
||||
&& viewer_node_->video_frame_cache()->HasInvalidatedRanges(viewer_node_->GetVideoLength())
|
||||
&& hash_tasks_.isEmpty()
|
||||
&& has_changed_
|
||||
&& VideoParams::FormatIsFloat(viewer_node_->GetVideoParams().format())
|
||||
&& (!paused_ || use_custom_range_)) {
|
||||
TimeRange using_range;
|
||||
@@ -580,8 +599,6 @@ void PreviewAutoCacher::RequeueFrames()
|
||||
queued_frame_iterator_ = TimeRangeListFrameIterator(invalidated, viewer_node_->video_frame_cache()->GetTimebase());
|
||||
|
||||
QueueNextFrameInRange(RenderManager::GetNumberOfIdealConcurrentJobs());
|
||||
|
||||
has_changed_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,7 +616,6 @@ void PreviewAutoCacher::ConformFinished()
|
||||
|
||||
void PreviewAutoCacher::ForceCacheRange(const TimeRange &range)
|
||||
{
|
||||
has_changed_ = true;
|
||||
use_custom_range_ = true;
|
||||
custom_autocache_range_ = range;
|
||||
|
||||
@@ -655,6 +671,7 @@ void PreviewAutoCacher::SetViewerNode(ViewerOutput *viewer_node)
|
||||
disconnect(graph, &NodeGraph::InputConnected, this, &PreviewAutoCacher::EdgeAdded);
|
||||
disconnect(graph, &NodeGraph::InputDisconnected, this, &PreviewAutoCacher::EdgeRemoved);
|
||||
disconnect(graph, &NodeGraph::ValueChanged, this, &PreviewAutoCacher::ValueChanged);
|
||||
disconnect(graph, &NodeGraph::InputValueHintChanged, this, &PreviewAutoCacher::ValueHintChanged);
|
||||
|
||||
// Disconnect signal (will be a no-op if the signal was never connected)
|
||||
disconnect(viewer_node_->video_frame_cache(),
|
||||
@@ -705,6 +722,7 @@ void PreviewAutoCacher::SetViewerNode(ViewerOutput *viewer_node)
|
||||
connect(graph, &NodeGraph::InputConnected, this, &PreviewAutoCacher::EdgeAdded);
|
||||
connect(graph, &NodeGraph::InputDisconnected, this, &PreviewAutoCacher::EdgeRemoved);
|
||||
connect(graph, &NodeGraph::ValueChanged, this, &PreviewAutoCacher::ValueChanged);
|
||||
connect(graph, &NodeGraph::InputValueHintChanged, this, &PreviewAutoCacher::ValueHintChanged);
|
||||
|
||||
// Copy invalidated ranges - used to determine which frames need hashing
|
||||
invalidated_video_ = viewer_node_->video_frame_cache()->GetInvalidatedRanges(viewer_node_->GetVideoLength());
|
||||
|
||||
@@ -90,6 +90,7 @@ private:
|
||||
void AddEdge(Node *output, const NodeInput& input);
|
||||
void RemoveEdge(Node *output, const NodeInput& input);
|
||||
void CopyValue(const NodeInput& input);
|
||||
void CopyValueHint(const NodeInput& input);
|
||||
|
||||
void InsertIntoCopyMap(Node* node, Node* copy);
|
||||
|
||||
@@ -124,7 +125,8 @@ private:
|
||||
kNodeRemoved,
|
||||
kEdgeAdded,
|
||||
kEdgeRemoved,
|
||||
kValueChanged
|
||||
kValueChanged,
|
||||
kValueHintChanged
|
||||
};
|
||||
|
||||
Type type;
|
||||
@@ -147,8 +149,6 @@ private:
|
||||
|
||||
TimeRange cache_range_;
|
||||
|
||||
bool has_changed_;
|
||||
|
||||
bool use_custom_range_;
|
||||
TimeRange custom_autocache_range_;
|
||||
|
||||
@@ -220,6 +220,8 @@ private slots:
|
||||
|
||||
void ValueChanged(const NodeInput& input);
|
||||
|
||||
void ValueHintChanged(const NodeInput &input);
|
||||
|
||||
/**
|
||||
* @brief Generic function called whenever the frames to render need to be (re)queued
|
||||
*/
|
||||
|
||||
@@ -176,7 +176,7 @@ void RenderProcessor::Run()
|
||||
|
||||
QVariant sample_variant = table.Get(NodeValue::kSamples);
|
||||
SampleBufferPtr samples = sample_variant.value<SampleBufferPtr>();
|
||||
if (samples && ticket_->property("enablewaveforms").toBool()) {
|
||||
if (ticket_->property("enablewaveforms").toBool()) {
|
||||
AudioVisualWaveform vis;
|
||||
vis.set_channel_count(samples->audio_params().channel_count());
|
||||
vis.OverwriteSamples(samples, samples->audio_params().sample_rate());
|
||||
@@ -264,52 +264,56 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
|
||||
// Destination buffer
|
||||
NodeValueTable table = GenerateTable(b, track->GetValueHintForInput(Track::kBlockInput, track->GetArrayIndexFromBlock(b)),Track::TransformRangeForBlock(b, range_for_block));
|
||||
SampleBufferPtr samples_from_this_block = table.Take(NodeValue::kSamples).value<SampleBufferPtr>();
|
||||
ClipBlock *clip_cast = dynamic_cast<ClipBlock*>(b);
|
||||
|
||||
if (!samples_from_this_block) {
|
||||
// If we retrieved no samples from this block, do nothing
|
||||
continue;
|
||||
if (samples_from_this_block) {
|
||||
// If this is a clip, we might have extra speed/reverse information
|
||||
if (clip_cast) {
|
||||
double speed_value = clip_cast->speed();
|
||||
bool reversed = clip_cast->reverse();
|
||||
|
||||
if (qIsNull(speed_value)) {
|
||||
// Just silence, don't think there's any other practical application of 0 speed audio
|
||||
samples_from_this_block->fill(0);
|
||||
} else if (!qFuzzyCompare(speed_value, 1.0)) {
|
||||
// Multiply time
|
||||
samples_from_this_block->speed(speed_value);
|
||||
}
|
||||
|
||||
if (reversed) {
|
||||
samples_from_this_block->reverse();
|
||||
}
|
||||
}
|
||||
|
||||
int copy_length = qMin(max_dest_sz, samples_from_this_block->sample_count());
|
||||
|
||||
// Copy samples into destination buffer
|
||||
for (int i=0; i<samples_from_this_block->audio_params().channel_count(); i++) {
|
||||
block_range_buffer->set(i, samples_from_this_block->data(i), destination_offset, copy_length);
|
||||
}
|
||||
|
||||
NodeValueTable::Merge({merged_table, table});
|
||||
}
|
||||
|
||||
// If this is a clip, we might have extra speed/reverse information
|
||||
if (ClipBlock *clip_cast = dynamic_cast<ClipBlock*>(b)) {
|
||||
double speed_value = clip_cast->speed();
|
||||
bool reversed = clip_cast->reverse();
|
||||
// Create block waveforms if requested
|
||||
if (ticket_->property("enablewaveforms").toBool() && clip_cast) {
|
||||
// Format information for use in the main thread
|
||||
RenderedWaveform waveform_info;
|
||||
waveform_info.block = clip_cast;
|
||||
waveform_info.range = range_for_block - b->in();
|
||||
|
||||
if (qIsNull(speed_value)) {
|
||||
// Just silence, don't think there's any other practical application of 0 speed audio
|
||||
samples_from_this_block->fill(0);
|
||||
} else if (!qFuzzyCompare(speed_value, 1.0)) {
|
||||
// Multiply time
|
||||
samples_from_this_block->speed(speed_value);
|
||||
}
|
||||
|
||||
if (reversed) {
|
||||
samples_from_this_block->reverse();
|
||||
}
|
||||
|
||||
// Create block waveforms if requested
|
||||
if (ticket_->property("enablewaveforms").toBool()) {
|
||||
if (!(waveform_info.silence = !samples_from_this_block.get())) {
|
||||
// Generate a visual waveform from the samples acquired from this block
|
||||
AudioVisualWaveform visual_waveform;
|
||||
visual_waveform.set_channel_count(audio_params.channel_count());
|
||||
visual_waveform.OverwriteSamples(samples_from_this_block, audio_params.sample_rate());
|
||||
|
||||
// Format it for use back int eh maint hread
|
||||
RenderedWaveform waveform_info = {clip_cast, visual_waveform, range_for_block - b->in()};
|
||||
QVector<RenderedWaveform> waveform_list = ticket_->property("waveforms").value< QVector<RenderedWaveform> >();
|
||||
waveform_list.append(waveform_info);
|
||||
ticket_->setProperty("waveforms", QVariant::fromValue(waveform_list));
|
||||
waveform_info.waveform = visual_waveform;
|
||||
}
|
||||
|
||||
QVector<RenderedWaveform> waveform_list = ticket_->property("waveforms").value< QVector<RenderedWaveform> >();
|
||||
waveform_list.append(waveform_info);
|
||||
ticket_->setProperty("waveforms", QVariant::fromValue(waveform_list));
|
||||
}
|
||||
|
||||
int copy_length = qMin(max_dest_sz, samples_from_this_block->sample_count());
|
||||
|
||||
// Copy samples into destination buffer
|
||||
for (int i=0; i<samples_from_this_block->audio_params().channel_count(); i++) {
|
||||
block_range_buffer->set(i, samples_from_this_block->data(i), destination_offset, copy_length);
|
||||
}
|
||||
|
||||
NodeValueTable::Merge({merged_table, table});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
const ClipBlock* block;
|
||||
AudioVisualWaveform waveform;
|
||||
TimeRange range;
|
||||
bool silence;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user