The two BlockCore length setters swapped their anchors relative to the
C++ semantics they document, so the ported edit commands produced wrong
geometry on the live UI paths: roll edits kept the seam still, slides
left negative in-points, and trims wrote the timeline in-point into
media_in (playing the wrong media content).
Adopt three stored-range primitives in block.rs:
- set_length_and_media_out: in fixed, out moves, media untouched
(resize, trim-out, gaps growing rightward).
- set_length_and_media_in: in fixed, out moves, media_in += old-new
(resize-with-media-in, splice right half, ripple trim-in).
- set_length_keeping_out (new): out fixed, in moves, media_in +=
old-new (trim-in body and out-neighbour, slide out-neighbour,
ripple trim-in of the trailing block).
Point every command at the primitive matching its intent (undopointer,
undogeneral, undoripple, undosplit, graphops, cli, nodeops) and fix the
two real defects the swap hid:
- TrackReplaceBlockWithGapCommand grew a following gap rightward,
swallowing whatever followed it: the "dragging one clip moves
unrelated clips" regression. The gap now grows leftward over the
removed block's span; regression test in domain_test.
- The ripple/splice trims now advance media_in instead of rewriting it,
and BlockSplitCommand writes both halves' ranges and media
explicitly (the second half continues from the split point).
Rewrite the KNOWN-SWAP expectations to the correct geometry (roll moves
the seam, slide has no negative in-point, insert-gaps grows rightward,
resize-with-media-in yields media_in = 20) and add the missing media
assertions. TrackSlideCommand documents that the caller positions the
sliding blocks (the stored model has no track layout).
Adds VAAPI DMA-BUF, D3D11VA shared-handle and VideoToolbox IOSurface
imports behind a tri-state outcome (imported / unsupported / failed),
planar textures with bounded residency and a CPU staging fallback, the
staged montage decode path, reference-counted decoder frames, VAAPI-first
device selection on Linux, and the host-GPU context plumbing used by the
app and worker. See docs/zh/plans/render-pipeline-threads.md (M5).
Adjustment layers (docs/zh/plans/adjustment-layers-and-transitions.md):
a new timeline block type whose effect chain grades the composite of
every video track below it, over its own range (spanning clips or a
slice of one). The graph path flushes the lower tracks at the block's
track boundary and sweeps the composite through the chain via a
transient texture-source node; the montage path mirrors it with
AdjustmentSpan tickets (wire-compatible), so worker previews and
exports agree. An empty-area context menu creates one; the block
trims/moves/deletes like a clip, with undo everywhere.
Transitions: seam blocks come alive - cross dissolve/fade/wipe/slide
evaluate both neighbors through the graph path with progress from the
transition's own range (never the whole clip). Ctrl+Shift+D or the clip
menu inserts a default transition; the gpui wedges render and drag to
resize offsets undoably, and TransitionRemoveCommand now restores
offsets and edges on undo. The transitionfx node form runs the same
shaders on an adjustment layer with progress_in auto-filled from the
layer's span (explicit value wins).
Also: every built-in effect name and parameter name is now
translatable (360 node.* keys per locale, zh-CN fully translated, two
coverage tests guard future gaps); the new nodes register in
nodes/mod.rs with the factory smoke table updated; textfootage and
adjustment-layer i18n keys included.
- available_range declared a zero duration for every clip (the media
was 'unusable', so Resolve invalidated all of them): it now covers
the whole media - video clips in the probed frame rate, audio clips
in the probed sample rate (no more hardcoded 48000/0).
- Gap ranges mixed time bases (a 24 fps block start, a 1.0 trailing
duration): gaps now stay in the sequence's time base, the trailing
pad in whole frames.
- Empty sequences (no clips) are skipped, so a lone edited sequence
exports as a bare Timeline root instead of a SerializableCollection
Resolve cannot read.
- FCPXML: an asset used on both video and audio tracks now declares
hasVideo AND hasAudio (the first registration's track kind used to
hide the other stream); asset durations recover with available_range.
oak-common is gone; its modules (configstore, xmlutils, ocioutils,
oiioutils, colormath, colortransform, videoparams, ffmpegutils, ...)
now live in oak-core alongside the value types. The render value/GPU
types moved too: backend (wgpu context + DisplayRenderer), color
(ColorProcessor over ocio-rs), texture, frame, and the commonutil
config helpers.
Fix-ups to make the merged tree build and pass tests:
- oak-core Cargo.toml: wgpu back to 25 (the moved backend code is
written against that API generation); add the toml/quick-xml/image
deps oak-common carried.
- lib.rs: drop the duplicate 'pub mod error;'.
- error.rs: unified OAKCORE_* codes; restore Error::new() and
From<OcioError> from oak-common's error type.
- backend.rs/color.rs: oak_core::/oak_render:: self-references
rewritten to crate::; the shaderfx-dependent GPU effect test moved
to oak-render's shaderfx tests (shaderfx depends on oak-node and
cannot live in oak-core).
- oak-render's error module re-exports oak_core::error::{Error,
Result}; the OAKRENDER_* codes stay as the public-code contract.
- oak-node jobs.rs: ColorProcessor imported from oak_core::color.
- Integration tests repointed at oak_core::{texture, frame, backend,
color, colormath}.
- the display-ICC regression test treats an empty OAK_DISPLAY_ICC as
unset, matching displayicc::env_override_icc.
- File > New > Sequence opens a real dialog (name, PAL/NTSC/HD presets,
width/height/frame rate, progressive/interlaced); VideoParams gains an
interlaced flag
- File > New > Folder creates a folder in the project root
- sequences are mounted under the root folder so they appear in the
project explorer (including the auto-created Sequence 1 and orphans
from older projects); right-click > Sequence Properties edits the
parameters afterwards
- dropping footage onto an empty, sequence-less timeline auto-creates a
sequence from the footage's first video stream
All crates take the oak-* kebab-case naming (oak-audio, oak-codec,
oak-common, oak-core, oak-ffmpeg-link, oak-node, oak-otio, oak-plugin,
oak-render, oak-storage, oak-task, oak-timeline, oak-undo), with the
lib identifiers rewritten (oakrender:: -> oak_render::, oakcore_rs:: ->
oak_core::, ...) across all 226 referencing files.
The GUI application moves from the workspace root into
crates/oak-app/: src/, build.rs (paths fixed for the new location) and
tests/ travel with it, the root Cargo.toml becomes workspace-only
([workspace] + workspace.package + profiles), and the app package
inherits the workspace version. The screenshots example becomes a
standalone crate examples/simple_player/ with its own Cargo.toml.
Every crate now inherits the single workspace version
(version.workspace = true), and the workflows' crate paths and the
build docs follow the renames.
Validated with a clean cargo check --workspace.