Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
243cb5a
Replace custom VideoWidgets with QML VideoOutput
ddennedy May 11, 2026
b1dd45e
Settings > Player > External Monitor > HDR Preview Window
ddennedy May 13, 2026
fb5c767
fix cmake configure
ddennedy May 13, 2026
a7d0417
fix HDR on Windows
ddennedy May 13, 2026
9270a80
Propagate keyboard events from HdrPreviewWindow
ddennedy May 13, 2026
3093e0f
add playback controls
ddennedy May 13, 2026
64ccba4
AVX2/SSE2 optimizations in VideoWidget
ddennedy May 13, 2026
9b46412
build and use a minimal Qt media plugin on Linux
ddennedy May 14, 2026
cda08d1
only build and install minimal media for linux
ddennedy May 14, 2026
394ca46
fix build on macos
ddennedy May 14, 2026
9040d3a
fix HDR levels on macOS
ddennedy May 14, 2026
c870ecd
fix: install qml/QtMultimedia
ddennedy May 14, 2026
32be113
Stop hardcoding the Quick graphics API
ddennedy May 14, 2026
fc5d347
add Settings > Drawing Method > Vulkan on Linux
ddennedy May 14, 2026
3353622
fix: clear video frame buffer on sink set to prevent distorted frames
ddennedy May 15, 2026
10ea198
Move External Menu to Player menu
ddennedy May 15, 2026
dc7b921
add smtpe2048 PQ HDR
ddennedy May 16, 2026
1b6ecb6
Fix Preview Window increases its size on start
ddennedy May 16, 2026
23c19b8
Implement HDR display settings with user-configurable peak brightness…
ddennedy May 16, 2026
76a906f
Add HDR transfer and metadata to Export
ddennedy May 16, 2026
67172a7
clang-format
ddennedy May 16, 2026
9b755dc
Fix open/close preview window restarts playback
ddennedy May 16, 2026
578b3dd
fix some crashes in GPU processing mode
ddennedy May 16, 2026
143923c
Refactor HDR preview action handling into a separate slot
ddennedy May 16, 2026
0585268
Right align labels in HDR Metadata dialog
ddennedy May 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ find_package(Qt6 6.4 REQUIRED
Widgets
Xml
)
if(NOT APPLE)
find_package(Qt6 6.4 REQUIRED GuiPrivate)
endif()
if(UNIX AND NOT APPLE)
find_package(Qt6 6.4 REQUIRED COMPONENTS DBus)
# X11 for WindowPicker (Linux/X11)
Expand All @@ -66,6 +69,9 @@ endif()
add_subdirectory(CuteLogger)
add_subdirectory(src)
add_subdirectory(translations)
if(UNIX AND NOT APPLE)
add_subdirectory(MinimalMediaBackend)
endif()

feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

Expand Down
19 changes: 19 additions & 0 deletions MinimalMediaBackend/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.12...3.31)

project(MinimalMediaBackend)

find_package(Qt6 REQUIRED COMPONENTS Core Multimedia)
find_package(Qt6MultimediaPrivate REQUIRED)

qt_add_plugin(minimalmediaplugin
CLASS_NAME MinimalMediaPlugin
PLUGIN_TYPE multimedia
OUTPUT_TARGETS minimalmediaplugin_targets
minimalmediaplugin.cpp
)

target_link_libraries(minimalmediaplugin PRIVATE
Qt6::Core
Qt6::Multimedia
Qt6::MultimediaPrivate
)
76 changes: 76 additions & 0 deletions MinimalMediaBackend/minimalmediaplugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2026 Meltytech, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <private/qplatformmediaplugin_p.h>
#include <private/qplatformmediaintegration_p.h>
#include <private/qplatformvideosink_p.h>

QT_BEGIN_NAMESPACE

// Minimal QPlatformVideoSink — the base class does all the work
class MinimalVideoSink : public QPlatformVideoSink
{
Q_OBJECT
public:
explicit MinimalVideoSink(QVideoSink *sink)
: QPlatformVideoSink(sink)
{}
};

// Minimal integration — only creates video sinks
class MinimalMediaIntegration : public QPlatformMediaIntegration
{
public:
MinimalMediaIntegration()
: QPlatformMediaIntegration(QLatin1String("minimal"))
{}

#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
q23::expected<QPlatformVideoSink *, QString> createVideoSink(QVideoSink *sink) override
{
return new MinimalVideoSink(sink);
}
#else
QMaybe<QPlatformVideoSink *> createVideoSink(QVideoSink *sink) override
{
return new MinimalVideoSink(sink);
}
#endif
};

// Plugin entry point
class MinimalMediaPlugin : public QPlatformMediaPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformMediaPlugin_iid FILE "minimalmediaplugin.json")

public:
MinimalMediaPlugin(QObject *parent = nullptr)
: QPlatformMediaPlugin(parent)
{}

QPlatformMediaIntegration *create(const QString &key) override
{
if (key == QLatin1String("minimal"))
return new MinimalMediaIntegration;
return nullptr;
}
};

QT_END_NAMESPACE

#include "minimalmediaplugin.moc"
3 changes: 3 additions & 0 deletions MinimalMediaBackend/minimalmediaplugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"Keys": ["minimal"]
}
4 changes: 2 additions & 2 deletions scripts/build-shotcut-msys2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1240,7 +1240,7 @@ function deploy

log Copying some libs from Qt
if [ "$DEBUG_BUILD" != "1" -o "$SDK" = "1" ]; then
cmd cp -p "$QTDIR"/bin/Qt6{Charts,Concurrent,Core,Core5Compat,Gui,Multimedia,Network,OpenGL,OpenGLWidgets,Qml,QmlMeta,QmlModels,QmlWorkerScript,Quick,QuickControls2*,QuickDialogs2,QuickDialogs2QuickImpl,QuickDialogs2Utils,QuickLayouts,QuickTemplates2,QuickWidgets,Sql,Svg,SvgWidgets,UiTools,WebSockets,Widgets,Xml}.dll .
cmd cp -p "$QTDIR"/bin/Qt6{Charts,Concurrent,Core,Core5Compat,Gui,Multimedia,MultimediaQuick,Network,OpenGL,OpenGLWidgets,Qml,QmlMeta,QmlModels,QmlWorkerScript,Quick,QuickControls2*,QuickDialogs2,QuickDialogs2QuickImpl,QuickDialogs2Utils,QuickLayouts,QuickShapes,QuickTemplates2,QuickWidgets,Sql,Svg,SvgWidgets,UiTools,WebSockets,Widgets,Xml}.dll .
fi

if [ "$ENABLE_GLAXNIMATE" = "1" ]; then
Expand Down Expand Up @@ -1293,7 +1293,7 @@ function deploy
done
done
cmd mkdir -p lib/qml
cmd cp -pr "$QT_SHARE_DIR"/qml/{Qt,QtCore,QtQml,QtQuick} lib/qml
cmd cp -pr "$QT_SHARE_DIR"/qml/{Qt,QtCore,QtMultimedia,QtQml,QtQuick} lib/qml
cmd cp -pr "$QT_SHARE_DIR"/translations/qt_*.qm share/translations
cmd cp -pr "$QT_SHARE_DIR"/translations/qtbase_*.qm share/translations

Expand Down
8 changes: 5 additions & 3 deletions scripts/build-shotcut.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1202,13 +1202,15 @@ function install_shotcut_linux {
cmd install -p -c COPYING "$FINAL_INSTALL_DIR"
cmd install -p -c "$QTDIR"/translations/qt_*.qm "$FINAL_INSTALL_DIR"/share/shotcut/translations
cmd install -p -c "$QTDIR"/translations/qtbase_*.qm "$FINAL_INSTALL_DIR"/share/shotcut/translations
cmd install -p -c "$QTDIR"/lib/libQt6{Charts,Concurrent,Core,Core5Compat,DBus,Gui,LabsFolderListModel,Multimedia,Network,OpenGL,OpenGLWidgets,Qml,QmlMeta,QmlModels,QmlWorkerScript,Quick,QuickControls2*,QuickDialogs2,QuickDialogs2QuickImpl,QuickDialogs2Utils,QuickLayouts,QuickTemplates2,QuickWidgets,Sql,Svg,SvgWidgets,UiTools,WaylandClient,WaylandEglClientHwIntegration,WebSockets,Widgets,Xml,X11Extras,XcbQpa}.so.6 "$FINAL_INSTALL_DIR"/lib
cmd install -p -c "$QTDIR"/lib/libQt6{Charts,Concurrent,Core,Core5Compat,DBus,Gui,LabsFolderListModel,Multimedia,MultimediaQuick,Network,OpenGL,OpenGLWidgets,Qml,QmlMeta,QmlModels,QmlWorkerScript,Quick,QuickControls2*,QuickDialogs2,QuickDialogs2QuickImpl,QuickDialogs2Utils,QuickLayouts,QuickShapes,QuickTemplates2,QuickWidgets,Sql,Svg,SvgWidgets,UiTools,WaylandClient,WaylandEglClientHwIntegration,WebSockets,Widgets,Xml,X11Extras,XcbQpa}.so.6 "$FINAL_INSTALL_DIR"/lib
cmd install -p -c "$QTDIR"/lib/lib{icudata,icui18n,icuuc}.so* "$FINAL_INSTALL_DIR"/lib
cmd install -d "$FINAL_INSTALL_DIR"/lib/qt6/sqldrivers
cmd cp -a "$QTDIR"/plugins/{egldeviceintegrations,generic,iconengines,imageformats,multimedia,platforminputcontexts,platforms,platformthemes,tls,wayland-decoration-client,wayland-graphics-integration-client,wayland-shell-integration,xcbglintegrations} "$FINAL_INSTALL_DIR"/lib/qt6
cmd cp -p "$QTDIR"/plugins/sqldrivers/libqsqlite.so "$FINAL_INSTALL_DIR"/lib/qt6/sqldrivers
cmd install -d "$FINAL_INSTALL_DIR"/lib/qml
cmd cp -a "$QTDIR"/qml/{Qt,QtCore,QtQml,QtQuick} "$FINAL_INSTALL_DIR"/lib/qml
cmd cp -a "$QTDIR"/qml/{Qt,QtCore,QtMultimedia,QtQml,QtQuick} "$FINAL_INSTALL_DIR"/lib/qml
cmd install -d "$FINAL_INSTALL_DIR"/lib/qt6/multimedia
cmd cp -p MinimalMediaBackend/libminimalmediaplugin.so "$FINAL_INSTALL_DIR"/lib/qt6/multimedia
}

function build_vmaf_darwin {
Expand Down Expand Up @@ -1952,7 +1954,7 @@ function deploy_mac
# Qt QML modules
log Copying Qt QML modules
cmd mkdir -p Resources/qml 2>/dev/null
cmd cp -a "$QTDIR"/qml/{Qt,QtCore,QtQml,QtQuick} Resources/qml
cmd cp -a "$QTDIR"/qml/{Qt,QtCore,QtMultimedia,QtQml,QtQuick} Resources/qml
for lib in $(find Resources -name '*.dylib'); do
fixlibs "$lib"
done
Expand Down
27 changes: 20 additions & 7 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ add_executable(shotcut WIN32 MACOSX_BUNDLE
transportcontrol.h
util.cpp util.h
videowidget.cpp videowidget.h
hdrpreviewwindow.cpp hdrpreviewwindow.h
widgets/alsawidget.cpp widgets/alsawidget.h
widgets/alsawidget.ui
widgets/audiometerwidget.cpp widgets/audiometerwidget.h
Expand Down Expand Up @@ -266,12 +267,29 @@ add_custom_target(OTHER_FILES
../scripts/staple.sh
)

# Compile HDR gain shader (used by HdrPreview.qml ShaderEffect)
find_program(QSB_EXECUTABLE qsb HINTS
"${Qt6_DIR}/../../../bin" "${Qt6Core_DIR}/../../../bin")
if(QSB_EXECUTABLE)
set(HDR_GAIN_FRAG ${CMAKE_CURRENT_SOURCE_DIR}/qml/views/hdr_gain.frag)
set(HDR_GAIN_QSB ${CMAKE_CURRENT_SOURCE_DIR}/qml/views/hdr_gain.frag.qsb)
add_custom_command(
OUTPUT ${HDR_GAIN_QSB}
COMMAND ${QSB_EXECUTABLE} --glsl "100 es,120,150" --hlsl 50 --msl 12 -o ${HDR_GAIN_QSB} ${HDR_GAIN_FRAG}
DEPENDS ${HDR_GAIN_FRAG}
COMMENT "Compiling HDR gain shader"
)
add_custom_target(hdr_shaders ALL DEPENDS ${HDR_GAIN_QSB})
add_dependencies(shotcut hdr_shaders)
endif()

target_link_libraries(shotcut
PRIVATE
CuteLogger
PkgConfig::mlt++
PkgConfig::FFTW
Qt6::Charts
Qt6::GuiPrivate
Qt6::Multimedia
Qt6::Network
Qt6::OpenGL
Expand Down Expand Up @@ -310,9 +328,7 @@ if(WIN32)

# Windows integration features
target_sources(shotcut PRIVATE windowstools.cpp windowstools.h)
target_sources(shotcut PRIVATE widgets/d3dvideowidget.h widgets/d3dvideowidget.cpp)
target_sources(shotcut PRIVATE widgets/openglvideowidget.h widgets/openglvideowidget.cpp)
target_link_libraries(shotcut PRIVATE d3d11 d3dcompiler ole32)
target_link_libraries(shotcut PRIVATE ole32)

# Runtime exception handler for debug only
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")
Expand All @@ -331,13 +347,10 @@ if(WIN32)
install(DIRECTORY qml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/shotcut/)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/filter-sets DESTINATION ${CMAKE_INSTALL_PREFIX}/share/shotcut/)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/voices DESTINATION ${CMAKE_INSTALL_PREFIX}/share/shotcut/)
else()
target_sources(shotcut PRIVATE widgets/openglvideowidget.h widgets/openglvideowidget.cpp)
endif()

if(APPLE)
target_sources(shotcut PRIVATE macos.mm macos.h
widgets/metalvideowidget.h widgets/metalvideowidget.mm)
target_sources(shotcut PRIVATE macos.mm macos.h)
set_target_properties(shotcut PROPERTIES
OUTPUT_NAME "Shotcut"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/packaging/macos/Info.plist.in)
Expand Down
36 changes: 35 additions & 1 deletion src/dialogs/customprofiledialog.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2025 Meltytech, LLC
* Copyright (c) 2013-2026 Meltytech, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -49,6 +49,18 @@ CustomProfileDialog::CustomProfileDialog(QWidget *parent)
ui->colorspaceCombo->setCurrentIndex(1);
break;
}
// Initialize Dynamic range: enabled only for BT.2020, default from profile/producer
if (MLT.profile().colorspace() != 2020) {
ui->dynamicRangeCombo->setEnabled(false);
} else {
const QString trc = MLT.colorTrc();
if (trc == QLatin1String("arib-std-b67"))
ui->dynamicRangeCombo->setCurrentIndex(1);
else if (trc == QLatin1String("smpte2084"))
ui->dynamicRangeCombo->setCurrentIndex(2);
else
ui->dynamicRangeCombo->setCurrentIndex(0);
}
}

CustomProfileDialog::~CustomProfileDialog()
Expand Down Expand Up @@ -92,6 +104,18 @@ void CustomProfileDialog::on_buttonBox_accepted()
}
MLT.updatePreviewProfile();
MLT.setPreviewScale(Settings.playerPreviewScale());
// Set color_trc based on dynamic range selection
switch (ui->dynamicRangeCombo->currentIndex()) {
case 1: // HLG HDR
MLT.setColorTrc(QStringLiteral("arib-std-b67"));
break;
case 2: // PQ HDR
MLT.setColorTrc(QStringLiteral("smpte2084"));
break;
default: // SDR
MLT.setColorTrc(QString());
break;
}

// Save it to a file
if (!ui->nameEdit->text().isEmpty()) {
Expand All @@ -114,6 +138,8 @@ void CustomProfileDialog::on_buttonBox_accepted()
p.set("colorspace", MLT.profile().colorspace());
p.set("frame_rate_num", MLT.profile().frame_rate_num());
p.set("frame_rate_den", MLT.profile().frame_rate_den());
if (!MLT.colorTrc().isEmpty())
p.set("color_trc", MLT.colorTrc().toLatin1().constData());
p.save(dir.filePath(profileName()).toUtf8().constData());
}
}
Expand Down Expand Up @@ -169,3 +195,11 @@ void CustomProfileDialog::on_aspectRatioComboBox_textActivated(const QString &ar
ui->aspectNumSpinner->setValue(parts[0].toInt());
ui->aspectDenSpinner->setValue(parts[1].toInt());
}

void CustomProfileDialog::on_colorspaceCombo_currentIndexChanged(int index)
{
const bool isBt2020 = (index == 2);
ui->dynamicRangeCombo->setEnabled(isBt2020);
if (!isBt2020)
ui->dynamicRangeCombo->setCurrentIndex(0); // reset to SDR
}
4 changes: 3 additions & 1 deletion src/dialogs/customprofiledialog.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2023 Meltytech, LLC
* Copyright (c) 2013-2026 Meltytech, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -48,6 +48,8 @@ private slots:

void on_aspectRatioComboBox_textActivated(const QString &arg1);

void on_colorspaceCombo_currentIndexChanged(int index);

private:
Ui::CustomProfileDialog *ui;
double m_fps;
Expand Down
51 changes: 50 additions & 1 deletion src/dialogs/customprofiledialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>496</width>
<height>376</height>
<height>410</height>
</rect>
</property>
<property name="windowTitle">
Expand Down Expand Up @@ -459,6 +459,55 @@
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="dynamicRangeLabel">
<property name="text">
<string>Dynamic range</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>dynamicRangeCombo</cstring>
</property>
</widget>
</item>
<item row="8" column="1" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QComboBox" name="dynamicRangeCombo">
<item>
<property name="text">
<string notr="true">SDR</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">HLG HDR</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">PQ HDR</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="10" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
Expand Down
Loading
Loading