Skip to content

Develop a frei0r plugin

A frei0r plugin is a shared library implementing a small C ABI. The repository also provides a C++ wrapper that handles exported functions and parameter plumbing for common plugins.

Start with the maintained src/filter/tutorial example and keep include/frei0r.h open as the specification.

1. Choose a plugin type

TypeFrames inPurpose
F0R_PLUGIN_TYPE_SOURCE0Generate a frame
F0R_PLUGIN_TYPE_FILTER1Transform a frame
F0R_PLUGIN_TYPE_MIXER22Combine two frames
F0R_PLUGIN_TYPE_MIXER33Combine three frames

Choose the narrowest type that represents the effect. Hosts use this metadata to decide how many inputs to connect.

2. Choose a color model

New plugins should normally use F0R_COLOR_MODEL_RGBA8888. The API also defines BGRA and packed 32-bit models for compatibility. A frame is a width-by-height array of 32-bit pixels in the declared model.

3. Implement the effect

The C++ wrapper provides base classes named source, filter, mixer2 and mixer3. A minimal filter stores its parameters and implements update:

cpp
#include "frei0r.hpp"

class MyFilter : public frei0r::filter {
 public:
  MyFilter(unsigned int width, unsigned int height) {
    register_param(amount, "Amount", "Strength of the effect");
    amount = 0.5;
  }

  void update(double time, uint32_t* out, const uint32_t* in) override {
    // Transform width * height pixels from in to out.
  }

 private:
  double amount;
};

frei0r::construct<MyFilter> plugin(
    "My filter", "A short description", "Your name", 0, 1,
    F0R_COLOR_MODEL_RGBA8888);

The wrapper's constructor receives (width, height), and its base class stores both dimensions. Initialize every parameter in the constructor.

4. Register parameters

frei0r supports Boolean values, normalized doubles, colors, positions and strings. Hosts generally present doubles in a normalized 0.0 to 1.0 range. Convert that range to the useful domain inside the plugin and document any special mapping in the parameter description.

5. Process frames safely

  • Treat input frame pointers as read-only.
  • Write every output pixel unless the effect first copies the input.
  • Handle in-place operation only if the algorithm explicitly supports it.
  • Keep allocation and expensive lookup-table setup in construction.
  • Use time for deterministic animation rather than a private wall clock.
  • Validate dimensions and arithmetic before calculating buffer offsets.

The tutorial demonstrates pixel iteration, parameter registration, lookup tables and clamping. It is a collection of ideas, not an installed effect.

6. Add the CMake target

Create a directory under the matching src category with a CMakeLists.txt:

cmake
set(SOURCES myfilter.cpp)
set(TARGET myfilter)

if(MSVC)
  set(SOURCES ${SOURCES} ${FREI0R_DEF})
endif()

add_library(${TARGET} MODULE ${SOURCES})
set_target_properties(${TARGET} PROPERTIES PREFIX "")
install(TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})

Add the directory with add_subdirectory(myfilter) in the parent category's CMakeLists.txt.

7. Build and inspect it

sh
cmake -S . -B build -G Ninja
cmake --build build --target myfilter

cd test
make frei0r-meta
./frei0r-meta ../build/src/filter/myfilter/myfilter.so

Adjust the library suffix and path for the platform. Check the displayed name, author, explanation, type, color model, version and every parameter.

8. Run the plugin tests

sh
cd test
make frei0r-asan
make check

New plugins should also include focused tests for their invariants where practical. At minimum, exercise unusual frame dimensions, parameter boundaries and repeated update calls.

9. Contribute

  1. Keep the plugin focused on one reusable effect.
  2. Use a clear, unique plugin name and human-readable metadata.
  3. Confirm builds with and without optional dependencies as applicable.
  4. Open a pull request.

Use GitHub issues for defects and Telegram for design discussion.