Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ebe1cae
Add libplacebo GPU module with render and shader filters
D-Ogi Feb 1, 2026
35e85eb
Fix MinGW build: portable format specifiers, add libplacebo to CI
D-Ogi Feb 2, 2026
394d73c
Fix clang-format violation in save_cache log line
D-Ogi Feb 3, 2026
32f8a47
Reuse GPU textures between chained placebo filters
D-Ogi Feb 4, 2026
d687bdf
Support DYNAMIC shader parameters and base64-encoded shader_text
D-Ogi Feb 4, 2026
cc02961
Fix clang-format-14 violations in placebo module
D-Ogi Feb 5, 2026
11bf94d
Merge branch 'feature/placebo-module' of https://github.com/D-Ogi/mlt…
ddennedy May 6, 2026
3b112bb
add MLT_PLACEBO_CACHE_PATH and replace atext()
ddennedy May 6, 2026
ce99364
Add placebo.convert filter
ddennedy May 6, 2026
1def44b
fix cppcheck and redundant workflow runs
ddennedy May 6, 2026
e80a020
fix ctest on msvc
ddennedy May 6, 2026
626cf8a
docs for placebo private image handling
ddennedy May 6, 2026
9f97a83
Enhance image conversion logic to handle private format cases
ddennedy May 6, 2026
739224f
Fix double-free of src_tex and out-of-bounds in imageconvert
Copilot May 6, 2026
86df189
Apply suggestions from code review
ddennedy May 6, 2026
7cd956a
fix lazy allocation not thread-safe
ddennedy May 6, 2026
9a6e134
fix races in placebo.shader
ddennedy May 6, 2026
f2a9e83
Add permanent failure flag for GPU initialization and fix leak
ddennedy May 6, 2026
8d7260a
Add permanent failure and shutdown flags for GPU management
ddennedy May 6, 2026
34b2717
use "mlt_image_private"
ddennedy May 7, 2026
ef2da1c
add `mlt_frame_prepend_convert_image()`
ddennedy May 7, 2026
50c1f24
Merge branch 'refactor-image-convert' into libplacebo
ddennedy May 7, 2026
6c75bd1
remove placebo.convert filter
ddennedy May 7, 2026
2dcf694
fix cppcheck
ddennedy May 7, 2026
148bfa2
Merge branch 'refactor-image-convert' into libplacebo
ddennedy May 7, 2026
705b3e0
update CMakeLists.txt to require libplacebo version 5.229
ddennedy May 7, 2026
4c74b79
improve placebo.render meta & cleanup
ddennedy May 8, 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
12 changes: 7 additions & 5 deletions .github/workflows/build-distros.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,35 +37,36 @@ jobs:
sed -i 's/^Types: deb/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
DEBIAN_FRONTEND=noninteractive apt-get -qq update
DEBIAN_FRONTEND=noninteractive apt-get -yqq build-dep mlt
DEBIAN_FRONTEND=noninteractive apt-get -yqq install cmake qt6-base-dev libqt6svg6-dev
DEBIAN_FRONTEND=noninteractive apt-get -yqq install cmake qt6-base-dev libqt6svg6-dev libplacebo-dev
- name: ubuntu-22.04
image: ubuntu:22.04
setup_script: |
sed -i '/^#\sdeb-src /s/^#//' "/etc/apt/sources.list"
DEBIAN_FRONTEND=noninteractive apt-get -qq update
DEBIAN_FRONTEND=noninteractive apt-get -yqq build-dep mlt
DEBIAN_FRONTEND=noninteractive apt-get -yqq install cmake qt6-base-dev libqt6svg6-dev libqt6core5compat6-dev
DEBIAN_FRONTEND=noninteractive apt-get -yqq install cmake qt6-base-dev libqt6svg6-dev libqt6core5compat6-dev libplacebo-dev
- name: debian-unstable
image: debian:unstable
setup_script: |
echo 'deb-src http://deb.debian.org/debian unstable main' >> /etc/apt/sources.list
apt-get -qq update
apt-get -yqq build-dep mlt
apt-get -yqq install libplacebo-dev
- name: debian-testing
image: debian:testing
setup_script: |
echo 'deb-src http://deb.debian.org/debian testing main' >> /etc/apt/sources.list
apt-get -qq update
apt-get -yqq build-dep mlt
apt-get -yqq install cmake qt6-base-dev libqt6svg6-dev
apt-get -yqq install cmake qt6-base-dev libqt6svg6-dev libplacebo-dev
- name: debian-stable
image: debian:stable
setup_script: |
echo 'deb-src http://deb.debian.org/debian stable main\ndeb-src http://deb.debian.org/debian stable-updates main' >> /etc/apt/sources.list
echo 'deb http://deb.debian.org/debian bookworm-backports main' >> /etc/apt/sources.list
apt-get -qq update
apt-get -yqq build-dep mlt
apt-get -yqq install cmake qt6-base-dev libqt6svg6-dev
apt-get -yqq install cmake qt6-base-dev libqt6svg6-dev libplacebo-dev
- name: fedora-42
image: fedora:42
setup_script: |
Expand All @@ -78,7 +79,8 @@ jobs:
libtheora-devel libvorbis-devel libvdpau-devel \
libsoup-devel liboil-devel python-devel alsa-lib \
pulseaudio-libs-devel gcc-c++ cmake ffmpeg-free-devel \
movit-devel rubberband-devel vid.stab-devel
movit-devel rubberband-devel vid.stab-devel \
libplacebo-devel
- name: fedora-38
image: fedora:38
setup_script: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
sudo apt-get -qq update
sudo apt-get -yqq build-dep mlt
sudo apt-get -yqq install qt6-base-dev libqt6svg6-dev libqt6core5compat6-dev
sudo apt-get -yqq install cmake ninja-build kwalify
sudo apt-get -yqq install cmake ninja-build kwalify libplacebo-dev
cmake -D CMAKE_BUILD_TYPE=Debug -D BUILD_TESTING=ON -D SWIG_PYTHON=ON -S . -B build -G Ninja
cmake --build build
sudo cmake --install build
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/build-msys2-mingw64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ jobs:
mingw-w64-x86_64-x264
mingw-w64-x86_64-x265
mingw-w64-x86_64-zimg
mingw-w64-x86_64-libplacebo

- uses: actions/checkout@v4

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/static-code-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
--library=cppcheck.cfg
--suppress=ctuOneDefinitionRuleViolation
--suppress=syntaxError:src/modules/xml/common.c
--suppress=syntaxError:src/modules/placebo/*.c
steps:
- uses: actions/checkout@v4
- name: Install Cppcheck
Expand Down
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ option(MOD_NORMALIZE "Enable Normalize module (GPL)" ON)
option(MOD_OLDFILM "Enable Oldfilm module" ON)
option(MOD_OPENCV "Enable OpenCV module" OFF)
option(MOD_OPENFX "Enable OpenFX module (GPL)" ON)
option(MOD_PLACEBO "Enable libplacebo GPU module" ON)
option(MOD_PLUS "Enable Plus module" ON)
option(MOD_PLUSGPL "Enable PlusGPL module (GPL)" ON)
option(MOD_QT6 "Enable Qt6 module (GPL)" ON)
Expand Down Expand Up @@ -309,6 +310,15 @@ if(MOD_OPENFX)
pkg_check_modules(glib IMPORTED_TARGET glib-2.0)
endif()

if(MOD_PLACEBO)
pkg_check_modules(libplacebo IMPORTED_TARGET libplacebo>=5.229)
if(libplacebo_FOUND)
list(APPEND MLT_SUPPORTED_COMPONENTS placebo)
else()
set(MOD_PLACEBO OFF)
endif()
endif()
Comment thread
ddennedy marked this conversation as resolved.

if(MOD_PLUS)
pkg_check_modules(libebur128 IMPORTED_TARGET libebur128)
list(APPEND MLT_SUPPORTED_COMPONENTS plus)
Expand Down Expand Up @@ -583,6 +593,7 @@ add_feature_info("Module: Normalize" MOD_NORMALIZE "")
add_feature_info("Module: Oldfilm" MOD_OLDFILM "")
add_feature_info("Module: OpenCV" MOD_OPENCV "")
add_feature_info("Module: OpenFX" MOD_OPENFX "")
add_feature_info("Module: Placebo" MOD_PLACEBO "")
add_feature_info("Module: Plus" MOD_PLUS "")
add_feature_info("Module: PlusGPL" MOD_PLUSGPL "")
add_feature_info("Module: Qt6" MOD_QT6 "")
Expand Down
5 changes: 1 addition & 4 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,4 @@ cppcheck:
--library=cppcheck.cfg \
--suppress=ctuOneDefinitionRuleViolation \
--suppress=syntaxError:src/modules/xml/common.c \
--suppress=syntaxError:src/modules/placebo/filter_placebo_convert.c \
--suppress=syntaxError:src/modules/placebo/filter_placebo_render.c \
--suppress=syntaxError:src/modules/placebo/filter_placebo_shader.c \
--suppress=syntaxError:src/modules/placebo/gpu_context.c
--suppress=syntaxError:src/modules/placebo/*.c
17 changes: 7 additions & 10 deletions src/framework/mlt_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ static int generate_test_image(mlt_properties properties,
case mlt_image_none:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
*format = mlt_image_yuv422;
break;
case mlt_image_invalid:
Expand Down Expand Up @@ -1157,15 +1158,13 @@ mlt_frame mlt_frame_clone(mlt_frame self, int is_deep)
}
size = 0;
data = mlt_properties_get_data(properties, "image", &size);
if (data && mlt_image_movit != mlt_properties_get_int(properties, "format")) {
mlt_image_format format = mlt_properties_get_int(properties, "format");
if (data && format != mlt_image_movit && format != mlt_image_private) {
int width = mlt_properties_get_int(properties, "width");
int height = mlt_properties_get_int(properties, "height");

if (!size)
size = mlt_image_format_size(mlt_properties_get_int(properties, "format"),
width,
height,
NULL);
size = mlt_image_format_size(format, width, height, NULL);
copy = mlt_pool_alloc(size);
memcpy(copy, data, size);
mlt_properties_set_data(new_props, "image", copy, size, mlt_pool_release, NULL);
Expand Down Expand Up @@ -1299,15 +1298,13 @@ mlt_frame mlt_frame_clone_image(mlt_frame self, int is_deep)

if (is_deep) {
data = mlt_properties_get_data(properties, "image", &size);
if (data && mlt_image_movit != mlt_properties_get_int(properties, "format")) {
mlt_image_format format = mlt_properties_get_int(properties, "format");
if (data && format != mlt_image_movit && format != mlt_image_private) {
int width = mlt_properties_get_int(properties, "width");
int height = mlt_properties_get_int(properties, "height");

if (!size)
size = mlt_image_format_size(mlt_properties_get_int(properties, "format"),
width,
height,
NULL);
size = mlt_image_format_size(format, width, height, NULL);
copy = mlt_pool_alloc(size);
memcpy(copy, data, size);
mlt_properties_set_data(new_props, "image", copy, size, mlt_pool_release, NULL);
Expand Down
12 changes: 10 additions & 2 deletions src/framework/mlt_image.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ int mlt_image_calculate_size(mlt_image self)
return self->width * self->height * 3 / 2;
case mlt_image_movit:
case mlt_image_opengl_texture:
return 4;
case mlt_image_private:
return sizeof(void *);
case mlt_image_yuv422p16:
return self->width * self->height * 4;
case mlt_image_yuv420p10:
Expand Down Expand Up @@ -228,6 +229,8 @@ const char *mlt_image_format_name(mlt_image_format format)
return "glsl";
case mlt_image_opengl_texture:
return "opengl_texture";
case mlt_image_private:
return "private";
case mlt_image_yuv422p16:
return "yuv422p16";
case mlt_image_yuv420p10:
Expand Down Expand Up @@ -489,6 +492,7 @@ mlt_colorspace mlt_image_default_colorspace(mlt_image_format format, int height)
case mlt_image_rgba64:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
colorspace = mlt_colorspace_rgb;
break;
case mlt_image_yuv422:
Expand Down Expand Up @@ -605,6 +609,7 @@ void mlt_image_fill_black(mlt_image self)
case mlt_image_none:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
return;
case mlt_image_rgb:
case mlt_image_rgba:
Expand Down Expand Up @@ -693,6 +698,7 @@ void mlt_image_fill_checkerboard(mlt_image self, double sample_aspect_ratio)
case mlt_image_none:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
return;
case mlt_image_rgb:
case mlt_image_rgba: {
Expand Down Expand Up @@ -798,6 +804,7 @@ void mlt_image_fill_white(mlt_image self, int full_range)
case mlt_image_none:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
return;
case mlt_image_rgb:
case mlt_image_rgba:
Expand Down Expand Up @@ -952,9 +959,10 @@ int mlt_image_format_size(mlt_image_format format, int width, int height, int *b
return width * height * 3 / 2;
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
if (bpp)
*bpp = 0;
return 4;
return sizeof(void *);
case mlt_image_yuv422p16:
if (bpp)
*bpp = 4;
Expand Down
5 changes: 3 additions & 2 deletions src/framework/mlt_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* \file mlt_types.h
* \brief Provides forward definitions of all public types
*
* Copyright (C) 2003-2025 Meltytech, LLC
* Copyright (C) 2003-2026 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -49,7 +49,8 @@ typedef enum {
mlt_image_yuv420p10, /**< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian */
mlt_image_yuv444p10, /**< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian */
mlt_image_rgba64, /**< 16-bit RGB with alpha channel */
mlt_image_invalid
mlt_image_invalid,
mlt_image_private /**< for module internal use only */
} mlt_image_format;

/** The set of supported audio formats */
Expand Down
4 changes: 4 additions & 0 deletions src/modules/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ if(MOD_MOVIT)
add_subdirectory(movit)
endif()

if(MOD_PLACEBO)
add_subdirectory(placebo)
endif()

if(MOD_PLUS)
add_subdirectory(plus)
endif()
Expand Down
2 changes: 2 additions & 0 deletions src/modules/avformat/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ int mlt_to_av_image_format(mlt_image_format format)
return AV_PIX_FMT_RGBA64LE;
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
case mlt_image_invalid:
mlt_log_error(NULL,
"[filter_avfilter] Unexpected image format: %s\n",
Expand All @@ -339,6 +340,7 @@ mlt_image_format mlt_get_supported_image_format(mlt_image_format format)
case mlt_image_none:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
case mlt_image_rgba:
return mlt_image_rgba;
case mlt_image_rgb:
Expand Down
8 changes: 8 additions & 0 deletions src/modules/avformat/filter_avcolour_space.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ static int convert_image(mlt_frame frame,
mlt_properties_clear(properties, "convert_image_height");

if (*format != output_format || out_width) {
if (*format == mlt_image_none || *format == mlt_image_movit
|| *format == mlt_image_opengl_texture || *format == mlt_image_private
|| *format == mlt_image_invalid || output_format == mlt_image_none
|| output_format == mlt_image_movit || output_format == mlt_image_opengl_texture
|| output_format == mlt_image_private || output_format == mlt_image_invalid) {
return 1;
}

mlt_profile profile = mlt_service_profile(
MLT_PRODUCER_SERVICE(mlt_frame_get_original_producer(frame)));
int width = mlt_properties_get_int(properties, "width");
Expand Down
2 changes: 1 addition & 1 deletion src/modules/avformat/filter_sws_colortransform.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ static int filter_get_image(mlt_frame frame,

// Only process if we have a valid image
if (!*image || *format == mlt_image_none || *format == mlt_image_movit
|| *format == mlt_image_opengl_texture)
|| *format == mlt_image_opengl_texture || *format == mlt_image_private)
return 0;

// Get the current color transfer characteristics
Expand Down
1 change: 1 addition & 0 deletions src/modules/avformat/link_avdeinterlace.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ static mlt_image_format validate_format(mlt_image_format format)
case mlt_image_none:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
case mlt_image_invalid:
ret_format = mlt_image_yuv422;
break;
Expand Down
6 changes: 4 additions & 2 deletions src/modules/avformat/producer_avformat.c
Original file line number Diff line number Diff line change
Expand Up @@ -827,8 +827,9 @@ static mlt_image_format pick_image_format(enum AVPixelFormat pix_fmt,
mlt_image_format current_format)
{
if (current_format == mlt_image_none || current_format == mlt_image_movit
|| pix_fmt == AV_PIX_FMT_ARGB || pix_fmt == AV_PIX_FMT_RGBA || pix_fmt == AV_PIX_FMT_ABGR
|| pix_fmt == AV_PIX_FMT_BGRA || pix_fmt == AV_PIX_FMT_GBRAP) {
|| current_format == mlt_image_private || pix_fmt == AV_PIX_FMT_ARGB
|| pix_fmt == AV_PIX_FMT_RGBA || pix_fmt == AV_PIX_FMT_ABGR || pix_fmt == AV_PIX_FMT_BGRA
|| pix_fmt == AV_PIX_FMT_GBRAP) {
switch (pix_fmt) {
case AV_PIX_FMT_ARGB:
case AV_PIX_FMT_RGBA:
Expand Down Expand Up @@ -2516,6 +2517,7 @@ static void convert_image(producer_avformat self,
case mlt_image_yuv422:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
case mlt_image_invalid:
break;
}
Expand Down
1 change: 1 addition & 0 deletions src/modules/core/filter_brightness.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ static int filter_get_image(mlt_frame frame,
break;
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
*format = mlt_image_rgba;
break;
case mlt_image_none:
Expand Down
4 changes: 3 additions & 1 deletion src/modules/core/filter_color_transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ static void ensure_color_properties(mlt_filter self, mlt_frame frame)
case mlt_image_rgba64:
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
full_range = 1;
break;
case mlt_image_yuv422:
Expand Down Expand Up @@ -182,7 +183,8 @@ static int filter_get_image(mlt_frame frame,
mlt_properties filter_properties = MLT_FILTER_PROPERTIES(self);
mlt_image_format requested_format = *format;
int ret = mlt_frame_get_image(frame, image, format, width, height, writable);
if (ret || requested_format == mlt_image_movit || requested_format == mlt_image_none)
if (ret || requested_format == mlt_image_movit || requested_format == mlt_image_private
|| requested_format == mlt_image_none)
return ret;

const char *out_trc_str = mlt_properties_get(filter_properties, "force_trc");
Expand Down
4 changes: 4 additions & 0 deletions src/modules/core/filter_imageconvert.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,10 @@ static int convert_image(mlt_frame frame,
int height = mlt_properties_get_int(properties, "height");

if (*format != requested_format) {
// Only handle standard CPU formats; skip private/invalid/none formats
if (*format <= mlt_image_none || *format >= mlt_image_invalid
|| requested_format <= mlt_image_none || requested_format >= mlt_image_invalid)
return 1;
conversion_function converter = conversion_matrix[*format - 1][requested_format - 1];

mlt_log_debug(NULL,
Expand Down
5 changes: 3 additions & 2 deletions src/modules/core/producer_colour.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ static int producer_get_image(mlt_frame frame,
*format = mlt_image_format_id(mlt_properties_get(producer_props, "mlt_image_format"));

// Choose suitable out values if nothing specific requested
if (*format == mlt_image_none || *format == mlt_image_movit)
if (*format == mlt_image_none || *format == mlt_image_movit || *format == mlt_image_private)
*format = mlt_image_rgba;
// Optimize the format to avoid unnecessary conversion
if ((requested_format == mlt_image_rgba && *format == mlt_image_rgba64)
Expand All @@ -109,7 +109,7 @@ static int producer_get_image(mlt_frame frame,
// Choose default image format if specific request is unsupported
if (*format != mlt_image_yuv420p && *format != mlt_image_yuv422 && *format != mlt_image_rgb
&& *format != mlt_image_movit && *format != mlt_image_opengl_texture
&& *format != mlt_image_rgba64)
&& *format != mlt_image_private && *format != mlt_image_rgba64)
*format = mlt_image_rgba;

// See if we need to regenerate
Expand Down Expand Up @@ -182,6 +182,7 @@ static int producer_get_image(mlt_frame frame,
break;
case mlt_image_movit:
case mlt_image_opengl_texture:
case mlt_image_private:
memset(p, 0, size);
break;
case mlt_image_rgba:
Expand Down
Loading
Loading