nodes: fix loop mode regression

This commit is contained in:
itsmattkc
2022-11-01 09:15:51 -07:00
parent c5a86af181
commit 5e92930de0
16 changed files with 111 additions and 86 deletions
+1 -1
View File
@@ -293,7 +293,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();
while (write_index < buffer_length_in_bytes) {
if (loop_mode == kLoopModeLoop) {
if (loop_mode == LoopMode::kLoopModeLoop) {
while (read_index >= input.size()) {
read_index -= input.size();
}
+1 -8
View File
@@ -31,12 +31,11 @@ extern "C" {
#include <QWaitCondition>
#include <stdint.h>
#include "codec/frame.h"
#include "codec/samplebuffer.h"
#include "common/rational.h"
#include "node/block/block.h"
#include "node/project/footage/footagedescription.h"
#include "task/task.h"
#include "render/cancelatom.h"
namespace olive {
@@ -71,12 +70,6 @@ public:
kIndexUnavailable
};
enum LoopMode {
kLoopModeOff,
kLoopModeLoop,
kLoopModeClamp
};
Decoder();
/**
@@ -100,9 +100,9 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, cons
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_combo_->addItem(tr("None"), int(LoopMode::kLoopModeOff));
loop_combo_->addItem(tr("Loop"), int(LoopMode::kLoopModeLoop));
loop_combo_->addItem(tr("Clamp"), int(LoopMode::kLoopModeClamp));
loop_layout->addWidget(loop_combo_, row, 1);
}
@@ -117,7 +117,7 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, cons
start_duration_ = clips.first()->length();
start_reverse_ = clips.first()->reverse();
start_maintain_audio_pitch_ = clips.first()->maintain_audio_pitch();
start_loop_ = clips.first()->loop_mode();
start_loop_ = int(clips.first()->loop_mode());
for (int i=1; i<clips.size(); i++) {
ClipBlock *c = clips.at(i);
@@ -141,7 +141,7 @@ SpeedDurationDialog::SpeedDurationDialog(const QVector<ClipBlock *> &clips, cons
start_maintain_audio_pitch_ = -1;
}
if (start_loop_ != -1 && c->loop_mode() != start_loop_) {
if (start_loop_ != -1 && int(c->loop_mode()) != start_loop_) {
start_loop_ = -1;
}
}
+2
View File
@@ -453,6 +453,8 @@ void ClipBlock::InputValueChangedEvent(const QString &input, int element)
}
}
}
} else if (input == kLoopModeInput) {
emit PreviewChanged();
}
}
+3 -3
View File
@@ -188,12 +188,12 @@ public:
/**
* @brief Get currently set loop mode
*/
Decoder::LoopMode loop_mode() const
LoopMode loop_mode() const
{
return static_cast<Decoder::LoopMode>(GetStandardValue(kLoopModeInput).toInt());
return static_cast<LoopMode>(GetStandardValue(kLoopModeInput).toInt());
}
void set_loop_mode(Decoder::LoopMode l)
void set_loop_mode(LoopMode l)
{
SetStandardValue(kLoopModeInput, int(l));
}
+11 -2
View File
@@ -25,6 +25,7 @@
#include "common/timerange.h"
#include "render/audioparams.h"
#include "render/loopmode.h"
#include "render/videoparams.h"
namespace olive {
@@ -34,10 +35,16 @@ class NodeGlobals
public:
NodeGlobals(){}
NodeGlobals(const VideoParams &vparam, const AudioParams &aparam, const TimeRange &time) :
NodeGlobals(const VideoParams &vparam, const AudioParams &aparam, const TimeRange &time, LoopMode loop_mode) :
video_params_(vparam),
audio_params_(aparam),
time_(time)
time_(time),
loop_mode_(loop_mode)
{
}
NodeGlobals(const VideoParams &vparam, const AudioParams &aparam, const rational &time, LoopMode loop_mode) :
NodeGlobals(vparam, aparam, TimeRange(time, time + vparam.frame_rate_as_time_base()), loop_mode)
{
}
@@ -46,11 +53,13 @@ public:
const AudioParams &aparams() const { return audio_params_; }
const VideoParams &vparams() const { return video_params_; }
const TimeRange &time() const { return time_; }
LoopMode loop_mode() const { return loop_mode_; }
private:
VideoParams video_params_;
AudioParams audio_params_;
TimeRange time_;
LoopMode loop_mode_;
};
+5 -5
View File
@@ -265,7 +265,7 @@ void Footage::Value(const NodeValueRow &value, const NodeGlobals &globals, NodeV
// Push each stream as a footage job
for (int i=0; i<GetTotalStreamCount(); i++) {
Track::Reference ref = GetReferenceFromRealIndex(i);
FootageJob job(globals.time(), decoder_, filename(), ref.type(), GetLength());
FootageJob job(globals.time(), decoder_, filename(), ref.type(), GetLength(), globals.loop_mode());
if (ref.type() == Track::kVideo) {
VideoParams vp = GetVideoParams(ref.index());
@@ -337,7 +337,7 @@ bool TimeIsOutOfBounds(const rational& time, const rational& length)
return time < 0 || time >= length;
}
rational Footage::AdjustTimeByLoopMode(rational time, Decoder::LoopMode loop_mode, const rational &length, VideoParams::Type type, const rational& timebase)
rational Footage::AdjustTimeByLoopMode(rational time, LoopMode loop_mode, const rational &length, VideoParams::Type type, const rational& timebase)
{
if (type == VideoParams::kVideoTypeStill) {
// No looping for still images
@@ -346,15 +346,15 @@ rational Footage::AdjustTimeByLoopMode(rational time, Decoder::LoopMode loop_mod
if (TimeIsOutOfBounds(time, length)) {
switch (loop_mode) {
case Decoder::kLoopModeOff:
case LoopMode::kLoopModeOff:
// Return no time to indicate no frame should be shown here
time = rational::NaN;
break;
case Decoder::kLoopModeClamp:
case LoopMode::kLoopModeClamp:
// Clamp footage time to length
time = clamp(time, rational(0), length - timebase);
break;
case Decoder::kLoopModeLoop:
case LoopMode::kLoopModeLoop:
// Loop footage time around job length
do {
if (time >= length) {
+1 -1
View File
@@ -173,7 +173,7 @@ public:
virtual Node *GetConnectedSampleOutput() override;
static rational AdjustTimeByLoopMode(rational time, Decoder::LoopMode loop_mode, const rational& length, VideoParams::Type type, const rational &timebase);
static rational AdjustTimeByLoopMode(rational time, LoopMode loop_mode, const rational& length, VideoParams::Type type, const rational &timebase);
virtual void LoadFinishedEvent() override;
+4 -9
View File
@@ -32,7 +32,7 @@ NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRa
NodeValueDatabase database;
// HACK: Pick up loop mode from clips
Decoder::LoopMode old_loop_mode = loop_mode_;
LoopMode old_loop_mode = loop_mode_;
if (const ClipBlock *clip = dynamic_cast<const ClipBlock*>(node)) {
loop_mode_ = clip->loop_mode();
}
@@ -184,11 +184,6 @@ void NodeTraverser::Transform(QTransform *transform, const Node *start, const No
transform_ = nullptr;
}
NodeGlobals NodeTraverser::GenerateGlobals(const VideoParams &vparams, const AudioParams &aparams, const TimeRange &time)
{
return NodeGlobals(vparams, aparams, time);
}
NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& input, const TimeRange& range)
{
// If input is connected, retrieve value directly
@@ -259,7 +254,7 @@ void NodeTraverser::ProcessInputElement(NodeValueTableArray &array_tbl, const No
NodeTraverser::NodeTraverser() :
cancel_(nullptr),
transform_(nullptr),
loop_mode_(Decoder::kLoopModeOff)
loop_mode_(LoopMode::kLoopModeOff)
{
}
@@ -309,7 +304,7 @@ NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& rang
table = database.Merge();
// By this point, the node should have all the inputs it needs to render correctly
NodeGlobals globals = GenerateGlobals(video_params_, audio_params_, range);
NodeGlobals globals(video_params_, audio_params_, range, loop_mode_);
n->Value(row, globals, &table);
// `transform_now_` is the next node in the path that needs to be traversed. It only ever goes
@@ -430,7 +425,7 @@ void NodeTraverser::ResolveJobs(NodeValue &val)
} else if (FootageJob *fj = dynamic_cast<FootageJob*>(base_job)) {
rational footage_time = Footage::AdjustTimeByLoopMode(fj->time().in(), loop_mode_, fj->length(), fj->video_params().video_type(), fj->video_params().frame_rate_as_time_base());
rational footage_time = Footage::AdjustTimeByLoopMode(fj->time().in(), fj->loop_mode(), fj->length(), fj->video_params().video_type(), fj->video_params().frame_rate_as_time_base());
TexturePtr tex;
+2 -8
View File
@@ -54,12 +54,6 @@ public:
void Transform(QTransform *transform, const Node *start, const Node *end, const TimeRange &range);
static NodeGlobals GenerateGlobals(const VideoParams &vparams, const AudioParams &aparams, const TimeRange &time);
static NodeGlobals GenerateGlobals(const VideoParams &vparams, const AudioParams &aparams, const rational &time)
{
return GenerateGlobals(vparams, aparams, TimeRange(time, time + vparams.frame_rate_as_time_base()));
}
const VideoParams& GetCacheVideoParams() const
{
return video_params_;
@@ -144,7 +138,7 @@ protected:
return block_stack_.empty() ? nullptr : block_stack_.back();
}
Decoder::LoopMode loop_mode() const { return loop_mode_; }
LoopMode loop_mode() const { return loop_mode_; }
virtual bool UseCache() const { return false; }
@@ -163,7 +157,7 @@ private:
std::list<Block*> block_stack_;
Decoder::LoopMode loop_mode_;
LoopMode loop_mode_;
QHash<const Node*, QHash<TimeRange, NodeValueTable> > value_cache_;
QHash<Texture*, TexturePtr> resolved_texture_cache_;
+1
View File
@@ -38,6 +38,7 @@ set(OLIVE_SOURCES
render/framehashcache.h
render/framemanager.cpp
render/framemanager.h
render/loopmode.h
render/managedcolor.cpp
render/managedcolor.h
render/playbackcache.cpp
+8 -2
View File
@@ -33,12 +33,13 @@ public:
{
}
FootageJob(const TimeRange &time, const QString& decoder, const QString& filename, Track::Type type, const rational& length) :
FootageJob(const TimeRange &time, const QString& decoder, const QString& filename, Track::Type type, const rational& length, LoopMode loop_mode) :
time_(time),
decoder_(decoder),
filename_(filename),
type_(type),
length_(length)
length_(length),
loop_mode_(loop_mode)
{
}
@@ -99,6 +100,9 @@ public:
const TimeRange &time() const { return time_; }
LoopMode loop_mode() const { return loop_mode_; }
void set_loop_mode(LoopMode m) { loop_mode_ = m; }
private:
TimeRange time_;
@@ -116,6 +120,8 @@ private:
rational length_;
LoopMode loop_mode_;
};
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef LOOPMODE_H
#define LOOPMODE_H
namespace olive {
enum class LoopMode {
kLoopModeOff,
kLoopModeLoop,
kLoopModeClamp
};
}
#endif // LOOPMODE_H
@@ -532,18 +532,18 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q
qreal zebra_right = TimeToScene(clip->in() - clip->media_in());
switch (clip->loop_mode()) {
case Decoder::kLoopModeOff:
case LoopMode::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:
case LoopMode::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:
case LoopMode::kLoopModeClamp:
painter->drawLine(zebra_right, block_top, zebra_right, block_top + block_height);
break;
}
@@ -552,18 +552,18 @@ void TimelineView::DrawBlock(QPainter *painter, bool foreground, Block *block, q
if (clip->length() + clip->media_in() > clip->connected_viewer()->GetLength()) {
qreal zebra_left = TimeToScene(clip->out() - (clip->media_in() + clip->length() - clip->connected_viewer()->GetLength()));
switch (clip->loop_mode()) {
case Decoder::kLoopModeOff:
case LoopMode::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:
case LoopMode::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:
case LoopMode::kLoopModeClamp:
painter->drawLine(zebra_left, block_top, zebra_left, block_top + block_height);
break;
}
+45 -36
View File
@@ -380,15 +380,7 @@ void ViewerDisplayWidget::OnPaint()
VideoParams device_params = GetViewportParams();
if (push_mode_ == kPushBlank) {
if (blank_shader_.isNull()) {
blank_shader_ = renderer()->CreateNativeShader(ShaderCode());
}
ShaderJob job;
job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, combined_matrix_flipped_));
job.Insert(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix_));
renderer()->Blit(blank_shader_, job, device_params, false);
DrawBlank(device_params);
} else if (color_service()) {
if (FramePtr frame = load_frame_.value<FramePtr>()) {
// This is a CPU frame, upload it now
@@ -415,35 +407,39 @@ void ViewerDisplayWidget::OnPaint()
TexturePtr texture_to_draw = texture_;
if (deinterlace_) {
if (deinterlace_shader_.isNull()) {
deinterlace_shader_ = renderer()->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/deinterlace.frag"))));
if (!texture_to_draw || texture_to_draw->IsDummy()) {
DrawBlank(device_params);
} else {
if (deinterlace_) {
if (deinterlace_shader_.isNull()) {
deinterlace_shader_ = renderer()->CreateNativeShader(ShaderCode(FileFunctions::ReadFileAsString(QStringLiteral(":/shaders/deinterlace.frag"))));
}
if (!deinterlace_texture_
|| deinterlace_texture_->params() != texture_to_draw->params()) {
// (Re)create texture
deinterlace_texture_ = renderer()->CreateTexture(texture_to_draw->params());
}
ShaderJob job;
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw)));
renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get());
texture_to_draw = deinterlace_texture_;
}
if (!deinterlace_texture_
|| deinterlace_texture_->params() != texture_to_draw->params()) {
// (Re)create texture
deinterlace_texture_ = renderer()->CreateTexture(texture_to_draw->params());
}
ColorTransformJob ctj;
ctj.SetColorProcessor(color_service());
ctj.SetInputTexture(texture_to_draw);
ctj.SetInputAlphaAssociation(OLIVE_CONFIG("ReassocLinToNonLin").toBool() ? kAlphaAssociated : kAlphaNone);
ctj.SetClearDestinationEnabled(false);
ctj.SetTransformMatrix(combined_matrix_flipped_);
ctj.SetCropMatrix(crop_matrix_);
ShaderJob job;
job.Insert(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture_to_draw)));
renderer()->BlitToTexture(deinterlace_shader_, job, deinterlace_texture_.get());
texture_to_draw = deinterlace_texture_;
renderer()->BlitColorManaged(ctj, device_params);
}
ColorTransformJob ctj;
ctj.SetColorProcessor(color_service());
ctj.SetInputTexture(texture_to_draw);
ctj.SetInputAlphaAssociation(OLIVE_CONFIG("ReassocLinToNonLin").toBool() ? kAlphaAssociated : kAlphaNone);
ctj.SetClearDestinationEnabled(false);
ctj.SetTransformMatrix(combined_matrix_flipped_);
ctj.SetCropMatrix(crop_matrix_);
renderer()->BlitColorManaged(ctj, device_params);
}
}
@@ -455,7 +451,7 @@ void ViewerDisplayWidget::OnPaint()
p.setWorldTransform(gizmo_last_draw_transform_);
gizmos_->UpdateGizmoPositions(gizmo_db_, NodeTraverser::GenerateGlobals(gizmo_params_, gizmo_audio_params_, gizmo_draw_time_));
gizmos_->UpdateGizmoPositions(gizmo_db_, NodeGlobals(gizmo_params_, gizmo_audio_params_, gizmo_draw_time_, LoopMode::kLoopModeOff));
foreach (NodeGizmo *gizmo, gizmos_->GetGizmos()) {
if (gizmo->IsVisible()) {
gizmo->Draw(&p);
@@ -831,7 +827,7 @@ bool ViewerDisplayWidget::OnMousePress(QMouseEvent *event)
// Handle gizmo click
gizmo_start_drag_ = event->pos();
gizmo_last_drag_ = gizmo_start_drag_;
current_gizmo_->SetGlobals(NodeTraverser::GenerateGlobals(gizmo_params_, gizmo_audio_params_, GenerateGizmoTime()));
current_gizmo_->SetGlobals(NodeGlobals(gizmo_params_, gizmo_audio_params_, GenerateGizmoTime(), LoopMode::kLoopModeOff));
} else {
@@ -1213,6 +1209,19 @@ void ViewerDisplayWidget::GenerateGizmoTransforms()
gizmo_last_draw_transform_inverted_ = gizmo_last_draw_transform_.inverted();
}
void ViewerDisplayWidget::DrawBlank(const VideoParams &device_params)
{
if (blank_shader_.isNull()) {
blank_shader_ = renderer()->CreateNativeShader(ShaderCode());
}
ShaderJob job;
job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, combined_matrix_flipped_));
job.Insert(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix_));
renderer()->Blit(blank_shader_, job, device_params, false);
}
void ViewerDisplayWidget::SetShowFPS(bool e)
{
show_fps_ = e;
+2
View File
@@ -306,6 +306,8 @@ private:
void GenerateGizmoTransforms();
void DrawBlank(const VideoParams &device_params);
/**
* @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL().
*/