architecture: move loop modes to clips

This commit is contained in:
itsmattkc
2022-07-17 15:22:36 -07:00
parent 4c71a33b7b
commit 0d9727b6d2
13 changed files with 179 additions and 79 deletions
+3 -3
View File
@@ -109,7 +109,7 @@ TexturePtr Decoder::RetrieveVideo(Renderer *renderer, const rational &timecode,
return RetrieveVideoInternal(renderer, timecode, divider, cancelled); return RetrieveVideoInternal(renderer, timecode, divider, cancelled);
} }
Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams &params, const QString& cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode) Decoder::RetrieveAudioStatus Decoder::RetrieveAudio(SampleBuffer &dest, const TimeRange &range, const AudioParams &params, const QString& cache_path, LoopMode loop_mode, RenderMode::Mode mode)
{ {
QMutexLocker locker(&mutex_); QMutexLocker locker(&mutex_);
@@ -280,7 +280,7 @@ bool Decoder::ConformAudioInternal(const QVector<QString> &filenames, const Audi
return false; return false;
} }
bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange& range, Footage::LoopMode loop_mode, const AudioParams &input_params) bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange& range, LoopMode loop_mode, const AudioParams &input_params)
{ {
PlanarFileDevice input; PlanarFileDevice input;
if (input.open(conform_filenames, QFile::ReadOnly)) { if (input.open(conform_filenames, QFile::ReadOnly)) {
@@ -290,7 +290,7 @@ bool Decoder::RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVecto
const qint64 buffer_length_in_bytes = sample_buffer.sample_count() * input_params.bytes_per_sample_per_channel(); const qint64 buffer_length_in_bytes = sample_buffer.sample_count() * input_params.bytes_per_sample_per_channel();
while (write_index < buffer_length_in_bytes) { while (write_index < buffer_length_in_bytes) {
if (loop_mode == Footage::kLoopModeLoop) { if (loop_mode == kLoopModeLoop) {
while (read_index >= input.size()) { while (read_index >= input.size()) {
read_index -= input.size(); read_index -= input.size();
} }
+8 -3
View File
@@ -35,7 +35,6 @@ extern "C" {
#include "codec/samplebuffer.h" #include "codec/samplebuffer.h"
#include "common/rational.h" #include "common/rational.h"
#include "node/block/block.h" #include "node/block/block.h"
#include "node/project/footage/footage.h"
#include "node/project/footage/footagedescription.h" #include "node/project/footage/footagedescription.h"
#include "task/task.h" #include "task/task.h"
@@ -72,6 +71,12 @@ public:
kIndexUnavailable kIndexUnavailable
}; };
enum LoopMode {
kLoopModeOff,
kLoopModeLoop,
kLoopModeClamp
};
Decoder(); Decoder();
/** /**
@@ -209,7 +214,7 @@ public:
* *
* This function is thread safe and can only run while the decoder is open. \see Open() * This function is thread safe and can only run while the decoder is open. \see Open()
*/ */
RetrieveAudioStatus RetrieveAudio(SampleBuffer &dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, Footage::LoopMode loop_mode, RenderMode::Mode mode); RetrieveAudioStatus RetrieveAudio(SampleBuffer &dest, const TimeRange& range, const AudioParams& params, const QString &cache_path, LoopMode loop_mode, RenderMode::Mode mode);
/** /**
* @brief Determine the last time this decoder instance was used in any way * @brief Determine the last time this decoder instance was used in any way
@@ -316,7 +321,7 @@ signals:
private: private:
void UpdateLastAccessed(); void UpdateLastAccessed();
bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange &range, Footage::LoopMode loop_mode, const AudioParams &params); bool RetrieveAudioFromConform(SampleBuffer &sample_buffer, const QVector<QString> &conform_filenames, const TimeRange &range, LoopMode loop_mode, const AudioParams &params);
CodecStream stream_; CodecStream stream_;
@@ -38,12 +38,12 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, cons
clips_(clips), clips_(clips),
timebase_(timebase) timebase_(timebase)
{ {
setWindowTitle(tr("Speed/Duration")); setWindowTitle(tr("Clip Properties"));
QVBoxLayout *layout = new QVBoxLayout(this); QVBoxLayout *layout = new QVBoxLayout(this);
{ {
QGroupBox *speed_group = new QGroupBox(); QGroupBox *speed_group = new QGroupBox(tr("Speed/Duration"));
layout->addWidget(speed_group); layout->addWidget(speed_group);
QGridLayout *speed_layout = new QGridLayout(speed_group); QGridLayout *speed_layout = new QGridLayout(speed_group);
@@ -72,16 +72,39 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, cons
link_box_ = new QCheckBox(tr("Link Speed and Duration")); link_box_ = new QCheckBox(tr("Link Speed and Duration"));
link_box_->setChecked(true); link_box_->setChecked(true);
speed_layout->addWidget(link_box_, row, 0, 1, 2); speed_layout->addWidget(link_box_, row, 0, 1, 2);
row++;
reverse_box_ = new QCheckBox(tr("Reverse"));
speed_layout->addWidget(reverse_box_, row, 0, 1, 2);
row++;
maintain_audio_pitch_box_ = new QCheckBox(tr("Maintain Audio Pitch"));
speed_layout->addWidget(maintain_audio_pitch_box_, row, 0, 1, 2);
row++;
ripple_box_ = new QCheckBox(tr("Ripple Trailing Clips"));
speed_layout->addWidget(ripple_box_, row, 0, 1, 2);
} }
reverse_box_ = new QCheckBox(tr("Reverse")); {
layout->addWidget(reverse_box_); auto loop_box = new QGroupBox(tr("Loop"));
layout->addWidget(loop_box);
maintain_audio_pitch_box_ = new QCheckBox(tr("Maintain Audio Pitch")); auto loop_layout = new QGridLayout(loop_box);
layout->addWidget(maintain_audio_pitch_box_);
ripple_box_ = new QCheckBox(tr("Ripple Trailing Clips")); int row = 0;
layout->addWidget(ripple_box_);
loop_layout->addWidget(new QLabel(tr("Loop:")), row, 0);
loop_combo_ = new QComboBox();
loop_combo_->addItem(tr("None"), Decoder::kLoopModeOff);
loop_combo_->addItem(tr("Loop"), Decoder::kLoopModeLoop);
loop_combo_->addItem(tr("Clamp"), Decoder::kLoopModeClamp);
loop_layout->addWidget(loop_combo_, row, 1);
}
QDialogButtonBox *btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QDialogButtonBox *btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
btns->setCenterButtons(true); btns->setCenterButtons(true);
@@ -94,6 +117,7 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, cons
start_duration_ = clips.first()->length(); start_duration_ = clips.first()->length();
start_reverse_ = clips.first()->reverse(); start_reverse_ = clips.first()->reverse();
start_maintain_audio_pitch_ = clips.first()->maintain_audio_pitch(); start_maintain_audio_pitch_ = clips.first()->maintain_audio_pitch();
start_loop_ = clips.first()->loop_mode();
for (int i=1; i<clips.size(); i++) { for (int i=1; i<clips.size(); i++) {
ClipBlock *c = clips.at(i); ClipBlock *c = clips.at(i);
@@ -116,6 +140,10 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, cons
if (start_maintain_audio_pitch_ != -1 && clip_maintain_pitch != start_maintain_audio_pitch_) { if (start_maintain_audio_pitch_ != -1 && clip_maintain_pitch != start_maintain_audio_pitch_) {
start_maintain_audio_pitch_ = -1; start_maintain_audio_pitch_ = -1;
} }
if (start_loop_ != -1 && c->loop_mode() != start_loop_) {
start_loop_ = -1;
}
} }
if (qIsNaN(start_speed_)) { if (qIsNaN(start_speed_)) {
@@ -141,6 +169,12 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, cons
} else { } else {
maintain_audio_pitch_box_->setChecked(start_maintain_audio_pitch_); maintain_audio_pitch_box_->setChecked(start_maintain_audio_pitch_);
} }
if (start_loop_ == -1) {
loop_combo_->setCurrentIndex(-1);
} else {
loop_combo_->setCurrentIndex(start_loop_);
}
} }
void SpeedDurationDialog::accept() void SpeedDurationDialog::accept()
@@ -211,6 +245,12 @@ void SpeedDurationDialog::accept()
} }
} }
if (loop_combo_->currentIndex() != -1) {
foreach (ClipBlock *c, clips_) {
command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(NodeInput(c, ClipBlock::kLoopModeInput)), loop_combo_->currentData()));
}
}
Core::instance()->undo_stack()->push(command); Core::instance()->undo_stack()->push(command);
super::accept(); super::accept();
@@ -22,6 +22,7 @@
#define SPEEDDURATIONDIALOG_H #define SPEEDDURATIONDIALOG_H
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox>
#include <QDialog> #include <QDialog>
#include "node/block/clip/clip.h" #include "node/block/clip/clip.h"
@@ -62,6 +63,8 @@ private:
QCheckBox *ripple_box_; QCheckBox *ripple_box_;
QComboBox *loop_combo_;
int start_reverse_; int start_reverse_;
int start_maintain_audio_pitch_; int start_maintain_audio_pitch_;
@@ -70,6 +73,8 @@ private:
rational start_duration_; rational start_duration_;
int start_loop_;
rational timebase_; rational timebase_;
private slots: private slots:
+28 -5
View File
@@ -34,6 +34,7 @@ const QString ClipBlock::kMediaInInput = QStringLiteral("media_in_in");
const QString ClipBlock::kSpeedInput = QStringLiteral("speed_in"); const QString ClipBlock::kSpeedInput = QStringLiteral("speed_in");
const QString ClipBlock::kReverseInput = QStringLiteral("reverse_in"); const QString ClipBlock::kReverseInput = QStringLiteral("reverse_in");
const QString ClipBlock::kMaintainAudioPitchInput = QStringLiteral("maintain_audio_pitch_in"); const QString ClipBlock::kMaintainAudioPitchInput = QStringLiteral("maintain_audio_pitch_in");
const QString ClipBlock::kLoopModeInput = QStringLiteral("loop_in");
ClipBlock::ClipBlock() : ClipBlock::ClipBlock() :
in_transition_(nullptr), in_transition_(nullptr),
@@ -56,6 +57,8 @@ ClipBlock::ClipBlock() :
//SetValueHintForInput(kBufferIn, ValueHint(NodeValue::kBuffer)); //SetValueHintForInput(kBufferIn, ValueHint(NodeValue::kBuffer));
SetEffectInput(kBufferIn); SetEffectInput(kBufferIn);
AddInput(kLoopModeInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
} }
QString ClipBlock::Name() const QString ClipBlock::Name() const
@@ -89,7 +92,8 @@ void ClipBlock::set_length_and_media_out(const rational &length)
if (reverse()) { if (reverse()) {
// Calculate media_in adjustment // 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); set_media_in(proposed_media_in);
} }
@@ -104,7 +108,7 @@ void ClipBlock::set_length_and_media_in(const rational &length)
if (!reverse()) { if (!reverse()) {
// Calculate media_in adjustment // 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()); 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)); 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 // These constants are not considered "values" per se, so we don't modify them
if (sequence_time == RATIONAL_MIN || sequence_time == RATIONAL_MAX) { 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; rational media_time = sequence_time;
if (reverse() && !ignore_reverse) { if (reverse() && !(flags & kSTMIgnoreReverse)) {
media_time = length() - media_time; media_time = length() - media_time;
} }
if (!ignore_speed) { if (!(flags & kSTMIgnoreSpeed)) {
double speed_value = speed(); double speed_value = speed();
if (qIsNull(speed_value)) { if (qIsNull(speed_value)) {
// Effectively holds the frame at the in point // 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(); 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; return media_time;
} }
@@ -282,6 +303,8 @@ void ClipBlock::Retranslate()
SetInputName(kSpeedInput, tr("Speed")); SetInputName(kSpeedInput, tr("Speed"));
SetInputName(kReverseInput, tr("Reverse")); SetInputName(kReverseInput, tr("Reverse"));
SetInputName(kMaintainAudioPitchInput, tr("Maintain Audio Pitch")); SetInputName(kMaintainAudioPitchInput, tr("Maintain Audio Pitch"));
SetInputName(kLoopModeInput, tr("Loop"));
SetComboBoxStrings(kLoopModeInput, {tr("None"), tr("Loop"), tr("Clamp")});
} }
TimeRange ClipBlock::media_range() const TimeRange ClipBlock::media_range() const
+24 -1
View File
@@ -22,6 +22,7 @@
#define CLIPBLOCK_H #define CLIPBLOCK_H
#include "audio/audiovisualwaveform.h" #include "audio/audiovisualwaveform.h"
#include "codec/decoder.h"
#include "node/block/block.h" #include "node/block/block.h"
namespace olive { namespace olive {
@@ -121,17 +122,39 @@ public:
TimeRange media_range() const; 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 kBufferIn;
static const QString kMediaInInput; static const QString kMediaInInput;
static const QString kSpeedInput; static const QString kSpeedInput;
static const QString kReverseInput; static const QString kReverseInput;
static const QString kMaintainAudioPitchInput; static const QString kMaintainAudioPitchInput;
static const QString kLoopModeInput;
protected: protected:
virtual void LinkChangeEvent() override; virtual void LinkChangeEvent() override;
private: 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; rational MediaToSequenceTime(const rational& media_time) const;
+7 -19
View File
@@ -37,7 +37,6 @@
namespace olive { namespace olive {
const QString Footage::kFilenameInput = QStringLiteral("file_in"); const QString Footage::kFilenameInput = QStringLiteral("file_in");
const QString Footage::kLoopModeInput = QStringLiteral("loop_in");
#define super ViewerOutput #define super ViewerOutput
@@ -49,8 +48,6 @@ Footage::Footage(const QString &filename) :
{ {
SetCacheTextures(true); SetCacheTextures(true);
PrependInput(kLoopModeInput, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
PrependInput(kFilenameInput, NodeValue::kFile, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); PrependInput(kFilenameInput, NodeValue::kFile, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable));
Clear(); Clear();
@@ -70,8 +67,6 @@ void Footage::Retranslate()
super::Retranslate(); super::Retranslate();
SetInputName(kFilenameInput, tr("Filename")); 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) void Footage::InputValueChangedEvent(const QString &input, int element)
@@ -139,11 +134,6 @@ void Footage::SetValid()
valid_ = true; valid_ = true;
} }
Footage::LoopMode Footage::loop_mode() const
{
return static_cast<LoopMode>(GetStandardValue(kLoopModeInput).toInt());
}
QString Footage::filename() const QString Footage::filename() const
{ {
return GetStandardValue(kFilenameInput).toString(); return GetStandardValue(kFilenameInput).toString();
@@ -263,17 +253,15 @@ void Footage::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV
// Pop filename from table // Pop filename from table
QString file = value[kFilenameInput].toString(); 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 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 // 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 // Push each stream as a footage job
for (int i=0; i<GetTotalStreamCount(); i++) { for (int i=0; i<GetTotalStreamCount(); i++) {
Track::Reference ref = GetReferenceFromRealIndex(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; NodeValue::Type type;
@@ -339,7 +327,7 @@ bool TimeIsOutOfBounds(const rational& time, const rational& length)
return time < 0 || time >= 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) { if (type == VideoParams::kVideoTypeStill) {
// No looping for still images // No looping for still images
@@ -348,15 +336,15 @@ rational Footage::AdjustTimeByLoopMode(rational time, Footage::LoopMode loop_mod
if (TimeIsOutOfBounds(time, length)) { if (TimeIsOutOfBounds(time, length)) {
switch (loop_mode) { switch (loop_mode) {
case kLoopModeOff: case Decoder::kLoopModeOff:
// Return no time to indicate no frame should be shown here // Return no time to indicate no frame should be shown here
time = rational::NaN; time = rational::NaN;
break; break;
case kLoopModeClamp: case Decoder::kLoopModeClamp:
// Clamp footage time to length // Clamp footage time to length
time = clamp(time, rational(0), length - timebase); time = clamp(time, rational(0), length - timebase);
break; break;
case kLoopModeLoop: case Decoder::kLoopModeLoop:
// Loop footage time around job length // Loop footage time around job length
do { do {
if (time >= length) { if (time >= length) {
+2 -13
View File
@@ -24,6 +24,7 @@
#include <QList> #include <QList>
#include <QDateTime> #include <QDateTime>
#include "codec/decoder.h"
#include "common/rational.h" #include "common/rational.h"
#include "footagedescription.h" #include "footagedescription.h"
#include "node/output/viewer/viewer.h" #include "node/output/viewer/viewer.h"
@@ -44,12 +45,6 @@ class Footage : public ViewerOutput
{ {
Q_OBJECT Q_OBJECT
public: public:
enum LoopMode {
kLoopModeOff,
kLoopModeLoop,
kLoopModeClamp
};
/** /**
* @brief Footage Constructor * @brief Footage Constructor
*/ */
@@ -101,11 +96,6 @@ public:
*/ */
void SetValid(); void SetValid();
/**
* @brief Get currently set loop mode
*/
LoopMode loop_mode() const;
/** /**
* @brief Return the current filename of this Footage object * @brief Return the current filename of this Footage object
*/ */
@@ -183,7 +173,7 @@ public:
virtual Node *GetConnectedSampleOutput() override; 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; virtual void LoadFinishedEvent() override;
@@ -191,7 +181,6 @@ public:
virtual qint64 mod_time() const override; virtual qint64 mod_time() const override;
static const QString kFilenameInput; static const QString kFilenameInput;
static const QString kLoopModeInput;
protected: protected:
virtual void InputValueChangedEvent(const QString &input, int element) override; virtual void InputValueChangedEvent(const QString &input, int element) override;
+12 -2
View File
@@ -21,6 +21,7 @@
#include "traverser.h" #include "traverser.h"
#include "node.h" #include "node.h"
#include "node/block/clip/clip.h"
#include "render/job/footagejob.h" #include "render/job/footagejob.h"
#include "render/rendermanager.h" #include "render/rendermanager.h"
@@ -30,6 +31,12 @@ NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRa
{ {
NodeValueDatabase database; 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 // We need to insert tables into the database for each input
foreach (const QString& input, node->inputs()) { foreach (const QString& input, node->inputs()) {
if (IsCancelled()) { if (IsCancelled()) {
@@ -39,6 +46,8 @@ NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRa
database.Insert(input, ProcessInput(node, input, range)); database.Insert(input, ProcessInput(node, input, range));
} }
loop_mode_ = old_loop_mode;
return database; return database;
} }
@@ -260,7 +269,8 @@ NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& inpu
NodeTraverser::NodeTraverser() : NodeTraverser::NodeTraverser() :
cancel_(nullptr), 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) { 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; TexturePtr tex;
+4
View File
@@ -149,6 +149,8 @@ protected:
return block_stack_.empty() ? nullptr : block_stack_.back(); return block_stack_.empty() ? nullptr : block_stack_.back();
} }
Decoder::LoopMode loop_mode() const { return loop_mode_; }
private: private:
void PreProcessRow(const TimeRange &range, NodeValueRow &row); void PreProcessRow(const TimeRange &range, NodeValueRow &row);
@@ -166,6 +168,8 @@ private:
std::list<Block*> block_stack_; std::list<Block*> block_stack_;
Decoder::LoopMode loop_mode_;
}; };
} }
+3 -17
View File
@@ -29,17 +29,15 @@ class FootageJob
{ {
public: public:
FootageJob() : FootageJob() :
type_(Track::kNone), type_(Track::kNone)
loop_mode_(Footage::kLoopModeOff)
{ {
} }
FootageJob(const QString& decoder, const QString& filename, Track::Type type, const rational& length, Footage::LoopMode loop_mode) : FootageJob(const QString& decoder, const QString& filename, Track::Type type, const rational& length) :
decoder_(decoder), decoder_(decoder),
filename_(filename), filename_(filename),
type_(type), type_(type),
length_(length), length_(length)
loop_mode_(loop_mode)
{ {
} }
@@ -98,16 +96,6 @@ public:
length_ = length; length_ = length;
} }
Footage::LoopMode loop_mode() const
{
return loop_mode_;
}
void set_loop_mode(Footage::LoopMode loop_mode)
{
loop_mode_ = loop_mode;
}
private: private:
QString decoder_; QString decoder_;
@@ -123,8 +111,6 @@ private:
rational length_; rational length_;
Footage::LoopMode loop_mode_;
}; };
} }
+1 -1
View File
@@ -503,7 +503,7 @@ void RenderProcessor::ProcessAudioFootage(SampleBuffer &destination, const Foota
Decoder::RetrieveAudioStatus status = decoder->RetrieveAudio(destination, Decoder::RetrieveAudioStatus status = decoder->RetrieveAudio(destination,
input_time, audio_params, input_time, audio_params,
stream.cache_path(), stream.cache_path(),
stream.loop_mode(), loop_mode(),
static_cast<RenderMode::Mode>(ticket_->property("mode").toInt())); static_cast<RenderMode::Mode>(ticket_->property("mode").toInt()));
if (status == Decoder::kWaitingForConform) { if (status == Decoder::kWaitingForConform) {
@@ -531,19 +531,46 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q
// Draw zebra stripes and markers // Draw zebra stripes and markers
if (clip->connected_viewer()) { if (clip->connected_viewer()) {
if (!clip->connected_viewer()->GetLength().isNull()) { if (!clip->connected_viewer()->GetLength().isNull()) {
painter->setPen(shadow_color);
if (clip->media_in() < 0) { if (clip->media_in() < 0) {
// Draw stripes for sections of clip < 0 qreal zebra_right = TimeToScene(clip->in() - clip->media_in());
qreal zebra_right = TimeToScene(-clip->media_in());
if (zebra_right > GetTimelineLeftBound()) { switch (clip->loop_mode()) {
DrawZebraStripes(painter, QRectF(block_left, block_top, zebra_right, block_height)); case Decoder::kLoopModeOff:
// Draw stripes for sections of clip < 0
if (zebra_right > GetTimelineLeftBound()) {
DrawZebraStripes(painter, QRectF(block_left, block_top, zebra_right - block_left, block_height));
}
break;
case Decoder::kLoopModeLoop:
for (qreal i=zebra_right; i>block_left; i-=TimeToScene(clip->connected_viewer()->GetLength())) {
painter->drawLine(i, block_top, i, block_top + block_height);
}
break;
case Decoder::kLoopModeClamp:
painter->drawLine(zebra_right, block_top, zebra_right, block_top + block_height);
break;
} }
} }
if (clip->length() + clip->media_in() > clip->connected_viewer()->GetLength()) { if (clip->length() + clip->media_in() > clip->connected_viewer()->GetLength()) {
// Draw stripes for sections for clip > clip length
qreal zebra_left = TimeToScene(clip->out() - (clip->media_in() + clip->length() - clip->connected_viewer()->GetLength())); qreal zebra_left = TimeToScene(clip->out() - (clip->media_in() + clip->length() - clip->connected_viewer()->GetLength()));
if (zebra_left < GetTimelineRightBound()) { switch (clip->loop_mode()) {
DrawZebraStripes(painter, QRectF(zebra_left, block_top, block_right - zebra_left, block_height)); case Decoder::kLoopModeOff:
// Draw stripes for sections for clip > clip length
if (zebra_left < GetTimelineRightBound()) {
DrawZebraStripes(painter, QRectF(zebra_left, block_top, block_right - zebra_left, block_height));
}
break;
case Decoder::kLoopModeLoop:
for (qreal i=zebra_left; i<block_right; i+=TimeToScene(clip->connected_viewer()->GetLength())) {
painter->drawLine(i, block_top, i, block_top + block_height);
}
break;
case Decoder::kLoopModeClamp:
painter->drawLine(zebra_left, block_top, zebra_left, block_top + block_height);
break;
} }
} }
} }