Merge branch 'master' into nodeview-redux

This commit is contained in:
itsmattkc
2021-05-29 20:57:52 +10:00
49 changed files with 674 additions and 374 deletions
+11 -2
View File
@@ -60,10 +60,19 @@ void ColorPreviewBox::paintEvent(QPaintEvent *e)
QPainter p(this);
QRect draw_rect = rect().adjusted(0, 0, -1, -1);
p.setPen(Qt::black);
if (color_.alpha() < 1.0) {
// Draw black background so the background isn't the window color
p.setBrush(Qt::black);
p.drawRect(draw_rect);
}
// Draw with color over the top
p.setBrush(c);
p.drawRect(rect().adjusted(0, 0, -1, -1));
p.drawRect(draw_rect);
}
}
+9 -1
View File
@@ -27,7 +27,13 @@ namespace olive {
PixelSamplerWidget::PixelSamplerWidget(QWidget *parent) :
QGroupBox(parent)
{
QVBoxLayout* layout = new QVBoxLayout(this);
QHBoxLayout* layout = new QHBoxLayout(this);
box_ = new ColorPreviewBox();
QFontMetrics fm = fontMetrics();
int box_sz = fm.height() * 2;
box_->setFixedSize(box_sz, box_sz);
layout->addWidget(box_);
label_ = new QLabel();
layout->addWidget(label_);
@@ -45,6 +51,8 @@ void PixelSamplerWidget::SetValues(const Color &color)
void PixelSamplerWidget::UpdateLabelInternal()
{
box_->SetColor(color_);
label_->setText(tr("<html>"
"<font color='#FF8080'>R: %1</font><br>"
"<font color='#80FF80'>G: %2</font><br>"
+3
View File
@@ -26,6 +26,7 @@
#include <QWidget>
#include "render/color.h"
#include "widget/colorwheel/colorpreviewbox.h"
namespace olive {
@@ -43,6 +44,8 @@ private:
Color color_;
ColorPreviewBox *box_;
QLabel* label_;
};
+11 -38
View File
@@ -28,23 +28,22 @@ namespace olive {
ScopeBase::ScopeBase(QWidget* parent) :
super(parent),
buffer_(nullptr)
texture_(nullptr),
managed_tex_up_to_date_(false)
{
EnableDefaultContextMenu();
}
void ScopeBase::SetBuffer(Frame *frame)
void ScopeBase::SetBuffer(TexturePtr frame)
{
buffer_ = frame;
UploadTextureFromBuffer();
texture_ = frame;
managed_tex_up_to_date_ = false;
update();
}
void ScopeBase::showEvent(QShowEvent* e)
{
super::showEvent(e);
UploadTextureFromBuffer();
}
void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline)
@@ -58,32 +57,6 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline)
VideoParams::kInternalChannelCount));
}
void ScopeBase::UploadTextureFromBuffer()
{
if (!isVisible()) {
return;
}
if (buffer_) {
makeCurrent();
if (!texture_ || texture_->params() != buffer_->video_params()) {
texture_ = nullptr;
managed_tex_ = nullptr;
texture_ = renderer()->CreateTexture(buffer_->video_params(),
buffer_->data(), buffer_->linesize_pixels());
managed_tex_ = renderer()->CreateTexture(buffer_->video_params());
} else {
texture_->Upload(buffer_->data(), buffer_->linesize_pixels());
}
doneCurrent();
}
update();
}
void ScopeBase::OnInit()
{
super::OnInit();
@@ -96,13 +69,13 @@ void ScopeBase::OnPaint()
// Clear display surface
renderer()->ClearDestination();
if (buffer_) {
if (texture_) {
// Convert reference frame to display space
if (!texture_ || !managed_tex_) {
UploadTextureFromBuffer();
makeCurrent(); // UploadTextureFromBuffer calls "doneCurrent", so we re-call "makeCurrent"
if (!managed_tex_ || !managed_tex_up_to_date_
|| managed_tex_->params() != texture_->params()) {
managed_tex_ = renderer()->CreateTexture(texture_->params());
renderer()->BlitColorManaged(color_service(), texture_, true, managed_tex_.get());
}
renderer()->BlitColorManaged(color_service(), texture_, true, managed_tex_.get());
DrawScope(managed_tex_, pipeline_);
}
+2 -4
View File
@@ -35,7 +35,7 @@ public:
MANAGEDDISPLAYWIDGET_DEFAULT_DESTRUCTOR(ScopeBase)
public slots:
void SetBuffer(Frame* frame);
void SetBuffer(TexturePtr frame);
protected slots:
virtual void OnInit() override;
@@ -57,15 +57,13 @@ protected:
virtual void DrawScope(TexturePtr managed_tex, QVariant pipeline);
private:
void UploadTextureFromBuffer();
QVariant pipeline_;
TexturePtr texture_;
TexturePtr managed_tex_;
Frame* buffer_;
bool managed_tex_up_to_date_;
};
+22 -8
View File
@@ -463,7 +463,6 @@ public:
Q_ASSERT(i == 0 || time > times_.at(i-1));
QVector<Block*> splits(blocks_.size());
commands_.resize(blocks_.size());
for (int j=0;j<blocks_.size();j++) {
Block* b = blocks_.at(j);
@@ -472,7 +471,7 @@ public:
BlockSplitCommand* split_command = new BlockSplitCommand(b, time);
split_command->redo();
splits.replace(j, split_command->new_block());
commands_.replace(j, split_command);
commands_.append(split_command);
} else {
splits.replace(j, nullptr);
}
@@ -2045,8 +2044,8 @@ public:
}
foreach (auto add_gap, gaps_added_) {
add_gap.gap->setParent(add_gap.before->parent());
add_gap.before->track()->InsertBlockAfter(add_gap.gap, add_gap.before);
add_gap.gap->setParent(add_gap.track->parent());
add_gap.track->InsertBlockAfter(add_gap.gap, add_gap.before);
}
foreach (Track* track, working_tracks_) {
@@ -2121,6 +2120,7 @@ private:
QVector<Block*> blocks_to_split;
QVector<Block*> blocks_to_append_gap_to;
QVector<Track*> tracks_to_append_gap_to;
foreach (Track* track, working_tracks_) {
foreach (Block* b, track->Blocks()) {
@@ -2129,11 +2129,24 @@ private:
gaps_to_extend_.append(b);
break;
} else if (dynamic_cast<ClipBlock*>(b) && b->out() >= point_) {
if (b->out() > point_) {
bool append_gap = true;
if (b->in() == point_) {
// The only reason we should be here is if this block is at the start of the track,
// in which case no split needs to occur
b = nullptr;
} else if (b->out() > point_) {
// Block must be split as well as having a gap appended to it
blocks_to_split.append(b);
} else if (!b->next()) {
// At the end of a track, no gap needs to be added at all
append_gap = false;
}
blocks_to_append_gap_to.append(b);
if (append_gap) {
tracks_to_append_gap_to.append(track);
blocks_to_append_gap_to.append(b);
}
break;
}
}
@@ -2143,11 +2156,11 @@ private:
split_command_ = new BlockSplitPreservingLinksCommand(blocks_to_split, {point_});
}
foreach (Block* block, blocks_to_append_gap_to) {
for (int i=0; i<blocks_to_append_gap_to.size(); i++) {
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(length_);
gap->setParent(&memory_manager_);
gaps_added_.append({gap, block});
gaps_added_.append({gap, blocks_to_append_gap_to.at(i), tracks_to_append_gap_to.at(i)});
}
}
@@ -2166,6 +2179,7 @@ private:
struct AddGap {
GapBlock* gap;
Block* before;
Track* track;
};
QVector<AddGap> gaps_added_;
+15 -41
View File
@@ -56,8 +56,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
color_menu_enabled_(true),
time_changed_from_timer_(false),
prequeuing_(false),
last_loaded_buffer_(nullptr),
last_loaded_buffer_is_empty_(false),
active_queue_jobs_(0),
cache_time_(rational::NaN)
{
@@ -83,6 +81,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
connect(display_widget_, &ViewerDisplayWidget::DragEntered, this, &ViewerWidget::DragEntered);
connect(display_widget_, &ViewerDisplayWidget::Dropped, this, &ViewerWidget::Dropped);
connect(display_widget_, &ViewerDisplayWidget::VisibilityChanged, this, &ViewerWidget::Pause);
connect(display_widget_, &ViewerDisplayWidget::TextureChanged, this, &ViewerWidget::TextureChanged);
connect(sizer_, &ViewerSizer::RequestScale, display_widget_, &ViewerDisplayWidget::SetMatrixZoom);
connect(sizer_, &ViewerSizer::RequestTranslate, display_widget_, &ViewerDisplayWidget::SetMatrixTranslate);
connect(display_widget_, &ViewerDisplayWidget::HandDragMoved, sizer_, &ViewerSizer::HandDragMove);
@@ -249,7 +248,7 @@ void ViewerWidget::DisconnectNodeEvent(ViewerOutput *n)
disconnect(n->audio_playback_cache(), &AudioPlaybackCache::Validated, this, &ViewerWidget::AudioCacheValidated);
disconnect(n, &ViewerOutput::TextureInputChanged, this, &ViewerWidget::UpdateStack);
SetDisplayImage(nullptr);
SetDisplayImage(QVariant());
ruler()->SetPlaybackCache(nullptr);
@@ -351,7 +350,7 @@ void ViewerWidget::SetFullScreen(QScreen *screen)
vw->display_widget()->SetDeinterlacing(vw->display_widget()->IsDeinterlacing());
}
vw->display_widget()->SetImage(last_loaded_buffer_);
vw->display_widget()->SetImage(QVariant::fromValue(display_widget()->GetCurrentTexture()));
windows_.insert(screen, vw);
}
@@ -420,33 +419,10 @@ bool ViewerWidget::ShouldForceWaveform() const
void ViewerWidget::SetEmptyImage()
{
FramePtr frame = nullptr;
display_widget()->SetBlank();
if (GetConnectedNode()) {
frame = last_loaded_buffer_;
if (!frame) {
frame = Frame::Create();
}
if (frame->video_params() != GetConnectedNode()->GetVideoParams()) {
frame->destroy();
frame->set_video_params(GetConnectedNode()->GetVideoParams());
}
if (!frame->is_allocated()) {
frame->allocate();
}
if (!last_loaded_buffer_is_empty_) {
memset(frame->data(), 0, frame->allocated_size());
}
}
SetDisplayImage(frame);
if (frame) {
last_loaded_buffer_is_empty_ = true;
foreach (ViewerWindow *vw, windows_) {
vw->display_widget()->SetBlank();
}
}
@@ -554,6 +530,7 @@ void ViewerWidget::UpdateTextureFromNode()
} else {
// Not playing, run a task to get the frame either from the cache or the renderer
RenderTicketWatcher* watcher = new RenderTicketWatcher();
watcher->setProperty("time", QVariant::fromValue(time));
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame);
nonqueue_watchers_.append(watcher);
watcher->SetTicket(GetFrame(time, true));
@@ -723,7 +700,7 @@ bool ViewerWidget::ViewerMightBeAStill()
return GetConnectedNode() && GetConnectedNode()->GetConnectedTextureOutput().IsValid() && GetConnectedNode()->GetVideoLength().isNull();
}
void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only)
void ViewerWidget::SetDisplayImage(QVariant frame, bool main_only)
{
display_widget_->SetImage(frame);
@@ -732,10 +709,6 @@ void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only)
vw->display_widget()->SetImage(frame);
}
}
last_loaded_buffer_ = frame;
last_loaded_buffer_is_empty_ = false;
emit LoadedBuffer(frame.get());
}
void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
@@ -749,6 +722,7 @@ void ViewerWidget::RequestNextFrameForQueue(bool prioritize, bool increment)
}
RenderTicketWatcher* watcher = new RenderTicketWatcher();
watcher->setProperty("time", QVariant::fromValue(next_time));
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue);
watcher->SetTicket(GetFrame(next_time, prioritize));
active_queue_jobs_++;
@@ -886,8 +860,6 @@ void ViewerWidget::RendererGeneratedFrame()
RenderTicketWatcher* ticket = static_cast<RenderTicketWatcher*>(sender());
if (ticket->HasResult()) {
FramePtr frame = ticket->Get().value<FramePtr>();
if (nonqueue_watchers_.contains(ticket)) {
while (!nonqueue_watchers_.isEmpty()) {
if (nonqueue_watchers_.takeFirst() == ticket) {
@@ -895,7 +867,7 @@ void ViewerWidget::RendererGeneratedFrame()
}
}
SetDisplayImage(frame);
SetDisplayImage(ticket->Get());
}
}
@@ -907,14 +879,16 @@ void ViewerWidget::RendererGeneratedFrameForQueue()
RenderTicketWatcher* watcher = static_cast<RenderTicketWatcher*>(sender());
if (watcher->HasResult()) {
FramePtr frame = watcher->Get().value<FramePtr>();
QVariant frame = watcher->Get();
// Ignore this signal if we've paused now
if (IsPlaying() || prequeuing_) {
playback_queue_.AppendTimewise({frame->timestamp(), frame}, playback_speed_);
rational ts = watcher->property("time").value<rational>();
playback_queue_.AppendTimewise({ts, frame}, playback_speed_);
foreach (ViewerWindow* window, windows_) {
window->queue()->AppendTimewise({frame->timestamp(), frame}, playback_speed_);
window->queue()->AppendTimewise({ts, frame}, playback_speed_);
}
if (prequeuing_ && int(playback_queue_.size()) == prequeue_length_) {
+2 -5
View File
@@ -128,7 +128,7 @@ signals:
/**
* @brief Signal emitted when a new frame is loaded
*/
void LoadedBuffer(Frame* load_buffer);
void TextureChanged(TexturePtr t);
/**
* @brief Request a scope panel
@@ -185,7 +185,7 @@ private:
bool ViewerMightBeAStill();
void SetDisplayImage(FramePtr frame, bool main_only = false);
void SetDisplayImage(QVariant frame, bool main_only = false);
void RequestNextFrameForQueue(bool prioritize = false, bool increment = true);
@@ -251,9 +251,6 @@ private:
QTimer audio_restart_timer_;
FramePtr last_loaded_buffer_;
bool last_loaded_buffer_is_empty_;
int active_queue_jobs_;
rational cache_time_;
+84 -47
View File
@@ -45,13 +45,12 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
signal_cursor_color_(false),
gizmos_(nullptr),
gizmo_click_(false),
last_loaded_buffer_(nullptr),
hand_dragging_(false),
deinterlace_(false),
show_fps_(false),
frames_skipped_(0),
show_widget_background_(false),
texture_equal_to_frame_(false)
push_mode_(kPushNull)
{
connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::UpdateCursor);
@@ -100,17 +99,26 @@ void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e)
inner_widget()->setMouseTracking(e);
}
void ViewerDisplayWidget::SetImage(FramePtr in_buffer)
void ViewerDisplayWidget::SetImage(const QVariant &buffer)
{
if (last_loaded_buffer_ != in_buffer) {
last_loaded_buffer_ = in_buffer;
load_frame_ = buffer;
texture_equal_to_frame_ = false;
if (load_frame_.isNull()) {
push_mode_ = kPushNull;
} else {
push_mode_ = kPushFrame;
}
update();
}
void ViewerDisplayWidget::SetBlank()
{
push_mode_ = kPushBlank;
update();
}
void ViewerDisplayWidget::SetDeinterlacing(bool e)
{
deinterlace_ = e;
@@ -318,51 +326,73 @@ void ViewerDisplayWidget::OnPaint()
{
// Clear background to empty
QColor bg_color = show_widget_background_ ? palette().window().color() : Qt::black;
renderer()->ClearDestination(bg_color.redF(), bg_color.greenF(), bg_color.blueF());
renderer()->ClearDestination(nullptr, bg_color.redF(), bg_color.greenF(), bg_color.blueF());
// We only draw if we have a pipeline
if (last_loaded_buffer_ && color_service()) {
if (!texture_
|| texture_->width() != last_loaded_buffer_->width()
|| texture_->height() != last_loaded_buffer_->height()
|| texture_->format() != last_loaded_buffer_->format()
|| texture_->channel_count() != last_loaded_buffer_->channel_count()) {
texture_ = renderer()->CreateTexture(last_loaded_buffer_->video_params(), last_loaded_buffer_->data(), last_loaded_buffer_->linesize_pixels());
} else if (!texture_equal_to_frame_) {
texture_->Upload(last_loaded_buffer_->data(), last_loaded_buffer_->linesize_pixels());
}
texture_equal_to_frame_ = true;
TexturePtr texture_to_draw = texture_;
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.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
job.InsertValue(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 (push_mode_ != kPushNull) {
// Draw texture through color transform
int device_width = width() * devicePixelRatioF();
int device_height = height() * devicePixelRatioF();
VideoParams::Format device_format = static_cast<VideoParams::Format>(Config::Current()["OfflinePixelFormat"].toInt());
VideoParams device_params(device_width, device_height, device_format, VideoParams::kInternalChannelCount);
renderer()->BlitColorManaged(color_service(), texture_to_draw, true, device_params, false,
combined_matrix_flipped_, crop_matrix_);
if (push_mode_ == kPushBlank) {
if (blank_shader_.isNull()) {
blank_shader_ = renderer()->CreateNativeShader(ShaderCode());
}
ShaderJob job;
job.InsertValue(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, combined_matrix_flipped_));
job.InsertValue(QStringLiteral("ove_cropmatrix"), NodeValue(NodeValue::kMatrix, crop_matrix_));
renderer()->Blit(blank_shader_, job, device_params, false);
} else if (color_service()) {
if (FramePtr frame = load_frame_.value<FramePtr>()) {
// This is a CPU frame, upload it now
if (!texture_
|| texture_->renderer() != renderer() // Some implementations don't like it if we upload to a texture created in another (albeit shared) context
|| texture_->width() != frame->width()
|| texture_->height() != frame->height()
|| texture_->format() != frame->format()
|| texture_->channel_count() != frame->channel_count()) {
texture_ = renderer()->CreateTexture(frame->video_params(), frame->data(), frame->linesize_pixels());
} else {
texture_->Upload(frame->data(), frame->linesize_pixels());
}
} else if (TexturePtr texture = load_frame_.value<TexturePtr>()) {
// This is a GPU texture, switch to it directly
texture_ = texture;
}
emit TextureChanged(texture_);
push_mode_ = kPushUnnecessary;
TexturePtr texture_to_draw = texture_;
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.InsertValue(QStringLiteral("resolution_in"), NodeValue(NodeValue::kVec2, QVector2D(texture_to_draw->width(), texture_to_draw->height())));
job.InsertValue(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(color_service(), texture_to_draw, true, device_params, false,
combined_matrix_flipped_, crop_matrix_);
}
}
// Draw gizmos if we have any
@@ -452,12 +482,20 @@ void ViewerDisplayWidget::OnPaint()
void ViewerDisplayWidget::OnDestroy()
{
renderer()->DestroyNativeShader(deinterlace_shader_);
deinterlace_shader_.clear();
renderer()->DestroyNativeShader(blank_shader_);
blank_shader_.clear();
super::OnDestroy();
texture_ = nullptr;
deinterlace_texture_ = nullptr;
if (load_frame_.isNull()) {
push_mode_ = kPushNull;
} else {
push_mode_ = kPushFrame;
}
}
QPointF ViewerDisplayWidget::GetTexturePosition(const QPoint &screen_pos)
@@ -542,12 +580,11 @@ void ViewerDisplayWidget::EmitColorAtCursor(QMouseEvent *e)
if (signal_cursor_color_) {
Color reference, display;
if (last_loaded_buffer_) {
if (texture_) {
QPointF pixel_pos = GenerateGizmoTransform().inverted().map(e->pos());
pixel_pos /= texture_->params().divider();
pixel_pos /= last_loaded_buffer_->video_params().divider();
reference = last_loaded_buffer_->get_pixel(qRound(pixel_pos.x()), qRound(pixel_pos.y()));
reference = renderer()->GetPixelFromTexture(texture_.get(), pixel_pos);
display = color_service()->ConvertColor(reference);
}
+32 -10
View File
@@ -102,6 +102,11 @@ public:
fps_timer_update_count_++;
}
TexturePtr GetCurrentTexture() const
{
return texture_;
}
public slots:
/**
* @brief Set the transformation matrix to draw with
@@ -126,13 +131,9 @@ public slots:
*/
void SetSignalCursorColorEnabled(bool e);
/**
* @brief Overrides the image with the load buffer of another ViewerGLWidget
*
* If there are multiple ViewerGLWidgets showing the same thing, this is faster than decoding the image from file
* each time.
*/
void SetImage(FramePtr in_buffer);
void SetImage(const QVariant &buffer);
void SetBlank();
/**
* @brief Changes the pointer type if the tool is changed to the hand tool. Otherwise resets the pointer to it's
@@ -181,6 +182,8 @@ signals:
void VisibilityChanged(bool visible);
void TextureChanged(TexturePtr texture);
protected:
/**
* @brief Override the mouse press event for the DragStarted() signal and gizmos
@@ -249,6 +252,11 @@ private:
*/
QVariant deinterlace_shader_;
/**
* @brief Blank shader
*/
QVariant blank_shader_;
/**
* @brief Translation only matrix (defaults to identity).
*/
@@ -283,8 +291,6 @@ private:
rational time_;
FramePtr last_loaded_buffer_;
/**
* @brief Position of mouse to calculate delta from.
*/
@@ -304,7 +310,23 @@ private:
bool show_widget_background_;
bool texture_equal_to_frame_;
QVariant load_frame_;
enum PushMode {
/// New frame to push to internal texture
kPushFrame,
/// Internal texture reference is up to date, keep showing it
kPushUnnecessary,
/// Draw blank/black screen
kPushBlank,
/// Draw nothing (not even a black frame)
kPushNull,
};
PushMode push_mode_;
private slots:
void EmitColorAtCursor(QMouseEvent* e);
+1 -1
View File
@@ -29,7 +29,7 @@ namespace olive {
struct ViewerPlaybackFrame {
rational timestamp;
FramePtr frame;
QVariant frame;
};
class ViewerQueue : public std::list<ViewerPlaybackFrame> {