- Mark the raw-pointer interop entry points unsafe with # Safety docs
(oak-core upload/download/frame-from-pixels, oak-audio convert) and
satisfy the existing callers (tests).
- mut_from_ref: allow with the ABI contract documented (the handle
get_mut helpers in oak-timeline/oak-render/oak-task take the shared
reference the C ABI passes; exclusivity is the caller's unsafe
contract).
- Fix the eq_op in the white-balance normalization (green / green).
- Apply cargo clippy --fix across the workspace (redundant closures and
field names, field reassignment, items after test modules, ...).
- Revert the replace_box fix in image_effect's clip_define: a
redefinition must allocate a new box, otherwise the old clip handle
stays valid and the HS-map replace contract (clip != clip2) breaks.
- 283 warnings remain; they are all non-machine-applicable
(chunks_exact -> as_chunks needs a manual iter_mut, too_many_arguments,
complex types, missing Safety docs, ...) and are tracked as the
follow-up.
The 8.1.0 downgrade broke the build and the audio export: 8.1.0's
typed video encoder has no set_color_primaries /
set_color_transfer_characteristic, and its older audio path sent
near-NaN samples into the AAC encoder (transcode_mp4 and the oak-task
export test both failed). ffmpeg-next 9.0.0 supports ffmpeg_8_0/8_1
(the vcpkg pin of 8.1.2#3 is unaffected) and carries ffmpeg_9_0 cfg
branches for the day FFmpeg 9 lands.
254 warnings (320 counting replayed-cache re-emitters) cleaned:
unused mut/imports/variables, irrefutable if-lets and unreachable
patterns, dead code removed or annotated #[allow(dead_code)] with
the reason (C++ parity value sets, cfg(test) helpers, public API
reservations), drop(&ref) no-ops removed, fn-pointer identity via
std::ptr::fn_addr_eq, the test-stubs feature declared in
oak-node's manifest, missing docs filled. Every unused-Result site
was judged individually: meaningful errors propagate, intentional
ignores are let _ = with a note.
Two pre-existing latent bugs are documented in place, behavior
preserved: app.rs's timeline-tool observer and dialogs.rs's format
subscription both drop the returned Subscription immediately, so
they never fire.
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.
Per-chunk submit->render wait and render time (audio_thread), the push
lead against the playhead, the negotiated stream config, and the true
device-side callback rate (outputdevice) -- the ground truth used to
localize the playback starvation to the sequence-rate/clock mismatch.
Two playback-audio defects found while chasing periodic pops, clipped
words and repeated phrases:
1. The playback clocks are created at engine init with the fallback
rate (hd_1080p25) and never updated, while audio chunks are sized by
the SEQUENCE time base (30/1 from the broken default). The playhead
advanced at 25 fps but each chunk carried only 1600 samples, so
production ran at 40000 samples/s against the device's 48000 -- ~17%
of playback time was zero-filled silence (clipped words). tick() now
syncs both clocks to the sequence's actual rate.
2. The underrun self-heal cleared the whole device queue (~190 ms of
unheard content skipped), reset the prefetch (whose first
re-rendered chunk was then always dropped as late) and re-anchored
the master clock, re-rendering already-played audio whenever the
playhead lagged (audible as a pop plus a repeated phrase, every
~1.1 s). It now trims just the stale lead from the queue
(PreviewAudioDevice::drop_front_frames): the zero-fill already
advanced the output clock past that content, so the rest of the
queue stays audible and the anchor stays valid.
Also adds the OAK_DEBUG_AUDIO event log used to diagnose all of this
(prefetch resets, late drops, underruns, heals, reanchor jumps,
per-tick queue state).
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.