Files
oak-editor/crates/oak-cli
Mike-Solar f2aab8ce15
CI / Build & test (Windows) (push) Failing after 16m26s
CI / Build & test (Linux) (push) Successful in 19m12s
render: apply clip effect stacks in the montage path
Adding an effect to a clip did nothing: the sequence render is
flattened into a montage (decode + composite), and MontageClip carried
no effect data at all.

- MontageClip gains an ordered effect stack (type id / enabled /
  effect input / parameter values); protocol v2 carries it as an
  additive wire field (older peers default to an empty stack).
- renderops::video_montage fills the stack from the effect chain
  (the footage source node — the chain end without an effect input —
  is dropped; the montage decodes the footage itself). Export
  (oak-task) and the multicam single-track montage fill it too.
- The worker applies the stack between decode and composite: built-in
  Opacity gets a CPU evaluator (C++ opacity.frag parity — whole vec4,
  alpha included, unity pass-through); everything else dispatches as an
  OFX plugin job through a new instance-factory slot (oak-plugin
  lazily creates + caches one instance per identifier per render
  process) with the montage's parameters injected. Disabled effects
  bypass (the C++ traverser pushes the effect input through). Unknown
  types warn once per type id and pass through — no silent no-ops.

Not covered (explicitly): Transform/Crop and the other ~30 built-in
effects have no CPU evaluator in oak-render (they pass through with a
warning), keyframed parameter animation, audio effect chains, and the
CLI's simplified montage.

Acceptance: a real 50% Opacity on real media quarters the rendered
pixels both in-process (renderops test) and through a real worker
process over IPC + shared memory (procpool_integration test);
disabling restores the plain render byte-for-byte.
2026-08-25 04:49:00 +08:00
..

oak-cli (Rust)

Headless command-line consumer of the oak editor module crates — the Rust rewrite of cli/main.cpp (which stays in the tree until cutover). Same subcommands, same output format, same exit codes:

exit meaning
0 success
1 general error (bad project/media file, no sequence, I/O failure)
2 rendering unavailable or failed (e.g. no render backend)
64 usage error

Build and test

cargo build --release      # binary: target/release/oak-cli
cargo test                 # unit + integration tests

The crate is self-contained (M14 R2): it links the oak* module rlibs directly (oaknode, oaktimeline, oakcodec, oakrender, oaktask, oakcommon) — no liboakengine dylib, no C ABI, no build.rs link step. cargo test -p oak-cli stands alone.

Subcommands

Every subcommand of the C++ original is implemented:

oak-cli info <project.ove> <start> <end> <out_dir>   project name/sequences/footage
oak-cli render <project.ove> <start_seconds> <end_seconds> <out_dir>
oak-cli probe <mediafile>
oak-cli transcode <input_media> <out> [width] [--format ppm|mp4]

Argument validation is faithful to the C++ (invalid start seconds, invalid width, unknown --format … all exit 64). The output formatters (src/fmt.rs) reproduce the C++ printf output byte for byte and are golden-tested against the output captured from the C++ binary on the test fixtures (tests/project_with_footage.ove, tests/demo.mp4); the PPM and WAV writers (src/ppm.rs, src/wav.rs) are the exact ports of the C++ write_ppm/write_wav and are unit-tested.

Layout

src/
  main.rs     clap surface, --help/-h + unknown-command handling, dispatch
  engine.rs   module-native assembly layer (M14 R2): project load/create,
              footage probe, sequence + clip assembly, montage resolution,
              ticket rendering, synchronous export
  fmt.rs      golden output formatters (info/probe)
  ppm.rs      P6 PPM writer (f32/u8 frames)
  wav.rs      PCM s16 WAV writer (interleaved float samples)
  cmd/        per-subcommand validation + module-crate calls
tests/cli.rs  binary-level tests (exit codes, messages, usage errors)