nodes: clamp footage retrieval times for clips

Fixes #2070
This commit is contained in:
itsmattkc
2022-11-01 12:44:01 -07:00
parent 5e92930de0
commit ca47792dc7
15 changed files with 42 additions and 31 deletions
+1 -1
View File
@@ -290,7 +290,7 @@ bool FFmpegEncoder::WriteAudio(const SampleBuffer &audio)
size_t end = audio.sample_count();
const size_t max_frame = 48000;
while (start < end) {
while (result && start < end) {
// Create input buffer
uint8_t** input_data = nullptr;
size_t input_sample_count = std::min(end - start, max_frame);
+15 -4
View File
@@ -458,15 +458,26 @@ void ClipBlock::InputValueChangedEvent(const QString &input, int element)
}
}
TimeRange ClipBlock::InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const
TimeRange ClipBlock::InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time, bool clamp) const
{
Q_UNUSED(element)
if (input == kBufferIn) {
return TimeRange(SequenceToMediaTime(input_time.in()), SequenceToMediaTime(input_time.out()));
rational in = input_time.in();
rational out = input_time.out();
if (clamp) {
in = std::max(in, rational(0));
out = std::min(out, length());
}
in = SequenceToMediaTime(in);
out = SequenceToMediaTime(out);
return TimeRange(in, out);
}
return super::InputTimeAdjustment(input, element, input_time);
return super::InputTimeAdjustment(input, element, input_time, clamp);
}
TimeRange ClipBlock::OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const
@@ -540,7 +551,7 @@ void ClipBlock::ConnectedToPreviewEvent()
TimeRange ClipBlock::media_range() const
{
return InputTimeAdjustment(kBufferIn, -1, TimeRange(0, length()));
return InputTimeAdjustment(kBufferIn, -1, TimeRange(0, length()), false);
}
MultiCamNode *ClipBlock::FindMulticam()
+1 -1
View File
@@ -68,7 +68,7 @@ public:
virtual void InvalidateCache(const TimeRange& range, const QString& from, int element, InvalidateCacheOptions options) override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time, bool clamp) const override;
virtual TimeRange OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
+2 -2
View File
@@ -287,7 +287,7 @@ void TransitionBlock::InputDisconnectedEvent(const QString &input, int element,
}
}
TimeRange TransitionBlock::InputTimeAdjustment(const QString &input, int element, const TimeRange &input_time) const
TimeRange TransitionBlock::InputTimeAdjustment(const QString &input, int element, const TimeRange &input_time, bool clamp) const
{
if (input == kInBlockInput || input == kOutBlockInput) {
Block* block = dynamic_cast<Block*>(GetConnectedOutput(input));
@@ -296,7 +296,7 @@ TimeRange TransitionBlock::InputTimeAdjustment(const QString &input, int element
}
}
return super::InputTimeAdjustment(input, element, input_time);
return super::InputTimeAdjustment(input, element, input_time, clamp);
}
TimeRange TransitionBlock::OutputTimeAdjustment(const QString &input, int element, const TimeRange &input_time) const
+1 -1
View File
@@ -83,7 +83,7 @@ protected:
virtual void InputDisconnectedEvent(const QString& input, int element, Node *output) override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time, bool clamp) const override;
virtual TimeRange OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
+2 -2
View File
@@ -959,7 +959,7 @@ void Node::InvalidateCache(const TimeRange &range, const QString &from, int elem
SendInvalidateCache(range, options);
}
TimeRange Node::InputTimeAdjustment(const QString &, int, const TimeRange &input_time) const
TimeRange Node::InputTimeAdjustment(const QString &, int, const TimeRange &input_time, bool clamp) const
{
// Default behavior is no time adjustment at all
return input_time;
@@ -1727,7 +1727,7 @@ TimeRange Node::TransformTimeTo(TimeRange time, Node *target, TransformTimeDirec
if (dir == kTransformTowardsInput) {
for (auto it=path.crbegin(); it!=path.crend(); it++) {
const NodeInput &i = (*it);
time = i.node()->InputTimeAdjustment(i.input(), i.element(), time);
time = i.node()->InputTimeAdjustment(i.input(), i.element(), time, false);
}
} else {
// Traverse in output direction
+1 -1
View File
@@ -907,7 +907,7 @@ public:
* If this node modifies the `time` (i.e. a clip converting sequence time to media time), this function should be
* overridden to do so. Also make sure to override OutputTimeAdjustment() to provide the inverse function.
*/
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time, bool clamp) const;
/**
* @brief The inverse of InputTimeAdjustment()
+6 -6
View File
@@ -146,7 +146,7 @@ void Track::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeVal
}
}
TimeRange Track::InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const
TimeRange Track::InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time, bool clamp) const
{
if (input == kBlockInput && element >= 0) {
int cache_index = GetCacheIndexFromArrayIndex(element);
@@ -156,7 +156,7 @@ TimeRange Track::InputTimeAdjustment(const QString& input, int element, const Ti
}
}
return Node::InputTimeAdjustment(input, element, input_time);
return Node::InputTimeAdjustment(input, element, input_time, clamp);
}
TimeRange Track::OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const
@@ -647,16 +647,16 @@ void Track::ProcessAudioTrack(const NodeValueRow &value, const NodeGlobals &glob
TimeRange range_for_block(qMax(b->in(), range.in()),
qMin(b->out(), range.out()));
qint64 source_offset = 0;
qint64 destination_offset = globals.aparams().time_to_samples(range_for_block.in() - range.in());
qint64 max_dest_sz = globals.aparams().time_to_samples(range_for_block.length());
// Destination buffer
SampleBuffer samples_from_this_block = it->second.toSamples();
ClipBlock *clip_cast = dynamic_cast<ClipBlock*>(b);
if (samples_from_this_block.is_allocated()) {
// If this is a clip, we might have extra speed/reverse information
if (clip_cast) {
if (ClipBlock *clip_cast = dynamic_cast<ClipBlock*>(b)) {
double speed_value = clip_cast->speed();
bool reversed = clip_cast->reverse();
@@ -711,11 +711,11 @@ void Track::ProcessAudioTrack(const NodeValueRow &value, const NodeGlobals &glob
}
}
qint64 copy_length = qMin(max_dest_sz, qint64(samples_from_this_block.sample_count() - destination_offset));
qint64 copy_length = qMin(max_dest_sz, qint64(samples_from_this_block.sample_count() - source_offset));
// 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, destination_offset, copy_length);
block_range_buffer.set(i, samples_from_this_block.data(i) + source_offset, destination_offset, copy_length);
}
}
}
+1 -1
View File
@@ -57,7 +57,7 @@ public:
virtual ActiveElements GetActiveElementsAtTime(const QString &input, const TimeRange &r) const override;
virtual void Value(const NodeValueRow& value, const NodeGlobals &globals, NodeValueTable *table) const override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time, bool clamp = false) const override;
virtual TimeRange OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
+3 -3
View File
@@ -227,11 +227,11 @@ void ViewerOutput::InvalidateCache(const TimeRange& range, const QString& from,
if (from == kTextureInput) {
//connected->thumbnail_cache()->Request(range.Intersected(max_range), PlaybackCache::kPreviewsOnly);
if (autocache_input_video_) {
TimeRange max_range = InputTimeAdjustment(from, element, TimeRange(0, GetVideoLength()));
TimeRange max_range = InputTimeAdjustment(from, element, TimeRange(0, GetVideoLength()), false);
connected->video_frame_cache()->Request(range.Intersected(max_range));
}
} else if (from == kSamplesInput) {
TimeRange max_range = InputTimeAdjustment(from, element, TimeRange(0, GetAudioLength()));
TimeRange max_range = InputTimeAdjustment(from, element, TimeRange(0, GetAudioLength()), false);
if (waveform_requests_enabled_) {
connected->waveform_cache()->Request(range.Intersected(max_range));
}
@@ -394,7 +394,7 @@ void ViewerOutput::SetWaveformEnabled(bool e)
{
if ((waveform_requests_enabled_ = e)) {
if (Node *connected = this->GetConnectedSampleOutput()) {
TimeRange max_range = InputTimeAdjustment(kSamplesInput, -1, TimeRange(0, GetAudioLength()));
TimeRange max_range = InputTimeAdjustment(kSamplesInput, -1, TimeRange(0, GetAudioLength()), false);
TimeRangeList invalid = connected->waveform_cache()->GetInvalidatedRanges(max_range);
for (const TimeRange &r : invalid) {
connected->waveform_cache()->Request(r);
+2 -2
View File
@@ -46,12 +46,12 @@ void TimeOffsetNode::Retranslate()
SetInputName(kInputInput, QStringLiteral("Input"));
}
TimeRange TimeOffsetNode::InputTimeAdjustment(const QString &input, int element, const TimeRange &input_time) const
TimeRange TimeOffsetNode::InputTimeAdjustment(const QString &input, int element, const TimeRange &input_time, bool clamp) const
{
if (input == kInputInput) {
return TimeRange(GetRemappedTime(input_time.in()), GetRemappedTime(input_time.out()));
} else {
return super::InputTimeAdjustment(input, element, input_time);
return super::InputTimeAdjustment(input, element, input_time, clamp);
}
}
+1 -1
View File
@@ -52,7 +52,7 @@ public:
return tr("Offset time passing through the graph.");
}
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time, bool clamp) const override;
virtual TimeRange OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual void Retranslate() override;
+2 -2
View File
@@ -58,12 +58,12 @@ QString TimeRemapNode::Description() const
return tr("Arbitrarily remap time through the nodes.");
}
TimeRange TimeRemapNode::InputTimeAdjustment(const QString &input, int element, const TimeRange &input_time) const
TimeRange TimeRemapNode::InputTimeAdjustment(const QString &input, int element, const TimeRange &input_time, bool clamp) const
{
if (input == kInputInput) {
return TimeRange(GetRemappedTime(input_time.in()), GetRemappedTime(input_time.out()));
} else {
return super::InputTimeAdjustment(input, element, input_time);
return super::InputTimeAdjustment(input, element, input_time, clamp);
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ public:
virtual QVector<CategoryID> Category() const override;
virtual QString Description() const override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual TimeRange InputTimeAdjustment(const QString& input, int element, const TimeRange& input_time, bool clamp) const override;
virtual TimeRange OutputTimeAdjustment(const QString& input, int element, const TimeRange& input_time) const override;
virtual void Retranslate() override;
+3 -3
View File
@@ -189,7 +189,7 @@ NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& inpu
// If input is connected, retrieve value directly
if (node->IsInputConnectedForRender(input)) {
TimeRange adjusted_range = node->InputTimeAdjustment(input, -1, range);
TimeRange adjusted_range = node->InputTimeAdjustment(input, -1, range, true);
// Value will equal something from the connected node, follow it
Node *output = node->GetConnectedRenderOutput(input);
@@ -224,7 +224,7 @@ NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& inpu
} else {
// Not connected or an array, just pull the immediate
TimeRange adjusted_range = node->InputTimeAdjustment(input, -1, range);
TimeRange adjusted_range = node->InputTimeAdjustment(input, -1, range, true);
return_val = node->GetValueAtTime(input, adjusted_range.in());
@@ -240,7 +240,7 @@ NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& inpu
void NodeTraverser::ProcessInputElement(NodeValueTableArray &array_tbl, const Node *node, const QString &input, int element, const TimeRange &range)
{
NodeValueTable& sub_tbl = array_tbl[element];
TimeRange adjusted_range = node->InputTimeAdjustment(input, element, range);
TimeRange adjusted_range = node->InputTimeAdjustment(input, element, range, true);
if (node->IsInputConnectedForRender(input, element)) {
Node *output = node->GetConnectedRenderOutput(input, element);