architecture: move loop modes to clips
This commit is contained in:
@@ -34,6 +34,7 @@ const QString ClipBlock::kMediaInInput = QStringLiteral("media_in_in");
|
||||
const QString ClipBlock::kSpeedInput = QStringLiteral("speed_in");
|
||||
const QString ClipBlock::kReverseInput = QStringLiteral("reverse_in");
|
||||
const QString ClipBlock::kMaintainAudioPitchInput = QStringLiteral("maintain_audio_pitch_in");
|
||||
const QString ClipBlock::kLoopModeInput = QStringLiteral("loop_in");
|
||||
|
||||
ClipBlock::ClipBlock() :
|
||||
in_transition_(nullptr),
|
||||
@@ -56,6 +57,8 @@ ClipBlock::ClipBlock() :
|
||||
//SetValueHintForInput(kBufferIn, ValueHint(NodeValue::kBuffer));
|
||||
|
||||
SetEffectInput(kBufferIn);
|
||||
|
||||
AddInput(kLoopModeInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
}
|
||||
|
||||
QString ClipBlock::Name() const
|
||||
@@ -89,7 +92,8 @@ void ClipBlock::set_length_and_media_out(const rational &length)
|
||||
|
||||
if (reverse()) {
|
||||
// Calculate media_in adjustment
|
||||
rational proposed_media_in = SequenceToMediaTime(this->length() - length, true);
|
||||
|
||||
rational proposed_media_in = SequenceToMediaTime(this->length() - length, kSTMIgnoreReverse | kSTMIgnoreLoop);
|
||||
set_media_in(proposed_media_in);
|
||||
}
|
||||
|
||||
@@ -104,7 +108,7 @@ void ClipBlock::set_length_and_media_in(const rational &length)
|
||||
|
||||
if (!reverse()) {
|
||||
// Calculate media_in adjustment
|
||||
rational proposed_media_in = SequenceToMediaTime(this->length() - length, false, true);
|
||||
rational proposed_media_in = SequenceToMediaTime(this->length() - length, kSTMIgnoreSpeed | kSTMIgnoreLoop);
|
||||
|
||||
waveform_.TrimIn(proposed_media_in - media_in());
|
||||
|
||||
@@ -127,7 +131,7 @@ void ClipBlock::set_media_in(const rational &media_in)
|
||||
SetStandardValue(kMediaInInput, QVariant::fromValue(media_in));
|
||||
}
|
||||
|
||||
rational ClipBlock::SequenceToMediaTime(const rational &sequence_time, bool ignore_reverse, bool ignore_speed) const
|
||||
rational ClipBlock::SequenceToMediaTime(const rational &sequence_time, uint64_t flags) const
|
||||
{
|
||||
// These constants are not considered "values" per se, so we don't modify them
|
||||
if (sequence_time == RATIONAL_MIN || sequence_time == RATIONAL_MAX) {
|
||||
@@ -136,11 +140,11 @@ rational ClipBlock::SequenceToMediaTime(const rational &sequence_time, bool igno
|
||||
|
||||
rational media_time = sequence_time;
|
||||
|
||||
if (reverse() && !ignore_reverse) {
|
||||
if (reverse() && !(flags & kSTMIgnoreReverse)) {
|
||||
media_time = length() - media_time;
|
||||
}
|
||||
|
||||
if (!ignore_speed) {
|
||||
if (!(flags & kSTMIgnoreSpeed)) {
|
||||
double speed_value = speed();
|
||||
if (qIsNull(speed_value)) {
|
||||
// Effectively holds the frame at the in point
|
||||
@@ -153,6 +157,23 @@ rational ClipBlock::SequenceToMediaTime(const rational &sequence_time, bool igno
|
||||
|
||||
media_time += media_in();
|
||||
|
||||
/*if (!(flags & kSTMIgnoreLoop)
|
||||
&& this->loop_mode() != kLoopModeOff
|
||||
&& connected_viewer_
|
||||
&& !connected_viewer_->GetLength().isNull()
|
||||
&& (media_time < 0 || media_time >= connected_viewer_->GetLength())) {
|
||||
if (loop_mode() == kLoopModeLoop) {
|
||||
while (media_time < 0) {
|
||||
media_time += connected_viewer_->GetLength();
|
||||
}
|
||||
while (media_time >= connected_viewer_->GetLength()) {
|
||||
media_time -= connected_viewer_->GetLength();
|
||||
}
|
||||
} else if (loop_mode() == kLoopModeClamp) {
|
||||
media_time = std::clamp(media_time, rational(0), connected_viewer_->GetLength()-connected_viewer_->GetVideoParams().frame_rate_as_time_base());
|
||||
}
|
||||
}*/
|
||||
|
||||
return media_time;
|
||||
}
|
||||
|
||||
@@ -282,6 +303,8 @@ void ClipBlock::Retranslate()
|
||||
SetInputName(kSpeedInput, tr("Speed"));
|
||||
SetInputName(kReverseInput, tr("Reverse"));
|
||||
SetInputName(kMaintainAudioPitchInput, tr("Maintain Audio Pitch"));
|
||||
SetInputName(kLoopModeInput, tr("Loop"));
|
||||
SetComboBoxStrings(kLoopModeInput, {tr("None"), tr("Loop"), tr("Clamp")});
|
||||
}
|
||||
|
||||
TimeRange ClipBlock::media_range() const
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#define CLIPBLOCK_H
|
||||
|
||||
#include "audio/audiovisualwaveform.h"
|
||||
#include "codec/decoder.h"
|
||||
#include "node/block/block.h"
|
||||
|
||||
namespace olive {
|
||||
@@ -121,17 +122,39 @@ public:
|
||||
|
||||
TimeRange media_range() const;
|
||||
|
||||
/**
|
||||
* @brief Get currently set loop mode
|
||||
*/
|
||||
Decoder::LoopMode loop_mode() const
|
||||
{
|
||||
return static_cast<Decoder::LoopMode>(GetStandardValue(kLoopModeInput).toInt());
|
||||
}
|
||||
|
||||
void set_loop_mode(Decoder::LoopMode l)
|
||||
{
|
||||
SetStandardValue(kLoopModeInput, int(l));
|
||||
}
|
||||
|
||||
static const QString kBufferIn;
|
||||
static const QString kMediaInInput;
|
||||
static const QString kSpeedInput;
|
||||
static const QString kReverseInput;
|
||||
static const QString kMaintainAudioPitchInput;
|
||||
static const QString kLoopModeInput;
|
||||
|
||||
protected:
|
||||
virtual void LinkChangeEvent() override;
|
||||
|
||||
private:
|
||||
rational SequenceToMediaTime(const rational& sequence_time, bool ignore_reverse = false, bool ignore_speed = false) const;
|
||||
enum SequenceToMediaTimeFlag
|
||||
{
|
||||
kSTMNone,
|
||||
kSTMIgnoreReverse,
|
||||
kSTMIgnoreSpeed,
|
||||
kSTMIgnoreLoop
|
||||
};
|
||||
|
||||
rational SequenceToMediaTime(const rational& sequence_time, uint64_t flags = kSTMNone) const;
|
||||
|
||||
rational MediaToSequenceTime(const rational& media_time) const;
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
namespace olive {
|
||||
|
||||
const QString Footage::kFilenameInput = QStringLiteral("file_in");
|
||||
const QString Footage::kLoopModeInput = QStringLiteral("loop_in");
|
||||
|
||||
#define super ViewerOutput
|
||||
|
||||
@@ -49,8 +48,6 @@ Footage::Footage(const QString &filename) :
|
||||
{
|
||||
SetCacheTextures(true);
|
||||
|
||||
PrependInput(kLoopModeInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
|
||||
PrependInput(kFilenameInput, NodeValue::kFile, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
|
||||
|
||||
Clear();
|
||||
@@ -70,8 +67,6 @@ void Footage::Retranslate()
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kFilenameInput, tr("Filename"));
|
||||
SetInputName(kLoopModeInput, tr("Loop Mode"));
|
||||
SetComboBoxStrings(kLoopModeInput, {tr("None"), tr("Loop"), tr("Clamp")});
|
||||
}
|
||||
|
||||
void Footage::InputValueChangedEvent(const QString &input, int element)
|
||||
@@ -139,11 +134,6 @@ void Footage::SetValid()
|
||||
valid_ = true;
|
||||
}
|
||||
|
||||
Footage::LoopMode Footage::loop_mode() const
|
||||
{
|
||||
return static_cast<LoopMode>(GetStandardValue(kLoopModeInput).toInt());
|
||||
}
|
||||
|
||||
QString Footage::filename() const
|
||||
{
|
||||
return GetStandardValue(kFilenameInput).toString();
|
||||
@@ -263,17 +253,15 @@ void Footage::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV
|
||||
// Pop filename from table
|
||||
QString file = value[kFilenameInput].toString();
|
||||
|
||||
LoopMode loop_mode = static_cast<LoopMode>(value[kLoopModeInput].toInt());
|
||||
|
||||
// If the file exists and the reference is valid, push a footage job to the renderer
|
||||
if (QFileInfo(file).exists()) {
|
||||
if (QFileInfo::exists(file)) {
|
||||
// Push length
|
||||
table->Push(NodeValue::kRational, QVariant::fromValue(GetLength()), this, false, QStringLiteral("length"));
|
||||
table->Push(NodeValue::kRational, QVariant::fromValue(GetLength()), this, QStringLiteral("length"));
|
||||
|
||||
// Push each stream as a footage job
|
||||
for (int i=0; i<GetTotalStreamCount(); i++) {
|
||||
Track::Reference ref = GetReferenceFromRealIndex(i);
|
||||
FootageJob job(decoder_, filename(), ref.type(), GetLength(), loop_mode);
|
||||
FootageJob job(decoder_, filename(), ref.type(), GetLength());
|
||||
|
||||
NodeValue::Type type;
|
||||
|
||||
@@ -339,7 +327,7 @@ bool TimeIsOutOfBounds(const rational& time, const rational& length)
|
||||
return time < 0 || time >= length;
|
||||
}
|
||||
|
||||
rational Footage::AdjustTimeByLoopMode(rational time, Footage::LoopMode loop_mode, const rational &length, VideoParams::Type type, const rational& timebase)
|
||||
rational Footage::AdjustTimeByLoopMode(rational time, Decoder::LoopMode loop_mode, const rational &length, VideoParams::Type type, const rational& timebase)
|
||||
{
|
||||
if (type == VideoParams::kVideoTypeStill) {
|
||||
// No looping for still images
|
||||
@@ -348,15 +336,15 @@ rational Footage::AdjustTimeByLoopMode(rational time, Footage::LoopMode loop_mod
|
||||
|
||||
if (TimeIsOutOfBounds(time, length)) {
|
||||
switch (loop_mode) {
|
||||
case kLoopModeOff:
|
||||
case Decoder::kLoopModeOff:
|
||||
// Return no time to indicate no frame should be shown here
|
||||
time = rational::NaN;
|
||||
break;
|
||||
case kLoopModeClamp:
|
||||
case Decoder::kLoopModeClamp:
|
||||
// Clamp footage time to length
|
||||
time = clamp(time, rational(0), length - timebase);
|
||||
break;
|
||||
case kLoopModeLoop:
|
||||
case Decoder::kLoopModeLoop:
|
||||
// Loop footage time around job length
|
||||
do {
|
||||
if (time >= length) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <QList>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "codec/decoder.h"
|
||||
#include "common/rational.h"
|
||||
#include "footagedescription.h"
|
||||
#include "node/output/viewer/viewer.h"
|
||||
@@ -44,12 +45,6 @@ class Footage : public ViewerOutput
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum LoopMode {
|
||||
kLoopModeOff,
|
||||
kLoopModeLoop,
|
||||
kLoopModeClamp
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Footage Constructor
|
||||
*/
|
||||
@@ -101,11 +96,6 @@ public:
|
||||
*/
|
||||
void SetValid();
|
||||
|
||||
/**
|
||||
* @brief Get currently set loop mode
|
||||
*/
|
||||
LoopMode loop_mode() const;
|
||||
|
||||
/**
|
||||
* @brief Return the current filename of this Footage object
|
||||
*/
|
||||
@@ -183,7 +173,7 @@ public:
|
||||
|
||||
virtual Node *GetConnectedSampleOutput() override;
|
||||
|
||||
static rational AdjustTimeByLoopMode(rational time, LoopMode loop_mode, const rational& length, VideoParams::Type type, const rational &timebase);
|
||||
static rational AdjustTimeByLoopMode(rational time, Decoder::LoopMode loop_mode, const rational& length, VideoParams::Type type, const rational &timebase);
|
||||
|
||||
virtual void LoadFinishedEvent() override;
|
||||
|
||||
@@ -191,7 +181,6 @@ public:
|
||||
virtual qint64 mod_time() const override;
|
||||
|
||||
static const QString kFilenameInput;
|
||||
static const QString kLoopModeInput;
|
||||
|
||||
protected:
|
||||
virtual void InputValueChangedEvent(const QString &input, int element) override;
|
||||
|
||||
+12
-2
@@ -21,6 +21,7 @@
|
||||
#include "traverser.h"
|
||||
|
||||
#include "node.h"
|
||||
#include "node/block/clip/clip.h"
|
||||
#include "render/job/footagejob.h"
|
||||
#include "render/rendermanager.h"
|
||||
|
||||
@@ -30,6 +31,12 @@ NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRa
|
||||
{
|
||||
NodeValueDatabase database;
|
||||
|
||||
// HACK: Pick up loop mode from clips
|
||||
Decoder::LoopMode old_loop_mode = loop_mode_;
|
||||
if (const ClipBlock *clip = dynamic_cast<const ClipBlock*>(node)) {
|
||||
loop_mode_ = clip->loop_mode();
|
||||
}
|
||||
|
||||
// We need to insert tables into the database for each input
|
||||
foreach (const QString& input, node->inputs()) {
|
||||
if (IsCancelled()) {
|
||||
@@ -39,6 +46,8 @@ NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRa
|
||||
database.Insert(input, ProcessInput(node, input, range));
|
||||
}
|
||||
|
||||
loop_mode_ = old_loop_mode;
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
@@ -260,7 +269,8 @@ NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& inpu
|
||||
|
||||
NodeTraverser::NodeTraverser() :
|
||||
cancel_(nullptr),
|
||||
transform_(nullptr)
|
||||
transform_(nullptr),
|
||||
loop_mode_(Decoder::kLoopModeOff)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -436,7 +446,7 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range)
|
||||
|
||||
if (job.type() == Track::kVideo) {
|
||||
|
||||
rational footage_time = Footage::AdjustTimeByLoopMode(range.in(), job.loop_mode(), job.length(), job.video_params().video_type(), job.video_params().frame_rate_as_time_base());
|
||||
rational footage_time = Footage::AdjustTimeByLoopMode(range.in(), loop_mode_, job.length(), job.video_params().video_type(), job.video_params().frame_rate_as_time_base());
|
||||
|
||||
TexturePtr tex;
|
||||
|
||||
|
||||
@@ -149,6 +149,8 @@ protected:
|
||||
return block_stack_.empty() ? nullptr : block_stack_.back();
|
||||
}
|
||||
|
||||
Decoder::LoopMode loop_mode() const { return loop_mode_; }
|
||||
|
||||
private:
|
||||
void PreProcessRow(const TimeRange &range, NodeValueRow &row);
|
||||
|
||||
@@ -166,6 +168,8 @@ private:
|
||||
|
||||
std::list<Block*> block_stack_;
|
||||
|
||||
Decoder::LoopMode loop_mode_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user