- oakengine is now cdylib-only (no rlib/staticlib consumers anywhere;
cargo tree verified) — the plugin/external C ABI layer; README and
docs updated
- cd.yml drops the dylib embedding/re-sign steps (the app no longer
links it)
- test race root-caused and fixed for good: the global undo stack lock
is now a re-entrant mutex (parking_lot) shared by every test that
drives the stack, including the previously unlocked node/render
families; the render-manager serial-ordering bug (an earlier repro
test initialized the global manager before the not-initialized test)
is fixed with a shared SERIAL guard and a manager shutdown
- 5 consecutive parallel runs clean; serial 209/209
- real.rs rewritten over module Rust APIs (Arc<Mutex<Project>> +
NodeId; the addref handle dance and renderer boxes are gone);
AppEngine trait and all panels untouched
- new app assembly layers: graphops (project/timeline/edit
primitives), effectchain (chain composition with undo groups),
renderops (montage build + ticket render + ExportTask export),
library via oakstorage directly
- module-side safe API additions: oakundo global value-semantic
push/undo/redo + from_closures, oakstorage project_arc_of
- deleted: src/oakui/ffi.rs, src/oakui/host_syms.rs, the dylib link
config in build.rs (only the gpui IOSurface framework link remains)
- the binary carries zero liboakengine references (otool/nm verified);
101 app tests green incl. the real-render and full-res e2e tests
- behavior improvements for free: sequences land in the project graph
(the facade scratch-project deviation is gone), footage drops take
one undo record, effect remove/reorder undo restores edges
- oak-cli: new engine.rs assembly layer maps every facade call to
module Rust APIs (oaknode graph/serializer, oaktimeline commands,
oakrender ticket arena, oaktask ExportTask, oakcommon config); the
ffi/optional/host layers and build.rs link config are gone
- oak-worker: the worker session + POSIX shm transport moved into the
crate (oakrender backend + serde_json control plane); no dylib
- both binaries carry zero liboakengine references (otool verified);
tests green (30 cli / 41 worker)
- oakundo::global: the process-global undo stack, grouping and a
command observer API; facade undo.rs becomes a thin forwarder
- oakstorage::writethrough: the binding table, snapshot thread, flush
and config resolution; it subscribes to oakundo's observer itself
- the remaining non-forwarding facade logic (TaskMeta, effect chains,
timeline composites, RendererBox, exporter path) is documented as
facade-owned with reasons
- facade exports unchanged; full suite stays green (the one
render_manager_not_initialized failure is pre-existing on the base
commit)
D3: oakdb+pg:// fully wired (shared sea-orm entities, BIGSERIAL DDL,
connect-probe instead of pool retry on dead servers); Storage/Backend=pg
+ Storage/PgUrl config; 13 OAK_TEST_PG_URL-gated PG tests (verified
against a Docker postgres:16), always-on clean-error tests otherwise.
D4: DaVinci-style project manager — list with derived stats, create/
rename/duplicate/delete (confirm)/import/export (native dialogs,
ove/otio/fcpxml), shown at startup and from the file menu; facade
oakengine_library_* exports (list/create/delete/rename/duplicate/
import/export + project_load_library that binds write-through);
save/save-as menu becomes 'export project file', open splits into
from-library/from-file; status bar shows library write state; storage
activates on app start and flushes on exit; spawn_modal reentrancy
fixed (window-callback path) with a doc note.
Also: the P1 audio test's environment probe was lost in the ffi purge;
restored on cpal (the output device is cpal now).
- facade storage session manager: project handles bind to the default
SQLite library on project_new/load; every undo push/group_end/jump
write-throughs via DatabaseBackend::save (diff journal); project_free
flushes and unbinds
- background snapshot thread (Storage/SnapshotIntervalSec, latest-wins,
newest 3 kept) with exit flush (oakengine_storage_flush)
- config-gated: storage only activates with an explicit
Storage/Backend=sqlite, so headless consumers and tests never touch
the real library; new exports: storage_flush/is_bound/last_error
- it_storage: kill -9 recovery, cross-session undo, snapshot pruning,
multi-project isolation, graceful degradation
- also fixes a real config test polluting the user config.ini and the
undo-stack test races
Single-lib cleanup: the per-crate src/bridge/ and src/ffi.rs layers are
gone (oakundo/oakcommon/oaknode/oaktimeline/oakcodec/oakaudio/
oakrender/oaktask/oakplugin/oakstorage); cross-crate calls are plain
Rust, CHandle marshalling shrinks to the oakengine boundary, and tests
call the Rust APIs directly (pure C-ABI wrapper tests removed where
the domain layer already covers the behavior).
exporter.h family implemented: oakengine_export_render (CLI contract),
oakengine_export_render_with_params (was a stub), last_error and
progress callback; synchronous path reuses task_create_export +
start_sync. Fixes on the way: oaktask video ticket self-deadlock,
audio params dropped on the export path, codec encoder AAC slicing and
H.264 time base. Real-mp4 tests cover both entry points, progress and
the illegal-argument matrix.
Also: oakstorage session maps null project handles to None (version-
info path), configstore test double literal 3.14 -> 3.15 (clippy PI
lint), oakaudio output callback scratch buffer + env-aware P1 test,
cli media round-trip test uses a generated 16-frame clip (no more
minute-long debug runs).
oakstorage (new workspace member): URI dispatch, pluggable backends
(ove-xml built in, otio/fcpxml via oakotio, C-vtable foreign
registration), the M10 C API surface, version info codes, last-error
and alive accounting; round-trip tests per backend.
oaknode serializer: persists the full timeline — sequence track lists,
track block lists, block ranges/media_in/speed/flags, clip footage
references, footage filename+streams, folder children — through
<custom> behavior hooks with two-phase reference resolution; loads the
C++ <olive><project><layout> containers (golden: tests/
project_with_footage.ove); round-trip is field-by-field and
byte-idempotent.
engine:
- oakrender eval footage hook decodes via oakcodec (JobSpec::Footage
carries filename/stream); ticket/ffi/manager wiring, real-media
decode test with programmatically generated MPEG-2
- oakrender bridge/codec.rs + node.rs: direct oakcodec/oaknode calls;
the crate's dlsym module is gone (project_deep_copy/sync_copy remain
documented always-fail stubs — never implemented in oaknode)
- oakaudio waveform/decoder path adjustments for the decode hook
app (gpui + gpui_widgets):
- menu bar scrubbing: hovering another top-level title while a menu is
open switches to it; popup width is content-aware (CJK-aware) instead
of fixed 160px
- density pass: window rem 16 -> 14px, menu rows 26 -> 22px, dock tabs
32 -> 26px, viewer transport tightened
- open/import/save-as use the native platform file dialogs
(prompt_for_paths / prompt_for_new_path; multi-select import);
MockEngine records imported footage for tests
- project explorer Tree/Icons toggle is localized (explorer.tree /
explorer.icons widget keys)
- tooling/ffmpeg/build-ffmpeg.sh builds release/8.0 static+PIC into
.cache/ffmpeg: GPL/version3, every free-license external codec lib
probed via pkg-config (enabled when present), per-OS hardware
acceleration (VideoToolbox/AudioToolbox, VAAPI/VDPAU/libdrm,
D3D11VA/DXVA2/MediaFoundation, nvenc when ffnvcodec exists)
- tooling/install-deps.sh installs those libraries on Homebrew / MSYS2
UCRT64 / Debian-Ubuntu / Fedora / Arch; nothing in the build sudo's
- ffmpeg-next's own build feature is unusable (every crate-version to
FFmpeg-release pairing is broken upstream: 9.0.0->FF9 AVCodec fields,
8.1.0->FF8.1 new enum variants, 8.0.0->FF8 FF_PROFILE rename), so
ffmpeg-next 9 + FFmpeg 8.x headers via FFMPEG_DIR it is
- new links-crate oakffmpeg-link emits the static FFmpeg's transitive
link flags from its .pc files (cargo only propagates them from links
crates, and rustc prunes the flags unless the rlib is referenced —
hence the force_link statics)
- docs/build.md updated for the Rust workspace flow
- processor.rs: resample/channel-convert/time-stretch now runs an
in-process FFmpeg filter graph (abuffer -> atempo -> aformat ->
abuffersink) via ffmpeg-next
- waveform.rs: extraction decodes through oakcodec's FFmpegDecoder
(interleaved f32) instead of the fb_decoder/fb_audio_graph pair
- bridge/ffmpeg.rs and the null fb_* test stubs deleted;
oakcommon::ffmpegutils bridge constants become plain ints
- liboakengine.dylib no longer imports any fb_* symbol (nm -u clean);
the remaining runtime imports are the host-provided oakcore_* symbols
- real decode/resample tests added (generated PCM input, no network)
- App no longer depends on the oakengine rlib: build.rs links the
built liboakengine.dylib (+rpath, -export_dynamic, IOSurface) and
src/oakui/ffi.rs declares the pure-C surface; RealEngine calls only
the frozen oakengine_* C ABI
- host_syms.rs provides the oakcore_*/fb_* host symbols the dylib
imports via dynamic lookup
- Fix Preferences dialog crash (spawn_modal reentrancy) with a
regression test
- Timeline toolbar and viewer transport render C++-era icons (16px
grid, dark/light themes) with localized tooltips
- i18n: complete en-US table, add untranslated-key detection test
- New dialogs module (preferences, export, progress)