- 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
The CI runner has no Vulkan runtime (liboakvulkan.so fails to load) and
no display (offscreen QOpenGLWidget cannot create a context). The
viewer display tests only checked that the parameter was "vulkan", so
they ran on the OpenGL fallback and segfaulted with no usable GL
context. Probe the backend the same way the other render test fixtures
do (load, verify the backend kind actually matches the request, init)
and skip when it is unavailable. Also replace the stale "temporary
scratch test" file header now that this is a committed regression test.
Ubuntu (FFmpeg 7.0) build failure: the public FB_PIX_FMT_* values were
hardcoded to AVPixelFormat enum values, but those shift between FFmpeg
releases (new formats are inserted mid-enum: X2RGB10 in 7.0,
RGBF16/GRAYF16 later), so the static_asserts in internal.h failed and
RGBF16LE/GRAYF16LE did not exist at all.
The FB pixel format values are now fixed identifiers translated inside
the library by pixel format name (stable across releases):
- fb::PixFmtToAV/PixFmtFromAV resolve the static table by name;
formats a decoder produces that have no static identifier (hardware
downloads like nv12/p010le/p210le) receive process-local dynamic ids
>= 1000 so they keep round-tripping through the API (scaler etc.)
instead of collapsing to NONE and crashing sws.
- All crossing points translated: scaler, frame get/set format,
decoder/probe stream info, encoder config and write_video_frame,
fb_pix_fmt_* utilities, fb_find_best_pix_fmt_of_list (which also
reinterpret_cast the caller's list; now translated element-wise and
properly NONE-terminated).
- nv12 and p010le get static identifiers as the common hardware
download formats.
- Hardware frame detection no longer compares pixel formats (breaks
across format spaces); it uses the existing fb_frame_is_hw().
macOS test failures (FFmpegBridgeEncoder.WritePngVideoAndProbeBack,
WritePcmAudioAndProbeBack): config.filename held a dangling pointer to
a temporary QByteArray (UB; happened to work on Linux). Keep the
QByteArray alive for the encoder's lifetime.
Windows (MSYS2 UCRT64) build failure: timecodefunctions.h used int64_t
without including <cstdint> (previously pulled in transitively).
Full gtest suite: 584 passed.
ClipBlock::kBufferIn is declared as NodeValue::kNone with no value
hint, so when a footage node is connected straight to a clip's buffer
input (no effect node in between), the traverser has no type to look
up in the footage's value table and falls back to its last entry. A
footage pushes its video texture first and its audio samples last, so
a video clip ended up fed with audio samples, produced no texture and
the preview went silently black. With any node in between, the table
only carries the passthrough texture, which is why the bug only showed
on direct connections.
Make Node::GetValueHintForInput virtual and override it in ClipBlock
to prefer the value type matching the clip's track (kTexture on video
tracks, kSamples on audio tracks).
Regression tests cover the exact application render path
(PreviewAutoCacher -> RenderManager -> RenderWorkerPool ->
oak-render-worker) for both the direct and indirect cases, the hint
following the track type, and viewer display widgets. The direct-case
test reproduces the black frame without the fix and passes with it.
Full suite: 584 passed.
- Replace direct FFmpeg usage in the test suite (channel layout masks,
pixel/sample format constants, AVFrame field access, sws_scale) with
the bridge equivalents and the olive::AVFrame adapter
- Drop CoreRational.ToAVRational (API removed with core's FFmpeg
dependency) and the GetSwsColorspaceFromAVColorSpace tests (helper
moved inside the bridge)
- New ffmpeg_bridge_test.cpp exercises the C API directly: constants vs
core, error strings, pixel format utilities, frames/packets, scaler,
resampler, audio graph tempo processing, probe/decoder round-trip on
tests/demo.mp4 (including hw-frame transfer), SRT subtitle reading,
and encoder end-to-end tests (PNG video and PCM audio probed back)
Run clang-format over all project C/C++ source and header files
(.c, .cpp, .cc, .h, .hpp, .hh, .m, .mm) under app/ and tests/.
Non-source files (svg, qm, qrc, etc.) were not touched.
- Rename macOS bundle output from Olive.app to Oak.app.
- Rename editor binary to oak-editor and render worker to oak-render-worker.
- Rename crash handler output to oak-crashhandler.
- Update worker lookup, NSIS installer, Linux desktop/AppRun, crashhandler
symbol paths, and documentation for the new binary names.
- Update CD workflow paths and add -qmldir flags to macdeployqt so QtQuick
/ QML plugins required by KDDockWidgets are bundled, fixing the launch
crash on macOS.
- Update user-facing GitHub URLs to OakVideoEditorCommunity/oak.
- RenderWorkerFootageTest: skip when the dynamic render backend is not
built; we cannot verify backend availability without it, and the tests
fail on headless/GPU-less CI runners.
- NodeProject.FilenameAndNameUpdate: use a plain filename instead of
/tmp/... so the expected name does not depend on POSIX temp paths or
Windows backslash normalization.
- Make olive-editor depend on olive-render-worker on all platforms so the
worker is always built with the main app.
- Copy olive-render-worker and dynamic render backends (oakgl, oakvulkan)
into the macOS app bundle next to the executable.
- Include oakgl.dll and oakvulkan.dll in the Windows NSIS installer.
- Fix PluginSmokeThread.ConcurrentParamAccess CI failure by adding a mutex
around IntegerInstance's no-node fallback storage and serializing the
test's set/get pair.
- Hide the render worker's Dock icon on macOS via
NSApplicationActivationPolicyProhibited.
Renderer / preview:
- Switch the preview/display readback format from F16 to packed
10-bit RGBA (PixelFormat::U10) to halve GPU->CPU/IPC bandwidth
while keeping 10-bit panel precision.
- Add U10 support to VideoParams, FFmpeg/OIIO/OCIO utility mappings,
OpenGL (GL_RGB10_A2), Vulkan (VK_FORMAT_A2B10G10R10_UNORM_PACK32),
and plugin bit-depth lookups.
- Update preview autocacher comment to reflect the new behavior.
OCIO LUT tests:
- Add four E2E-style ColorLutNode gtests that drive a SolidGenerator
-> OCIOLutNode graph through NodeTraverser and compare resulting
pixels on the CPU. They cover forward/inverse transforms and verify
that switching LUT direction and LUT file updates both the processor
and the output pixels.
Cleanup:
- Remove a leftover SolidGenerator::Value debug fprintf.
- Capture render worker stderr in RenderWorkerFootageTest for better
diagnostics.
- Pass through input texture when the LUT processor is not ready yet,
preventing black frames while the processor is being generated.
- Serialize processor generation with a single in-flight task to avoid
concurrent OCIO lock contention that could freeze the UI.
- Invalidate cached frames after the async processor is set so the viewer
refreshes automatically without requiring the playhead to be moved.
- Add OAK_DISABLE_HWACCEL environment variable to force software decoding.
- Add FFmpegDecoderHW regression test for H.264 4:2:2 10-bit decoding.
- Add shared UBO layout across vertex + fragment stages so vertex
uniforms like ove_mvpmat compile and bind correctly.
- Rewrite uniform extraction/injection to avoid corrupting the UBO
block and to keep explicit sampler bindings stable.
- Make the UBO and sampler descriptor bindings visible to both vertex
and fragment stages.
- Add layout locations for vertex varyings (ove_texcoord) and fragment
inputs so SPIR-V generation succeeds.
- Extend TransitionImageLayout() to cover all layout pairs used by
upload/download/clear/blit.
- Add subpass dependencies to the cached render pass and leave
destinations in SHADER_READ_ONLY_OPTIMAL after Blit().
- Move descriptor allocation before command recording and abort cleanly
if allocation fails; switch Blit() to the persistent linear sampler.
- Add a gtest that creates a Vulkan backend, uploads a red U8 RGBA
texture, blits through the default pass-through shader, and verifies
the downloaded pixel is red. This test passes on the current system.
ctest passes 4/4; DynamicRenderBackend.* passes 3/1 (Vulkan fallback
skipped because Vulkan is available).
- Add PickRenderableFormat / IsColorAttachmentSupported so 3-channel
Vulkan formats fall back to 4-channel when unsupported.
- Make oakvulkan target and C ABI check conditional on Vulkan_FOUND;
skip liboakvulkan build/dependencies when Vulkan headers/libs are
absent.
- Update Preferences tooltip to reflect Vulkan is an experimental
prototype that may fall back to OpenGL.
- Revise dynamic backend plan doc: phase 3/4/5 described as prototype
frameworks with runtime validation pending, and list recent Vulkan
fixes (init idempotency, descriptor/sampler lifetime, dynamic
viewport/scissor, render pass clear, format probing).
Both OAK_ENABLE_DYNAMIC_RENDER_BACKEND=ON and OFF configurations
build and pass ctest (4/4).
- 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 removes redundant readbacks and uploads in the OpenFX
plugin pipeline, achieving zero-copy rendering for GL-capable
plugins and reducing CPU path overhead.
PluginRenderer (OpenGL path):
- Skip ReadbackTextureToFrame + ConvertFrameIfNeeded + Upload after
plugin render. The destination texture is already valid on GPU.
- Pass readback_cpu=false to setInputTexture() so input textures are
provided via loadTexture() (GL texture IDs) instead of being
downloaded to CPU Image buffers.
- Remove duplicate ReadbackTextureToFrame block between
getClipPreferences and the second setInputTexture call.
OliveClipInstance:
- Add optional bool readback_cpu=true to setInputTexture(). When
false, only params and input_textures_ are updated; CPU readback
and memcpy into Image are skipped.
- Add pruneImagesCache() to prevent unbounded growth of images_.
Input clips are limited to 8 cached frames; output clips are
left untouched.
Micro-optimizations:
- Replace per-row memcpy loops with single block memcpy when
src/dst strides are contiguous (common case in Olive pipeline).
- Remove dead GL_PREAMBLE macro definition.
fix(viewer): resolve playback head lag, frozen frames, and pause delay
Three playback pipeline behavioral issues are fixed:
1. Prequeue blocked playhead start:
Reduce kVideoPlaybackInterval from 0.5s to 0.1s. This lowers
prequeue length from 15–30 frames to 3–6 frames, so the
playback timer starts much sooner after pressing Play.
2. Frozen display during playback:
Relax the hard frame-drop logic in RendererGeneratedFrameForQueue.
When the queue has fewer than 2 frames, keep late frames instead
of dropping them, preventing the viewer from freezing entirely
when rendering cannot keep up with playback speed.
3. Delayed frame update after pause:
Cancel in-flight render tickets in PauseInternal() before
deleting queue watchers. Previously the render thread continued
processing stale playback frames, blocking the single-frame
render requested by UpdateTextureFromNode().
This commit resolves several categories of OFX plugin failures that
manifested as magenta (pink) render output or crashes:
1. Param default-value initialization
- IntegerInstance, DoubleInstance, BooleanInstance, ChoiceInstance,
and StringInstance now read kOfxParamPropDefault from the descriptor
at construction time. Previously, when no PluginNode was attached
(integration-test mode), get() returned 0/0.0/false, causing
generator plugins to receive invalid extent/format/PAR values and
crash in coordinate assertions.
- IntegerInstance also fixed uninitialized `id` that caused
kOfxStatErrBadHandle in CImg plugins.
2. Clip property initialization
- newClipInstance() now seeds pixelDepth and components from the
host VideoParams instead of leaving them as None. This prevents
Transform3x3Plugin and similar plugins from asserting on
getPixelComponentCount() during fetchClip inside createInstance.
- getAspectRatio() and getProjectPixelAspectRatio() now fall back
to 1.0 when the project's PAR is not yet set, avoiding division-
by-zero in coordinate conversion.
3. Frame-rate and time-base preservation
- setInputTexture() no longer overwrites the clip's frame_rate or
time_base with the input texture's values. Multi-input plugins
were crashing because setupClipPreferencesArgs throws when inputs
have mismatched rates.
4. Render loop hardening
- getClipPreferences() is now wrapped in try/catch so that frame-
rate mismatch exceptions mark render failure instead of aborting
the render thread.
- getRegionOfInterestAction() treats kOfxStatErrBadHandle as non-
fatal and falls back to default RoI.
- RenderPlugin syncs all clip instances after setVideoParam so that
getAspectRatio/getFrameRate return valid values before
createInstanceAction queries them.
5. Test suite updates
- All PluginMisc tests now use F32 input to match the host pipeline
default.
- CreateGradientTexture fixed to support F32 pixel format.
- Added CImgBilateral and CImgGuided_MultiInput tests.
- Secret parameters are now registered as hidden Node inputs so that
getClipPreferences can read them (fixes generator pink screen).
6. Debug logging in HostSupport
- clipGetImage and clipGetRegionOfDefinition now catch exceptions
and log the failing clip name for easier debugging.
- Fix SIGSEGV in PluginMisc.Keyer by linking Param::SetInstance to instances.
Olive's custom param instances (IntegerInstance, DoubleInstance, etc.) were
not passing the SetInstance pointer to the OpenFX HostSupport base class,
leaving _paramSetInstance as nullptr. When Keyer called paramSetValue during
createInstanceAction, the suite function dereferenced the null pointer in
paramChangedByPlugin(). Now newParam() passes 'this' to every constructor.
- Fix render-thread crash when OFX plugins set params during rendering.
MinOFX calls paramSetValue inside createInstanceAction from the render
thread. SubmitUndoCommand() used to push undo commands directly to
UndoStack, which modifies QAction state (GUI-only). Added IsGuiThread()
check: non-GUI threads execute redo_now() and discard the command without
touching the undo stack.
- Enable PluginMisc.MergeOver and PluginMisc.Keyer integration tests.
MergeOver now supplies both Source and Bg textures; Keyer uses U16 format.
Both pass in the full test suite.
- Make ViewerQueue thread-safe with QMutex around AppendTimewise/PurgeBefore.
Adds copy ctor and assignment to support mutex-per-instance semantics.