Skip to content

Commit 11c2031

Browse files
bmatherlyCopilotddennedy
authored
Add processing modes (#1729)
* Add processing modes Remove the previous GPU Effects option and replace it with multiple processing modes that enable higher bit depth and linear color processing. * Brightness is 10-bit now * Clean up if statement. Reduce property lookups Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Dan Dennedy <dan@dennedy.org> * Change GPU mode to linear * Improve preview image format for GPU and/or DeckLink * Use rgba64 with Linear10GpuCpu without HLG Now in Export, when `color_trc` is arib-std-b67 (HLG) do not add mlt_color_trc=linear. Also, let user override `mlt_image_format` or `mlt_color_trc`. * Fix HLG can be on/used with DeckLink turned off * Fix serialized GPU processing mode * Fix support for latest releases of MLT * A little rewording of message dialogs But this will change again when project conversion is added. * Fix adding processing modes to QActionGroup Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Refactor Settings * Fix processing mode after decline restart --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Dan Dennedy <dan@dennedy.org>
1 parent af2f68d commit 11c2031

14 files changed

Lines changed: 344 additions & 113 deletions

File tree

src/docks/encodedock.cpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -298,15 +298,12 @@ void EncodeDock::loadPresetFromProperties(Mlt::Properties &preset)
298298
ui->fpsSpinner->setValue(preset.get_double("frame_rate_num")
299299
/ preset.get_double("frame_rate_den"));
300300
} else if (name == "pix_fmt") {
301-
// Handle 10 bit encoding with hardware encoder and GPU Effects
301+
// Handle 10-bit encoding
302302
if (value.contains("p10le")) {
303-
if (Settings.playerGPU()) {
304-
if (value == "yuva444p10le") {
305-
other.append("mlt_image_format=rgba");
306-
} else {
307-
other.append("mlt_image_format=yuv444p10");
308-
}
309-
} else if (!other.contains("mlt_image_format=rgb")) {
303+
// Let 8-bit processing modes utilize full range RGB
304+
const auto pm = Settings.processingMode();
305+
if ((pm == ShotcutSettings::Native8Cpu || pm == ShotcutSettings::Linear8Cpu)
306+
&& !other.contains("mlt_image_format=rgb")) {
310307
other.append("mlt_image_format=rgb");
311308
}
312309
// Hardware encoder
@@ -1146,9 +1143,29 @@ void EncodeDock::collectProperties(QDomElement &node, int realtime)
11461143
{
11471144
Mlt::Properties *p = collectProperties(realtime);
11481145
if (p && p->is_valid()) {
1149-
for (int i = 0; i < p->count(); i++)
1146+
for (int i = 0; i < p->count(); i++) {
11501147
if (p->get_name(i) && strcmp(p->get_name(i), ""))
11511148
node.setAttribute(p->get_name(i), p->get(i));
1149+
}
1150+
1151+
const auto processingMode = Settings.processingMode();
1152+
if (processingMode == ShotcutSettings::Native10Cpu
1153+
|| processingMode == ShotcutSettings::Linear10Cpu
1154+
|| processingMode == ShotcutSettings::Linear10GpuCpu) {
1155+
if (!p->property_exists("mlt_image_format")) {
1156+
if (::qstrcmp(p->get("color_trc"), "arib-std-b67"))
1157+
node.setAttribute("mlt_image_format", "rgba64");
1158+
else
1159+
node.setAttribute("mlt_image_format", "yuv444p10");
1160+
}
1161+
}
1162+
if (processingMode == ShotcutSettings::Linear8Cpu
1163+
|| processingMode == ShotcutSettings::Linear10Cpu
1164+
|| (processingMode == ShotcutSettings::Linear10GpuCpu
1165+
&& ::qstrcmp(p->get("color_trc"), "arib-std-b67"))) {
1166+
if (!p->property_exists("mlt_color_trc"))
1167+
node.setAttribute("mlt_color_trc", "linear");
1168+
}
11521169
}
11531170
delete p;
11541171
}

src/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ class Application : public QApplication
237237
ShotcutSettings::setAppDataForSession(appDirArg);
238238
}
239239
if (parser.isSet(gpuOption))
240-
Settings.setPlayerGPU(true);
240+
Settings.setProcessingMode(ShotcutSettings::Linear10GpuCpu);
241241
if (!parser.positionalArguments().isEmpty())
242242
resourceArg = parser.positionalArguments();
243243

src/mainwindow.cpp

Lines changed: 150 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@ void MainWindow::setupAndConnectDocks()
682682
m_filterController->motionTrackerModel(),
683683
&MotionTrackerModel::removeFromService);
684684
connect(this, SIGNAL(audioChannelsChanged()), m_filterController, SLOT(setProducer()));
685+
connect(this, SIGNAL(processingModeChanged()), m_filterController, SLOT(setProducer()));
685686
connect(m_timelineDock,
686687
&TimelineDock::trimStarted,
687688
m_filterController,
@@ -1042,7 +1043,97 @@ MainWindow::~MainWindow()
10421043
void MainWindow::setupSettingsMenu()
10431044
{
10441045
LOG_DEBUG() << "begin";
1046+
1047+
Mlt::Filter filter(MLT.profile(), "color_transform");
1048+
if (!filter.is_valid()) {
1049+
ui->actionLinear8bitCpu->setVisible(false);
1050+
#if LIBMLT_VERSION_INT < ((7 << 16) + (34 << 8))
1051+
ui->actionNative10bitCpu->setVisible(false);
1052+
#endif
1053+
ui->actionLinear10bitCpu->setVisible(false);
1054+
}
10451055
QActionGroup *group = new QActionGroup(this);
1056+
ui->actionNative8bitCpu->setData(ShotcutSettings::Native8Cpu);
1057+
if (ui->actionLinear8bitCpu->isVisible())
1058+
ui->actionLinear8bitCpu->setData(ShotcutSettings::Linear8Cpu);
1059+
if (ui->actionNative10bitCpu->isVisible())
1060+
ui->actionNative10bitCpu->setData(ShotcutSettings::Native10Cpu);
1061+
if (ui->actionLinear10bitCpu->isVisible())
1062+
ui->actionLinear10bitCpu->setData(ShotcutSettings::Linear10Cpu);
1063+
ui->actionLinear10bitGpuCpu->setData(ShotcutSettings::Linear10GpuCpu);
1064+
if (ui->actionNative8bitCpu->isVisible())
1065+
group->addAction(ui->actionNative8bitCpu);
1066+
if (ui->actionLinear8bitCpu->isVisible())
1067+
group->addAction(ui->actionLinear8bitCpu);
1068+
if (ui->actionNative10bitCpu->isVisible())
1069+
group->addAction(ui->actionNative10bitCpu);
1070+
if (ui->actionLinear10bitCpu->isVisible())
1071+
group->addAction(ui->actionLinear10bitCpu);
1072+
if (ui->actionLinear10bitGpuCpu->isVisible())
1073+
group->addAction(ui->actionLinear10bitGpuCpu);
1074+
for (auto a : group->actions()) {
1075+
const auto mode = (ShotcutSettings::ProcessingMode) a->data().toInt();
1076+
if (Settings.processingMode() == mode) {
1077+
a->setChecked(true);
1078+
setProcessingMode(mode);
1079+
break;
1080+
}
1081+
}
1082+
connect(group, &QActionGroup::triggered, this, [&](QAction *action) {
1083+
const auto oldMode = Settings.processingMode();
1084+
const auto newMode = (ShotcutSettings::ProcessingMode) action->data().toInt();
1085+
if (oldMode == newMode)
1086+
return;
1087+
LOG_INFO() << "Processing Mode" << oldMode << "->" << newMode;
1088+
if (newMode == ShotcutSettings::Linear10GpuCpu) {
1089+
QMessageBox
1090+
dialog(QMessageBox::Warning,
1091+
qApp->applicationName(),
1092+
tr("GPU processing is experimental and does not work on all computers. "
1093+
"Plan to do some testing after turning this on.\n"
1094+
"At this time, a project created with GPU processing cannot be "
1095+
"converted to a CPU-only project later.\n"
1096+
"Do you want to enable GPU processing and restart Shotcut?"),
1097+
QMessageBox::No | QMessageBox::Yes,
1098+
this);
1099+
dialog.setDefaultButton(QMessageBox::Yes);
1100+
dialog.setEscapeButton(QMessageBox::No);
1101+
dialog.setWindowModality(QmlApplication::dialogModality());
1102+
dialog.adjustSize();
1103+
if (dialog.exec() == QMessageBox::Yes) {
1104+
Settings.setProcessingMode(newMode);
1105+
m_exitCode = EXIT_RESTART;
1106+
QApplication::closeAllWindows();
1107+
}
1108+
for (auto a : action->actionGroup()->actions()) {
1109+
if (oldMode == a->data().toInt()) {
1110+
a->setChecked(true);
1111+
break;
1112+
}
1113+
}
1114+
} else if (oldMode == ShotcutSettings::Linear10GpuCpu) {
1115+
QMessageBox dialog(QMessageBox::Information,
1116+
qApp->applicationName(),
1117+
tr("Shotcut must restart to disable GPU processing.\n"
1118+
"Disable GPU processing and restart?"),
1119+
QMessageBox::No | QMessageBox::Yes,
1120+
this);
1121+
dialog.setDefaultButton(QMessageBox::Yes);
1122+
dialog.setEscapeButton(QMessageBox::No);
1123+
dialog.setWindowModality(QmlApplication::dialogModality());
1124+
dialog.adjustSize();
1125+
if (dialog.exec() == QMessageBox::Yes) {
1126+
Settings.setProcessingMode(newMode);
1127+
m_exitCode = EXIT_RESTART;
1128+
QApplication::closeAllWindows();
1129+
}
1130+
ui->actionLinear10bitGpuCpu->setChecked(true);
1131+
} else {
1132+
setProcessingMode((ShotcutSettings::ProcessingMode) action->data().toInt());
1133+
}
1134+
});
1135+
1136+
group = new QActionGroup(this);
10461137
group->addAction(ui->actionChannels1);
10471138
group->addAction(ui->actionChannels2);
10481139
group->addAction(ui->actionChannels4);
@@ -1617,32 +1708,31 @@ bool MainWindow::isCompatibleWithGpuMode(MltXmlChecker &checker)
16171708
{
16181709
if (checker.needsGPU() && !Settings.playerGPU()) {
16191710
LOG_INFO() << "file uses GPU but GPU not enabled";
1620-
QMessageBox
1621-
dialog(QMessageBox::Warning,
1622-
qApp->applicationName(),
1623-
tr("The file you opened uses GPU effects, but GPU effects are not enabled."),
1624-
QMessageBox::Ok,
1625-
this);
1711+
QMessageBox dialog(QMessageBox::Warning,
1712+
qApp->applicationName(),
1713+
tr("The file you opened uses GPU processing, which is not enabled."),
1714+
QMessageBox::Ok,
1715+
this);
16261716
dialog.setWindowModality(QmlApplication::dialogModality());
16271717
dialog.setDefaultButton(QMessageBox::Ok);
16281718
dialog.setEscapeButton(QMessageBox::Ok);
16291719
dialog.exec();
16301720
return false;
16311721
} else if (checker.needsCPU() && Settings.playerGPU()) {
1632-
LOG_INFO() << "file uses GPU incompatible filters but GPU is enabled";
1633-
QMessageBox dialog(QMessageBox::Question,
1634-
qApp->applicationName(),
1635-
tr("The file you opened uses CPU effects that are incompatible with GPU "
1636-
"effects, but GPU effects are enabled.\n"
1637-
"Do you want to disable GPU effects and restart?"),
1638-
QMessageBox::No | QMessageBox::Yes,
1639-
this);
1722+
LOG_INFO() << "file uses GPU incompatible filters but GPU processing is enabled";
1723+
QMessageBox dialog(
1724+
QMessageBox::Question,
1725+
qApp->applicationName(),
1726+
tr("The file you opened uses CPU effects that are incompatible with GPU processing.\n"
1727+
"Do you want to disable GPU processing and restart?"),
1728+
QMessageBox::No | QMessageBox::Yes,
1729+
this);
16401730
dialog.setWindowModality(QmlApplication::dialogModality());
16411731
dialog.setDefaultButton(QMessageBox::Yes);
16421732
dialog.setEscapeButton(QMessageBox::No);
16431733
int r = dialog.exec();
16441734
if (r == QMessageBox::Yes) {
1645-
ui->actionGPU->setChecked(false);
1735+
Settings.setProcessingMode(ShotcutSettings::Native8Cpu);
16461736
m_exitCode = EXIT_RESTART;
16471737
QApplication::closeAllWindows();
16481738
}
@@ -1847,6 +1937,34 @@ void MainWindow::setAudioChannels(int channels)
18471937
emit audioChannelsChanged();
18481938
}
18491939

1940+
void MainWindow::setProcessingMode(ShotcutSettings::ProcessingMode mode)
1941+
{
1942+
LOG_DEBUG() << mode;
1943+
if (mode != Settings.processingMode()) {
1944+
Settings.setProcessingMode(mode);
1945+
}
1946+
switch (mode) {
1947+
case ShotcutSettings::Native8Cpu:
1948+
ui->actionNative8bitCpu->setChecked(true);
1949+
break;
1950+
case ShotcutSettings::Linear8Cpu:
1951+
ui->actionLinear8bitCpu->setChecked(true);
1952+
break;
1953+
case ShotcutSettings::Native10Cpu:
1954+
ui->actionNative10bitCpu->setChecked(true);
1955+
break;
1956+
case ShotcutSettings::Linear10Cpu:
1957+
ui->actionLinear10bitCpu->setChecked(true);
1958+
break;
1959+
case ShotcutSettings::Linear10GpuCpu:
1960+
ui->actionLinear10bitGpuCpu->setChecked(true);
1961+
break;
1962+
}
1963+
MLT.videoWidget()->setProperty("processing_mode", mode);
1964+
MLT.setProcessingMode(mode);
1965+
emit processingModeChanged();
1966+
}
1967+
18501968
void MainWindow::showSaveError()
18511969
{
18521970
QMessageBox dialog(QMessageBox::Critical,
@@ -2093,6 +2211,9 @@ bool MainWindow::open(QString url, const Mlt::Properties *properties, bool play,
20932211
m_player->setPauseAfterOpen(!play || !MLT.isClip());
20942212

20952213
setAudioChannels(MLT.audioChannels());
2214+
Mlt::Filter filter(MLT.profile(), "color_transform");
2215+
if (filter.is_valid())
2216+
setProcessingMode(MLT.processingMode());
20962217
if (url.endsWith(".mlt") || url.endsWith(".xml")) {
20972218
if (MLT.producer()->get_int(kShotcutProjectFolder)) {
20982219
MLT.setProjectFolder(info.absolutePath());
@@ -2297,8 +2418,6 @@ void MainWindow::readPlayerSettings()
22972418
ui->actionScrubAudio->setChecked(Settings.playerScrubAudio());
22982419
if (ui->actionJack)
22992420
ui->actionJack->setChecked(Settings.playerJACK());
2300-
if (ui->actionGPU)
2301-
ui->actionGPU->setChecked(Settings.playerGPU());
23022421

23032422
QString external = Settings.playerExternal();
23042423
bool ok = false;
@@ -2571,7 +2690,6 @@ void MainWindow::writeSettings()
25712690
if (isFullScreen())
25722691
showNormal();
25732692
#endif
2574-
Settings.setPlayerGPU(ui->actionGPU->isChecked());
25752693
Settings.setWindowGeometry(saveGeometry());
25762694
Settings.setWindowState(saveState());
25772695
Settings.sync();
@@ -4009,13 +4127,13 @@ void MainWindow::on_actionEnterFullScreen_triggered()
40094127

40104128
void MainWindow::onGpuNotSupported()
40114129
{
4012-
Settings.setPlayerGPU(false);
4013-
if (ui->actionGPU) {
4014-
ui->actionGPU->setChecked(false);
4015-
ui->actionGPU->setDisabled(true);
4130+
if (Settings.processingMode() == ShotcutSettings::Linear10GpuCpu) {
4131+
Settings.setProcessingMode(ShotcutSettings::Native8Cpu);
40164132
}
4133+
ui->actionLinear10bitGpuCpu->setChecked(false);
4134+
ui->actionLinear10bitGpuCpu->setDisabled(true);
40174135
LOG_WARNING() << "";
4018-
QMessageBox::critical(this, qApp->applicationName(), tr("GPU effects are not supported"));
4136+
QMessageBox::critical(this, qApp->applicationName(), tr("GPU processing is not supported"));
40194137
}
40204138

40214139
void MainWindow::onShuttle(float x)
@@ -4256,48 +4374,6 @@ void MainWindow::on_actionJack_triggered(bool checked)
42564374
}
42574375
}
42584376

4259-
void MainWindow::on_actionGPU_triggered(bool checked)
4260-
{
4261-
if (checked) {
4262-
QMessageBox dialog(QMessageBox::Warning,
4263-
qApp->applicationName(),
4264-
tr("GPU effects are experimental and do not work good on all computers. "
4265-
"Plan to do some testing after turning this on.\n"
4266-
"At this time, a project created with GPU effects cannot be "
4267-
"converted to a CPU-only project later."
4268-
"\n\n"
4269-
"Do you want to enable GPU effects and restart Shotcut?"),
4270-
QMessageBox::No | QMessageBox::Yes,
4271-
this);
4272-
dialog.setDefaultButton(QMessageBox::Yes);
4273-
dialog.setEscapeButton(QMessageBox::No);
4274-
dialog.setWindowModality(QmlApplication::dialogModality());
4275-
if (dialog.exec() == QMessageBox::Yes) {
4276-
m_exitCode = EXIT_RESTART;
4277-
QApplication::closeAllWindows();
4278-
} else {
4279-
ui->actionGPU->setChecked(false);
4280-
}
4281-
} else {
4282-
QMessageBox dialog(QMessageBox::Information,
4283-
qApp->applicationName(),
4284-
tr("Shotcut must restart to disable GPU effects."
4285-
"\n\n"
4286-
"Disable GPU effects and restart?"),
4287-
QMessageBox::No | QMessageBox::Yes,
4288-
this);
4289-
dialog.setDefaultButton(QMessageBox::Yes);
4290-
dialog.setEscapeButton(QMessageBox::No);
4291-
dialog.setWindowModality(QmlApplication::dialogModality());
4292-
if (dialog.exec() == QMessageBox::Yes) {
4293-
m_exitCode = EXIT_RESTART;
4294-
QApplication::closeAllWindows();
4295-
} else {
4296-
ui->actionGPU->setChecked(true);
4297-
}
4298-
}
4299-
}
4300-
43014377
void MainWindow::onExternalTriggered(QAction *action)
43024378
{
43034379
LOG_DEBUG() << action->data().toString();
@@ -5678,25 +5754,22 @@ void MainWindow::on_actionClearRecentOnExit_toggled(bool arg1)
56785754
void MainWindow::onSceneGraphInitialized()
56795755
{
56805756
if (Settings.playerGPU() && Settings.playerWarnGPU()) {
5681-
QMessageBox dialog(QMessageBox::Warning,
5682-
qApp->applicationName(),
5683-
tr("GPU effects are EXPERIMENTAL, UNSTABLE and UNSUPPORTED! Unsupported "
5684-
"means do not report bugs about it.\n\n"
5685-
"Do you want to disable GPU effects and restart Shotcut?"),
5686-
QMessageBox::No | QMessageBox::Yes,
5687-
this);
5757+
QMessageBox
5758+
dialog(QMessageBox::Warning,
5759+
qApp->applicationName(),
5760+
tr("GPU processing is EXPERIMENTAL, UNSTABLE and UNSUPPORTED! Unsupported "
5761+
"means do not report bugs about it.\n\n"
5762+
"Do you want to disable GPU processing and restart Shotcut?"),
5763+
QMessageBox::No | QMessageBox::Yes,
5764+
this);
56885765
dialog.setDefaultButton(QMessageBox::Yes);
56895766
dialog.setEscapeButton(QMessageBox::No);
56905767
dialog.setWindowModality(QmlApplication::dialogModality());
56915768
if (dialog.exec() == QMessageBox::Yes) {
5692-
ui->actionGPU->setChecked(false);
5769+
Settings.setProcessingMode(ShotcutSettings::Native8Cpu);
56935770
m_exitCode = EXIT_RESTART;
56945771
QApplication::closeAllWindows();
5695-
} else {
5696-
ui->actionGPU->setVisible(true);
56975772
}
5698-
} else {
5699-
ui->actionGPU->setVisible(true);
57005773
}
57015774
auto videoWidget = (Mlt::VideoWidget *) &(MLT);
57025775
videoWidget->setBlankScene();

0 commit comments

Comments
 (0)