refactor(app): cut liboakengine, link module rlibs directly (M14 R3)

- 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
This commit is contained in:
2026-08-16 23:36:43 +08:00
parent a45a7af2ac
commit 022c0a7a5a
22 changed files with 4345 additions and 4784 deletions
+11 -11
View File
@@ -20,20 +20,16 @@
//! Runs in its own test binary: the FFmpeg teardown state after a video
//! decode + an audio decode in one process crashes at exit, so the
//! waveform test stays isolated from the in-lib media tests.
//!
//! M14 R3: the extraction is a direct `oakaudio::waveform::extract` call
//! (no facade).
use oakapp::oakui::ffi::{
oakengine_waveform_extract, oakengine_testmedia_write_clip, oakapp_minmax,
};
use oakapp::oakui::waveform::{WaveformCache, MinMax};
use oakapp::oakui::waveform::{MinMax, WaveformCache};
#[test]
fn waveform_extract_and_cache_hit() {
let media = std::env::temp_dir().join(format!("oakapp_waveform_{}.mp4", std::process::id()));
let cpath = std::ffi::CString::new(media.to_string_lossy().into_owned()).unwrap();
assert_eq!(
unsafe { oakengine_testmedia_write_clip(cpath.as_ptr(), 64, 64, 10, 10) },
0
);
oakcodec::testmedia::write_test_clip(&media, 64, 64, 10, 10).expect("generate test media");
let filename = media.to_string_lossy().into_owned();
let cache = WaveformCache::new(25.0);
cache.refresh(7, &filename, 250);
@@ -52,9 +48,13 @@ fn waveform_extract_and_cache_hit() {
let _ = std::fs::remove_file(&media);
}
/// The MinMax mirror must stay layout-compatible with the oakaudio C ABI.
/// The MinMax mirror matches the oakaudio waveform point layout (two
/// f32s).
#[test]
fn minmax_layout_is_two_f32s() {
assert_eq!(std::mem::size_of::<MinMax>(), 8);
assert_eq!(std::mem::size_of::<oakapp_minmax>(), 8);
assert_eq!(
std::mem::size_of::<oakaudio::waveform::SamplePerChannel>(),
8
);
}