Update FFmpeg handling and focus management
Refactor FFmpeg frame processing and improve focus management in panels. Add memory sanitization for debug builds and update KDDockWidgets integration.
This commit is contained in:
@@ -5,3 +5,4 @@
|
||||
[submodule "ext/KDDockWidgets"]
|
||||
path = ext/KDDockWidgets
|
||||
url = https://github.com/olive-editor/KDDockWidgets.git
|
||||
branch = main
|
||||
|
||||
+6
-2
@@ -17,7 +17,11 @@
|
||||
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
|
||||
|
||||
project(olive-editor VERSION 0.2.0 LANGUAGES CXX)
|
||||
|
||||
if(${CMAKE_BUILD_TYPE} EQUAL Debug)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -g")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -g")
|
||||
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory)
|
||||
endif ()
|
||||
option(BUILD_QT6 "Build with Qt 6 over 5 (experimental)" ON)
|
||||
option(BUILD_DOXYGEN "Build Doxygen documentation" OFF)
|
||||
option(BUILD_TESTS "Build unit tests" OFF)
|
||||
@@ -168,7 +172,7 @@ list(APPEND OLIVE_LIBRARIES
|
||||
)
|
||||
|
||||
# Link FFmpeg
|
||||
find_package(FFMPEG 3.0 REQUIRED
|
||||
find_package(FFMPEG REQUIRED
|
||||
COMPONENTS
|
||||
avutil
|
||||
avcodec
|
||||
|
||||
@@ -140,7 +140,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f,
|
||||
break;
|
||||
}
|
||||
|
||||
AVFrame *hw_in = f.get();
|
||||
AVFramePtr hw_in = f;
|
||||
|
||||
VideoParams plane_params = vp;
|
||||
plane_params.set_channel_count(1);
|
||||
@@ -148,7 +148,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f,
|
||||
|
||||
TexturePtr y_plane = p.renderer->CreateTexture(
|
||||
plane_params, hw_in->data[0], hw_in->linesize[0] / px_size);
|
||||
|
||||
y_plane->handleFrame(hw_in);
|
||||
switch (f->format) {
|
||||
case AV_PIX_FMT_YUV420P:
|
||||
case AV_PIX_FMT_YUV422P:
|
||||
@@ -170,8 +170,11 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f,
|
||||
|
||||
TexturePtr u_plane = p.renderer->CreateTexture(
|
||||
plane_params, hw_in->data[1], hw_in->linesize[1] / px_size);
|
||||
u_plane->handleFrame(hw_in);
|
||||
|
||||
TexturePtr v_plane = p.renderer->CreateTexture(
|
||||
plane_params, hw_in->data[2], hw_in->linesize[2] / px_size);
|
||||
v_plane->handleFrame(hw_in);
|
||||
|
||||
ShaderJob job;
|
||||
job.Insert(QStringLiteral("y_channel"),
|
||||
@@ -207,6 +210,7 @@ TexturePtr FFmpegDecoder::ProcessFrameIntoTexture(AVFramePtr f,
|
||||
case AV_PIX_FMT_RGBA:
|
||||
case AV_PIX_FMT_RGBA64LE:
|
||||
// RGBA can be uploaded directly to the texture
|
||||
tex->handleFrame(f);
|
||||
tex->Upload(f->data[0], f->linesize[0] / vp.GetBytesPerPixel());
|
||||
break;
|
||||
}
|
||||
@@ -282,14 +286,17 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
|
||||
AVCOL_RANGE_MPEG;
|
||||
|
||||
// Perform any CPU processing required
|
||||
f = PreProcessFrame(f, p);
|
||||
AVFramePtr ptr = PreProcessFrame(f, p);
|
||||
f=std::move(ptr);
|
||||
if (!f) {
|
||||
// Error occurred while software scaling
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Finally, perform any GPU processing required
|
||||
return ProcessFrameIntoTexture(f, p, original);
|
||||
TexturePtr texture = ProcessFrameIntoTexture(f, p, original);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -799,7 +806,7 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f,
|
||||
dest->format = f->format;
|
||||
dest->color_range = f->color_range;
|
||||
dest->colorspace = f->colorspace;
|
||||
|
||||
dest->hw_frames_ctx = nullptr;
|
||||
if (p.divider > 1) {
|
||||
dest->width = VideoParams::GetScaledDimension(dest->width, p.divider);
|
||||
dest->height = VideoParams::GetScaledDimension(dest->height, p.divider);
|
||||
@@ -852,8 +859,8 @@ AVFramePtr FFmpegDecoder::PreProcessFrame(AVFramePtr f,
|
||||
dest->color_range == AVCOL_RANGE_JPEG ? 1 : 0, 0, 0x10000, 0x10000);
|
||||
}
|
||||
|
||||
r = sws_scale(sws_ctx_, f->data, f->linesize, 0, f->height, dest->data,
|
||||
dest->linesize);
|
||||
r = sws_scale_frame(sws_ctx_, dest.get(), f.get());
|
||||
|
||||
if (r < 0) {
|
||||
FFmpegError(r);
|
||||
return nullptr;
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
using AVFramePtr = std::shared_ptr<AVFrame>;
|
||||
inline AVFramePtr CreateAVFramePtr(AVFrame *f)
|
||||
{
|
||||
return std::shared_ptr<AVFrame>(f, [](AVFrame *g) { av_frame_free(&g); });
|
||||
return std::shared_ptr<AVFrame>(f, [](AVFrame *g) { av_frame_free(&g); });
|
||||
}
|
||||
inline AVFramePtr CreateAVFramePtr()
|
||||
{
|
||||
|
||||
@@ -776,6 +776,7 @@ void Core::StartGUI(bool full_screen)
|
||||
connect(qApp, &QApplication::focusChanged, PanelManager::instance(),
|
||||
&PanelManager::FocusChanged);
|
||||
|
||||
KDDockWidgets::initFrontend(KDDockWidgets::FrontendType::QtWidgets);
|
||||
// Set KDDockWidgets flags
|
||||
auto &config = KDDockWidgets::Config::self();
|
||||
auto flags = config.flags();
|
||||
|
||||
@@ -145,6 +145,7 @@ int decompress_project(const QString &project)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Set up debug handler
|
||||
qInstallMessageHandler(olive::DebugHandler);
|
||||
|
||||
|
||||
+15
-3
@@ -27,23 +27,26 @@
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QVariant>
|
||||
#include "Window_p.h"
|
||||
|
||||
#include "panel/panelmanager.h"
|
||||
|
||||
#include <OpenImageIO/hash.h>
|
||||
|
||||
namespace olive
|
||||
{
|
||||
|
||||
#define super KDDockWidgets::DockWidget
|
||||
#define super KDDockWidgets::QtWidgets::DockWidget
|
||||
|
||||
PanelWidget::PanelWidget(const QString &object_name)
|
||||
: super(object_name)
|
||||
, border_visible_(false)
|
||||
, signal_instead_of_close_(false)
|
||||
{
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
View<QWidget>::setFocusPolicy(Qt::ClickFocus);
|
||||
|
||||
connect(this, &PanelWidget::shown, this,
|
||||
static_cast<void (PanelWidget::*)()>(&PanelWidget::setFocus));
|
||||
reinterpret_cast<void (PanelWidget::*)()>(&PanelWidget::setFocus));
|
||||
|
||||
PanelManager::instance()->RegisterPanel(this);
|
||||
}
|
||||
@@ -125,6 +128,15 @@ void PanelWidget::changeEvent(QEvent *e)
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
Retranslate();
|
||||
}
|
||||
|
||||
if (e->type() == QEvent::WindowStateChange) {
|
||||
if (isVisible() && !isMinimized()) {
|
||||
emit shown(Qt::OtherFocusReason);
|
||||
}
|
||||
else {
|
||||
emit hidden();
|
||||
}
|
||||
}
|
||||
super::changeEvent(e);
|
||||
}
|
||||
|
||||
|
||||
+13
-3
@@ -21,18 +21,23 @@
|
||||
#ifndef PANEL_WIDGET_H
|
||||
#define PANEL_WIDGET_H
|
||||
|
||||
#include "KDDockWidgets/src/core/Window_p.h"
|
||||
#include "KDDockWidgets/src/qtwidgets/views/TabBar.h"
|
||||
|
||||
#include <kddockwidgets/DockWidget.h>
|
||||
#include <QEvent>
|
||||
|
||||
#include "common/define.h"
|
||||
|
||||
#include <QTabWidget>
|
||||
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A widget that is always dockable within the MainWindow.
|
||||
*/
|
||||
class PanelWidget : public KDDockWidgets::DockWidget {
|
||||
class PanelWidget : public KDDockWidgets::QtWidgets::DockWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
@@ -279,7 +284,8 @@ public:
|
||||
|
||||
signals:
|
||||
void CloseRequested();
|
||||
|
||||
void shown(Qt::FocusReason reason);
|
||||
void hidden();
|
||||
protected:
|
||||
/**
|
||||
* @brief paintEvent
|
||||
@@ -323,7 +329,7 @@ protected slots:
|
||||
* String to set the subtitle to
|
||||
*/
|
||||
void SetSubtitle(const QString &t);
|
||||
|
||||
protected slots:
|
||||
private:
|
||||
/**
|
||||
* @brief Internal function that sets the QDockWidget's window title whenever the title/subtitle change.
|
||||
@@ -339,6 +345,10 @@ private:
|
||||
bool border_visible_;
|
||||
|
||||
bool signal_instead_of_close_;
|
||||
|
||||
QMetaObject::Connection m_tabBarConnection;
|
||||
QMetaObject::Connection m_windowConnection;
|
||||
bool m_lastVisibleState = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ void ProjectPanel::ItemDoubleClickSlot(Node *item)
|
||||
PanelManager::instance()->MostRecentlyFocused<FootageViewerPanel>();
|
||||
panel->ConnectViewerNode(static_cast<Footage *>(item));
|
||||
panel->raise();
|
||||
panel->setFocus();
|
||||
panel->setFocus(Qt::FocusReason::MouseFocusReason);
|
||||
} else if (dynamic_cast<Sequence *>(item)) {
|
||||
// Open this sequence in the Timeline
|
||||
Core::instance()->main_window()->OpenSequence(
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#ifndef RENDERTEXTURE_H
|
||||
#define RENDERTEXTURE_H
|
||||
|
||||
#include "common/ffmpegutils.h"
|
||||
|
||||
#include <memory>
|
||||
#include <QVariant>
|
||||
|
||||
@@ -150,7 +152,10 @@ public:
|
||||
{
|
||||
return job_;
|
||||
}
|
||||
|
||||
void handleFrame(AVFramePtr ptr)
|
||||
{
|
||||
frame_=ptr;
|
||||
}
|
||||
private:
|
||||
Renderer *renderer_;
|
||||
|
||||
@@ -159,6 +164,8 @@ private:
|
||||
QVariant id_;
|
||||
|
||||
AcceleratedJob *job_;
|
||||
|
||||
AVFramePtr frame_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1203,8 +1203,11 @@ void ViewerWidget::UpdateMinimumScale()
|
||||
// Avoids divide by zero
|
||||
SetMinimumScale(0);
|
||||
} else {
|
||||
SetMinimumScale(static_cast<double>(ruler()->width()) /
|
||||
GetConnectedNode()->GetLength().toDouble());
|
||||
double min_scale = static_cast<double>(ruler()->width()) /
|
||||
GetConnectedNode()->GetLength().toDouble();
|
||||
// Ensure min_scale doesn't exceed max_scale to prevent crash
|
||||
min_scale = qMin(min_scale, GetMaximumScale());
|
||||
SetMinimumScale(min_scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,15 +29,17 @@
|
||||
#include <QOffscreenSurface>
|
||||
#endif
|
||||
|
||||
#include "KDDockWidgets/src/qtwidgets/Window_p.h"
|
||||
#include "dialog/about/about.h"
|
||||
#include "mainmenu.h"
|
||||
#include "mainstatusbar.h"
|
||||
#include "KDDockWidgets/src/LayoutSaver.h"
|
||||
#include "timeline/timelineundoworkarea.h"
|
||||
|
||||
namespace olive
|
||||
{
|
||||
|
||||
#define super KDDockWidgets::MainWindow
|
||||
#define super KDDockWidgets::QtWidgets::MainWindow
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: super(QStringLiteral("OliveMain"), KDDockWidgets::MainWindowOption_None,
|
||||
@@ -95,7 +97,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
// emit the "shown" signal before emitting the "hidden" signals, resulting
|
||||
// in Core thinking there are -1 pixel samplers open. To mitigate that,
|
||||
// we force "shown" to emit ourselves here.
|
||||
emit pixel_sampler_panel_->shown();
|
||||
emit pixel_sampler_panel_->shown(Qt::OtherFocusReason);
|
||||
|
||||
// Make node-related connections
|
||||
connect(node_panel_, &NodePanel::NodeSelectionChangedWithContexts,
|
||||
@@ -382,7 +384,7 @@ void MainWindow::ToggleMaximizedPanel()
|
||||
premaximized_state_.clear();
|
||||
|
||||
currently_focused_panel->raise();
|
||||
currently_focused_panel->setFocus();
|
||||
currently_focused_panel->setFocus(Qt::ActiveWindowFocusReason);
|
||||
|
||||
PanelManager::instance()->SetSuppressChangedSignal(false);
|
||||
}
|
||||
@@ -430,7 +432,7 @@ void MainWindow::SetProject(Project *p)
|
||||
project_panel_->set_project(p);
|
||||
|
||||
if (project_) {
|
||||
project_panel_->setFocus();
|
||||
project_panel_->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace olive
|
||||
/**
|
||||
* @brief Olive's main window responsible for docking widgets and the main menu bar.
|
||||
*/
|
||||
class MainWindow : public KDDockWidgets::MainWindow {
|
||||
class MainWindow : public KDDockWidgets::QtWidgets::MainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
|
||||
+1
-1
Submodule ext/KDDockWidgets updated: f24a04252b...d24ba267da
+1
-1
Submodule ext/core updated: 25e4152bb7...a3628c4641
Reference in New Issue
Block a user