- Footage can store custom proxy parameters (width/height/crf/preset/
extension/audio) that override the global settings; they are
serialized with the project and used by every generation entry point
via Footage::GetEffectiveProxyParams()
- Proxies now include the source audio streams (AAC) unless disabled;
the proxy filename records the audio flag and offline audio rendering
decodes from the proxy when present
- ProxyTask resolves ffmpeg from the new FFmpegPath config key first,
then PATH, then common install locations (e.g. Homebrew on macOS),
instead of relying on PATH only; the error message points at the
preferences when no executable is found
- ProxyTask::BuildArguments() is extracted for testability
- Add ProxyIncludeAudio and FFmpegPath config defaults
- Add regression tests for the filename audio marker, config-backed
params, ffmpeg resolution, argument building, and custom-param
persistence
Replace every direct FFmpeg call in the editor and the render worker
with the pure C ffmpeg_bridge API, wrapped in thin C++ adapters that
preserve the original interfaces:
- avframeptr.h: olive::AVFrame adapter around FBFrame handles
- ffmpegutils: format conversion helpers on FB_* constants; the int
overload is renamed GetCompatibleBridgePixelFormat to avoid a silent
overload-resolution trap with the PixelFormat enum
- ffmpegdecoder/ffmpegencoder: rewritten as handle-based adapters over
FBDecoder/FBProbe/FBEncoder/FBScaler/FBResampler
- audioprocessor: FBAudioGraph push/pull adapter
- pluginrenderer/OliveClip: sws/pixdesc usage converted to FBScaler and
fb_pix_fmt_* queries
- AudioParams/channel layouts are plain uint64_t masks everywhere
Build integration: the root project no longer links FFMPEG directly;
only ffmpeg_bridge does. Binaries resolve the bridge library at runtime
via @loader_path inside the macOS app bundle (copied there post-build)
and via $ORIGIN/../ffmpeg_bridge/bin on Linux; on Windows the DLL is
installed next to the executables, so packages on all three platforms
ship the bridge library.
ffmpeg_bridge gains the extra API the adapters need:
fb_frame_make_writable, fb_decoder_get_format_duration,
fb_resampler_convert_frame, FB_PIX_FMT_YUV440P, SRT validation in
fb_probe_read_subtitle_stream, packed/planar fixes in
fb_encoder_write_audio, and a component-size fix in
fb_pix_fmt_component_size.
- On Linux, automatically prefer PipeWire/JACK/PulseAudio over ALSA
even when a saved ALSA device name exists in config.
- Restore Footage length after deserialization so worker snapshots
have valid stream lengths and video playback can advance.
- Guard ResolveDecoderFromInput and ProcessAudioFootage against a
null decoder cache to prevent worker crashes on direct Footage ->
ViewerOutput connections.
- Keep Linux signal backtrace handler in the render worker.
- Add Oak project SVG logos.
- Extract libolive-rendercore static library to minimize backend link boundary.
- Add DynamicRenderer adapter with C ABI (oakgl/oakvulkan shared libs).
- Make OAK_ENABLE_DYNAMIC_RENDER_BACKEND default ON with OpenGL fallback.
- Implement VulkanRenderer prototype (textures, shaders, UBO blit, readback).
- Add backend-neutral viewer readback path (offscreen -> QImage -> QPainter).
- Refactor PluginRenderer to be renderer-agnostic; OFX plugins fall back to CPU
path on non-OpenGL backends while preserving OpenGL render path.
- Add Renderer::AttachOutputTexture/DetachOutputTexture and C ABI forwards.
- Update docs/zh/render-backend-dynamic-plan.md for Phase 3/4/5.
This commit fixes crashes (SIGSEGV in CImg blur_bilateral) and black-frame
corruption artifacts during playback and scrubbing on macOS Apple Silicon.
Root cause analysis:
1. macOS uses Tile-Based Deferred Rendering (TBDR). glFlush() does not
guarantee tile memory writeback, causing glReadPixels to read incomplete
tiles (black/corrupted frames) and cache them to disk.
2. Olive uses multiple shared OpenGL contexts (RenderProcessor contexts vs.
thread-local PluginRenderer context). glFinish() only waits for the
current context, not the shared context that produced the texture. CPU
readback in PluginRenderer could read partially-rendered tiles.
3. OlivePluginInstance and OliveClipInstance are not thread-safe. Concurrent
RenderProcessors could corrupt internal QMap/images_ and params_ via
setInputTexture/renderAction races.
Fixes:
- OpenGLRenderer::Flush() on macOS now uses glFinish() unconditionally.
- OpenGLRenderer::DownloadFromTexture() and OpenGLRenderer::Blit() insert
glFinish() before readback/detach to ensure tile writeback completes.
- PluginRenderer::RenderPlugin() now acquires a per-instance mutex to
serialize concurrent OFX render calls.
- Before CPU readback in PluginRenderer, flush the renderer that originally
produced each input texture, ensuring cross-context synchronization.
- RenderProcessor::ProcessVideoFootage() flushes after BlitColorManaged.
- Add black-frame detection in ProcessVideoCacheJob() to auto-purge TBDR-
corrupted cache files.
- Add diagnostic qDebug() logging in viewer, decoder, renderer, and plugin
paths to aid future debugging.
Fix three performance traps in the OFX plugin preview pipeline that
caused slideshow-like performance when any plugin was active.
1. Eliminate per-frame PluginRenderer creation (GL FBO alloc/free)
RenderProcessor is stack-allocated per ticket, so its
plugin_renderer_ member was constructed and destroyed every frame.
PluginRenderer inherits OpenGLRenderer, whose PostInit() calls
glGenFramebuffers() and whose destructor calls glDeleteFramebuffers().
On Apple Silicon's TBDR this is pathologically expensive.
Fix: use a thread_local cached PluginRenderer so each render thread
creates it only once and reuses it forever.
2. Call getClipPreferences() conditionally
The code unconditionally called instance->getClipPreferences() on
every single frame. This dispatches kOfxImageEffectActionGetClipPreferences
into the plugin even when no inputs or parameters have changed.
Fix: check areClipPrefsDirty() first. The OpenFX Host Support library
already tracks this flag and sets it to true when slave params or clip
connections change.
3. Call ApplyParamOverrides() before renderAction
ApplyParamOverrides() was defined but never invoked, so animated
plugin parameters were never pushed into the OFX instance before
rendering.
Fix: call it after beginRenderAction() and before renderAction(),
injecting the current NodeValueRow values at the correct OfxTime.
This commit extends the OFX plugin support in Olive by:
- Initializing and scanning for OFX plugins
- Updating PluginNode to handle OFX plugin parameters and inputs
- Adding necessary methods and properties for OFX plugin integration
- Enhancing NodeFactory to include OFX plugin nodes
- Refactoring and renaming OliveInstance to OlivePluginInstance
- Introducing new classes for parameter handling (ParamInstance)
- Adding PluginJob for rendering OFX plugins
- Adjusting CMakeLists.txt files to include new source files
This commit adds comprehensive support for OFX plugins in Olive, including:
- Add plugin node infrastructure with getPlugin() method
- Implement OliveHost for managing OFX plugin instances
- Create OliveInstance to handle plugin parameter and timeline interactions
- Add OliveClip implementation for plugin clip handling
- Implement region of definition (RoD) and region of interest (RoI) functionality
- Add interactive mode support in Current class
- Integrate plugin rendering into RenderProcessor
- Fix include dependencies and remove unused OlivePlugin.cpp reference