1212
Add support for experimental add-on filters by bmatherly · Pull Request #1813 · mltframework/shotcut · GitHub
Skip to content

Add support for experimental add-on filters#1813

Open
bmatherly wants to merge 5 commits intomasterfrom
autogen_filters
Open

Add support for experimental add-on filters#1813
bmatherly wants to merge 5 commits intomasterfrom
autogen_filters

Conversation

@bmatherly
Copy link
Copy Markdown
Member

This includes a new selection dialog and generated UIs
The --experimental option is required to expose the selection
--experimental is only available when Shotcut is compiled for debug

When --experimental is enabled, the filter selection menu adds a hamburger menu before the search bar with a single action called "Manage Add-on Filters"
image

This action opens a new Add-on Filter selection dialog which lists ALL available filters in MLT:
image

The user can select and de-select MLT filters to be added to the main filter selection as Add-on Filters. After the dialog is closed, the main filter selection is updated with the selected (or de-selected) filters
image

When the user selects an Add-on filter that has been added to a clip, the UI for that add-on is auto-generated and cached in a temporary folder.
image

The help button (?) opens a non-modal dialog with a detailed view of all the properties for that add-on filter
image

I find this feature useful for exploring filters - especially the host of OpenFx filters. This has also exposed some opportunities for improving metadata for some MLT filters - which I will submit in different PRs.

Review comments are welcome.

I recommend that we wait until after the April release before we consider merging this.

This includes a new selection dialog and generated UIs
The --experimental option is required to expose the selection
--experimental is ony available when Shotcut is compiles for debug
Comment thread src/controllers/filtercontroller.cpp Outdated
bool FilterController::ensureAddOnTempDir()
{
if (!m_addOnTempDir.isValid()) {
m_addOnTempDir = QTemporaryDir(QDir::tempPath() + "/shotcut-addon-XXXXXX");
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new Temporary directory is created for every Shotcut instance. If someone opens/closes Shotcut a lot, they can accumulate. But this handles the case of regenerating the UI for software updates or multiple versions installed at the same time. It also makes development easy since I don't have to delete the generated files every time I make a change to the code.

QmlMetadata *meta = m_attachedModel.getMetadata(m_currentFilterIndex);
QmlFilter *filter = nullptr;
if (meta) {
if (meta->objectName().startsWith(QStringLiteral("addOn.")) && !ensureAddOnFilterQml(meta)) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI QML for an add-on filter is only generated when absolutely needed - when a user has selected an add-on filter in the UI. If present, the cached version is used. Else, it is generated. So, in many cases, the temporary directory will never be created if the user opens shotcut, but never uses an add-on filter.

Comment thread src/qml/views/filter/FilterMenu.qml Outdated
Shotcut.Button {
id: addOnMenuButton

visible: enableAddOns
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This button only appears when --experimental is passed to Shotcut.

Comment thread src/main.cpp
QCommandLineOption gpuOption("gpu",
QCoreApplication::translate("main", "Use GPU processing."));
parser.addOption(gpuOption);
#ifdef QT_DEBUG
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The --experimental option is only available when Shotcut is compiled for debug.

Comment thread src/mltcontroller.cpp
if (experimental)
::qputenv("MLT_REPOSITORY_DENY", "libmltqt:libmltglaxnimate");
else
::qputenv("MLT_REPOSITORY_DENY", "libmltqt:libmltglaxnimate:libmltopenfx");
Copy link
Copy Markdown
Member Author

@bmatherly bmatherly Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The experimental option also enables openfx to be loaded at startup.

Comment thread src/settings.cpp
return settings.value("filter/addOnServices").toStringList();
}

void ShotcutSettings::setAddOnFilterServices(const QStringList &services)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the user selects add-on services in the dialog, they are saved in the settings so they can be reloaded very time shotcut starts (only with --experimental)

bmatherly

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an experimental add-on filter workflow (debug builds only) that lets users opt-in to exposing arbitrary MLT filter services in Shotcut’s filter menu, with auto-generated parameter UIs and a metadata/help viewer.

Changes:

  • Add --experimental (debug-only) flag and wire it into MLT repository deny-list behavior (e.g., OpenFX availability).
  • Add add-on filter management UI: hamburger menu entry in the filter menu + a new “Manage Add-on Filters” dialog backed by a new AddOnServiceModel persisted via settings.
  • Generate and cache QML UIs for enabled add-on filter services on demand, plus a non-modal metadata/help viewer.

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/settings.h Adds settings API for persisted add-on filter service list.
src/settings.cpp Implements persisted add-on filter service list getters/setters.
src/qmltypes/qmlutilities.cpp Registers new QML type used for the add-on menu popup.
src/qmltypes/qmlfiltermenu.h Declares C++ QML-facing menu helper for add-on actions.
src/qmltypes/qmlfiltermenu.cpp Implements popup menu that opens the add-on manager dialog.
src/qmltypes/qmlapplication.h Exposes showAddOnFiltersDialog() to QML/C++ menu helper.
src/qmltypes/qmlapplication.cpp Implements dialog launch for add-on filter management.
src/qml/views/filter/filterview.qml Plumbs generated-UI help signal up to the dock for display.
src/qml/views/filter/FilterMenu.qml Adds the experimental hamburger menu button.
src/models/addonservicemodel.h New model for enumerating MLT filter services and enabled selections.
src/models/addonservicemodel.cpp Implements MLT filter discovery + persistence of enabled add-ons.
src/mltcontroller.cpp Adjusts MLT_REPOSITORY_DENY based on experimental flag.
src/mainwindow.cpp Threads add-on service model into FiltersDock construction.
src/main.cpp Adds debug-only --experimental option and sets app property.
src/docks/filtersdock.h Adds support for showing non-modal add-on metadata help dialog.
src/docks/filtersdock.cpp Wires QML signal to a QTextBrowser help dialog; sets enableAddOns context property.
src/dialogs/addonfiltersdialog.h Declares add-on filter management dialog.
src/dialogs/addonfiltersdialog.cpp Implements searchable, checkable list of all MLT filter services.
src/controllers/filtercontroller.h Adds add-on UI generation/caching members and add-on metadata loading hooks.
src/controllers/filtercontroller.cpp Implements add-on metadata insertion/removal and on-demand generated UI caching.
src/controllers/addonqmlgenerator.h Declares generator for add-on filter parameter UI QML.
src/controllers/addonqmlgenerator.cpp Generates parameter UI QML + metadata help text for add-on services.
src/controllers/addonmetadataparser.h Declares parser to normalize MLT metadata into descriptors.
src/controllers/addonmetadataparser.cpp Implements metadata parsing into generator-friendly descriptors.
src/CMakeLists.txt Adds new sources (model, dialogs, generator, parser, QML type helper) to build.
Comments suppressed due to low confidence (1)

src/docks/filtersdock.cpp:53

  • The addOnServiceModel parameter is not used in this constructor, which can trigger unused-parameter warnings (and it’s unclear why it is being threaded through MainWindow). Either use it (e.g., expose it to QML via a context property) or remove it from the constructor signature/call sites; if it must remain, mark it with Q_UNUSED(addOnServiceModel) to make the intent explicit.
FiltersDock::FiltersDock(MetadataModel *metadataModel,
                         AddOnServiceModel *addOnServiceModel,
                         AttachedFiltersModel *attachedModel,
                         MotionTrackerModel *motionTrackerModel,
                         SubtitlesModel *subtitlesModel,
                         QWidget *parent)

Comment thread src/controllers/filtercontroller.cpp Outdated
Comment thread src/controllers/filtercontroller.cpp Outdated
Comment thread src/dialogs/addonfiltersdialog.cpp
Comment thread src/controllers/addonqmlgenerator.cpp
Comment thread src/controllers/addonqmlgenerator.cpp Outdated
Comment thread src/controllers/addonmetadataparser.cpp
Comment thread src/controllers/addonmetadataparser.cpp Outdated
Comment thread src/qmltypes/qmlfiltermenu.h Outdated
@ddennedy
Copy link
Copy Markdown
Member

Thank you; it is nice to have. The first filter I tried avfilter.rotate crashed (Windows). Not looked into it yet but a reminder this is full of landmines. I think we should filter out the ones that already have an installed QML if not too much trouble.

Comment thread src/dialogs/addonfiltersdialog.cpp
Comment thread src/qml/views/filter/FilterMenu.qml Outdated
@ddennedy
Copy link
Copy Markdown
Member

avfilter.rotate crashed

I found that the avformat module was incorrect about metadata and pushed a change. Now, it does not crash.

@bmatherly
Copy link
Copy Markdown
Member Author

I think we should filter out the ones that already have an installed QML if not too much trouble.

I am on the fence about this. On the one hand, it would reduce redundancy. On the other hand, filters can be exposed/represented in many ways. Maybe we are exposing a service through our curated UI, but not exposing some of the parameters or doing it in a limited way. It might be good if the experimenter can work with the raw filter even if we have exposed it through our supported filters.

As a reference, the following services are used in multiple Shotcut filters:

  • autofade (2)
  • brightness (4)
  • channelcopy (2)
  • frei0r.alpha0ps (2)
  • frei0r.IIRblur (3)
  • ladspa.1204 (2)
  • lift_gamma_gain (2)
  • mask_start (5)
  • movit.opacity (2)
  • panner (2)
  • qtcrop (2)
  • qtext (2)
  • volume (4)

As a variation on this comment, for each add-on filter, I could add a note somewhere to indicate which supported filters are using that MLT filter. Perhaps as a column in the manager dialog. Or maybe a tool tip in the generated UI.

@ddennedy
Copy link
Copy Markdown
Member

I am on the fence about this.

OK I see your point.

bmatherly and others added 2 commits April 14, 2026 21:41
Use LineEditClear
Replace hamburger menu with "configure" button
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants