Found while testing crates/interchange/src/edl.rs:118 (parse_event_line, num_at parsing as i64) and :498 (import_event, tick_of(l2.dur))
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
* M3: Add shared custom colors and complete marker editing
* #1435: refine native colors and range endpoint flags
Use the macOS Colors panel for custom label colors and reuse the established egui picker on other hosts. Preserve draft confirmation, exact sRGB values, native text shortcuts and project ownership. Compact the swatches and center the add control, split range glyphs across their endpoints, localize the new controls, protect newer marker edits from stale dialogs, and cover the behavior with rendered UI and hit-test regressions.
Co-authored-by: Codex <noreply@openai.com>
* #1435: preserve imported palettes and marker double-click ownership
Union saved OTIO palettes across timelines with deduplication, bounded capacity,
first-name preservation and explicit overflow warnings. Keep null authors
consistent with omitted fields, and consume marker double-clicks before the
work-area gesture so opening the editor does not alter project history.
Correct the CSV URL column and schema documentation. Add six regressions for
palette retention/capacity, author handling, and physical overlapping gestures.
Validation: full cargo xtask ci (3666 passed, 45 skipped), 42 rendered UI tests,
and strict workspace/all-target Clippy on Rust 1.99.1.
Co-authored-by: Codex <noreply@openai.com>
* #1435: retain OTIO swatch names and generator labels
Ignore orphan name entries when retaining saved palette names so input ordering
does not hide valid names after the first 64 entries. Keep names bounded by the
retained palette and preserve existing valid names.
Include generator preset labels alongside custom label colors in OTIO metadata.
Add regressions for orphan-prefixed name maps and three generator kinds with
preset/custom colors through actual export/import round trips.
Validation: both regressions failed before fixes; all 72 interchange tests and
full cargo xtask ci pass (3668 tests, 45 skipped), plus strict workspace/all-target
Clippy on Rust 1.99.1.
Co-authored-by: Codex <noreply@openai.com>
* #1435: preserve distinct OTIO generator item identity
Use exported FilmCraft item IDs for generator media identity so identical
content can retain distinct source names, labels and custom colors. Repeated
references to one source item still share a single imported media entry.
Preserve content-based fallback for missing or invalid item IDs. Cover black
video, bars and tone, and color mattes with distinct items/shared references,
plus legacy and malformed identity metadata.
Validation: distinct-generator regression failed before fix; legacy compatibility
passed. All 74 interchange tests and final full cargo xtask ci pass (3670 tests,
45 skipped); strict workspace/all-target Clippy also passes on Rust 1.99.1.
Co-authored-by: Codex <noreply@openai.com>
* #1435: align Edit Marker layout and add safe marker navigation
Give the editor a wide aligned form, larger Notes area, side action column,
and grouped palette with vertical marker types. Expand the Web Link field
with the form and keep actions accessible in small windows.
Previous/Next saves valid edits as one Undo step and stays with the original
sequence/source owner, including coincident markers. Invalid drafts stay open;
unchanged navigation and Done add no history. Keep native/shared color pickers,
Author, Notes, URL validation and immediate marker creation.
Validation: all 45 rendered sequence/marker UI tests pass, including five new
navigation/owner/validation/layout regressions. Native macOS layout, picker
Cancel and exact single-step Undo restoration verified. Full standard cargo
xtask ci passes 3675 tests (45 skipped), doctests and all remaining gates;
strict Rust 1.99.1 workspace/all-target Clippy also passes.
Co-authored-by: Codex <noreply@openai.com>
* #1435: refine Edit Marker proportions and action alignment
Narrow the dialog to 680 logical pixels and keep the core order Name,
Time/Duration, Notes, Color and marker type. Place Author after the type-specific
options as secondary metadata. Preserve our palette, custom picker and range controls.
Use consistently sized, centered rounded action buttons with a primary Done action.
Shorten Delete Marker to Delete and remove the navigation helper and unused translations.
Keep the existing navigation save/validation/Undo semantics and automation IDs.
Validation: all 45 rendered marker/sequence UI tests pass, including small-window
action accessibility. Actual macOS layout and no-op Previous/Next/Cancel verified.
Full standard cargo xtask ci passes 3675 tests (45 skipped), doctests, formatting,
Clippy, translations, layers, assets and 49 WASM crates. Strict Rust 1.99.1
workspace/all-target Clippy passes separately.
Co-authored-by: Codex <noreply@openai.com>
* #1435: tighten marker layout and validate text editing
Use a narrower aligned form with Author below Name, bounded scrolling Notes,
left-aligned colors, centered actions and an inline Web Link URL/open icon.
Remove the legacy Flash Cue choice while preserving imported marker types.
Constrain timecode typing/paste to complete numeric colon-separated fields,
validate drop-frame labels and frame bounds, and disable Done for invalid timing.
Preserve high-frame-rate timecodes and point-marker semantics when Duration is
unchecked. Route native/menu clipboard and text Undo commands to focused fields;
explicit engine commands retain project Undo and selection semantics.
Validation: standard cargo xtask ci passes 3679 tests (45 standard skips),
doctests, fmt, strict workspace/all-target Clippy, i18n, layers, 69 assets and
49 WASM crates. Also passed 48 rendered marker/sequence tests and strict Rust
1.99.1 Clippy. Actual macOS clipboard, bounded Notes, point save and exact Undo
were checked. Windows/Linux desktop interaction remains pending.
Co-authored-by: Codex <noreply@openai.com>
* M0: Wait for frame-worker recovery before asserting
Do not treat a nonempty request queue as proof of worker death in the
panic-recovery regression. Keep waiting for all injected faults and enough
post-fault completions, then drain the queue without adding more seeks.
Retain the exact fault-count, successful-recovery and empty-queue assertions
and bound the wait with a two-minute deadline.
The inherited test failed twice in independent fork CI. It did not reproduce
locally: baseline passed 20 normal and 10 delayed-report runs; the repair
passed 50 normal and 10 delayed-report runs. No product or marker UI changes.
Validation: standard cargo xtask ci passed all 4485 tests (52 standard skips),
doctests, formatting, strict workspace/all-target Clippy, i18n, layers,
69 assets and 49 WASM crates.
Assisted-by: OpenAI Codex
---------
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <codex@openai.com>
Import standalone video elements as picture-only clips, retaining media
paths, timing, adjustments, markers, transitions and connected placement.
Warn when a video references an unsupported generator or source.
Add synthetic importer and engine regressions covering zero-duration still
assets, missing-media relinking, save/reopen, undo/redo and rendered pixels.
Document the FCPXML 1.10 specification and supported behavior.
Validation: interchange tests and the engine slideshow regression pass,
as do scoped Clippy, formatting, layers, assets and WASM. Full CI on Rust
1.95 stops at the existing ProRes nonminimal_bool lint; unrelated CI
repairs are excluded from this change.
The reporter's original XML imports all 55 slides, 54 transitions and
55 media items in a temporary local check; reporter files are not included.
Fixes#2837
Co-authored-by: Codex <noreply@openai.com>
* Tests: one integration-test binary per crate
Each crate with several tests/*.rs files keeps them as modules of tests/it/,
so cargo links one test executable per crate instead of one per file. Files
that change process-wide state or time a workload stay binaries of their own.
* Profiles: line tables for workspace crates, no debug info for dependencies
* Windows ARM64: nightly and on release pushes instead of every push to main
* xtask ci: clippy and tests in the dev profile
The release profile's thin LTO and single codegen unit made linking the test
binaries take most of the gate. The codec and audio crates stay at opt-level 3
in the dev profile, so their tests run at release speed.
* xtask ci: nextest, doctests, no examples, one wasm check
Tests run with cargo nextest when it is installed (cargo test otherwise) and
build with --lib --bins --tests, so examples aren't linked; doctests run
separately. The wasm check keeps going past the first failing crate. VP8
fixture generation locks across processes, since nextest runs each test in
its own.
* VP9 synthetic fixtures: write aside and rename
A test in another process could read a fixture ffmpeg was still writing.
* Fuzz tests: a third of each sweep by default, all of it with FILMCRAFT_FUZZ_ITERS
Every seed, mutation kind and thread count still runs. Header bytes each get
one overwrite value and two bit flips in rotation, so every value and bit
index still occurs across the region. FILMCRAFT_FUZZ_ITERS=N runs the whole
sweep plus N random rounds per seed, as before.
* Platform fallback tests: one failure point per hybrid path
The failure-anywhere test injected a failure at four points around every
restart point; the hybrid's paths differ only in the first GOP, around the
second and last restart points, at the end and never. The replay test needs
the first two GOPs.
* Export tests: shorter ranges with the same checks
The bitrate test measures 0.5–1.5 s, where each preset reaches its own
target (on 0–3 s the simple demo left two presets at the same rate). The
every-preset test exports three frames per preset.
* Audio tests: effects in parallel, a table-driven FFT for the Opus quality metric
The extreme-settings test keeps both settings and the 40 s tail for every
effect, one thread each. The Opus quality metric's FFT builds its twiddles
once and allocates nothing per transform (same algorithm and summation order).
* CI: dev-profile gate with nextest
xtask ci no longer builds with --release, so the release-profile overrides
go; nextest is installed for the test step.
* CI: apt packages through the cached install-apt-packages action
* Review fixes: fuzz tests with a panic hook in their own binaries, loud fixture lock
The fuzz tests of av1, h264, hevc, mpeg2v, vp8 and vp9 count panics through
a process-wide hook, so a panic in another test of the same process would
fail them; they are binaries of their own again. The VP8 fixture lock fails
the test instead of skipping it silently, and the full-sweep doc comments say
how many truncation points the full run samples.
* Fuzz tests: rotate the default subset per run (FILMCRAFT_FUZZ_SEED replays one)
* platform tests: decode-switch tests in their own binaries, one NVENC lock
Bounded item_path, item_media, and base_item in interchange helpers
and ale::export_items with a 16-step bound matching crates/project.
Cyclic subclip chains (self-referencing or mutual cycles) and overly
deep chains now terminate safely without causing a stack overflow abort.
Closes#2788
Found while testing crates/interchange/src/common.rs:68
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/interchange/src/xml.rs:7 (escape, used by start_tag for attributes)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
CodeRabbit review: import_with returns early for AAF and OMF, so the
shared bound_start_timecodes pass never ran for them and an AAF with an
absurd start timecode kept it. The AAF and OMF importers now run the
pass themselves (the test fails without it for AAF; OMF carries no
sequence start timecode).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Review feedback: note that Tick has no Mul and its Add/Sub saturate, so
this one saturating multiply closes the whole class, and why it
saturates at the i64 bounds rather than Tick::MAX.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Review feedback: the FCP7 timebase clamp and the OTIO rate fallback happen
while parsing, so the post-import pass saw a plausible rate and said
nothing; only the FCPXML path warned. Each importer now checks the
document once and warns when a timebase or rate is beyond the limit
(OTIO's warning names audio sample rates such as DSD, which are above it).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
FCPXML src, FCP7 pathurl and OTIO target_url are URLs, but only file://
ones were decoded: a relative src="Clip%20A.mov" looked for a file
literally named Clip%20A.mov. Relative URLs are now decoded too (plain
names from EDL / AAF are not), and the OTIO exporter writes its relative
target_url percent-encoded so a name with % or spaces round-trips.
The web relink fallbacks the issue also asks for stay open.
Refs #2195
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OTIO has no references, so every use of a nested sequence is written in full.
Compound clips that each hold several uses of the next make that exponential:
a 3 KB FCPXML whose media nest 12 deep with 3 uses each imports as 14 items and
then makes the OTIO export run for minutes and grow to gigabytes (depth 5 is
216 MB, about 7x more per level), until memory runs out. The other formats
reference nested sequences and stay instant.
The exporter counts clips written inside nested sequences; after 25 000 (about
250 MB of JSON, far above real projects) further nested sequences are written
as gaps, with one warning. The depth-12 document now exports in seconds under
a 4 GB memory cap.
Regression tests lower the limit to keep the document tiny: without the check
all 112 stacks are written; an ordinary project is untouched.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
scaled() multiplied a duration by an integral speed with a plain `*`. An EDL
with a record-out timecode of 2147483647 hours and an `M2 ... 72.0` speed
change overflowed it (attempt to multiply with overflow, a panic in debug
builds, wrapped time in release). The same function serves the FCP7, FCPXML
and OTIO importers, so mutation fuzzing hit it from all four text formats.
The multiply saturates, like Tick's own arithmetic.
Regression tests: the EDL imported and exported in every format
(tests/edl.rs) and scaled() unit assertions; both panic at common.rs scaled
without the fix.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An importer accepted any positive frame rate and any start timecode. A rate
near i64::MAX per second (an FCPXML frameDuration of 1/9223372036854775807s,
an FCP7 timebase of 9223372036854775807) made frame_at clamp to i64::MAX, and
frames_round overflowed adding 1 on export as soon as the sequence had a start
timecode or a marker; an NTSC timebase overflowed multiplying by 1000 on
import. An FCP7 <frame>18446744073709551615</frame> start timecode saturates
to i64::MAX and overflowed the EDL export's rec_frames.
Rates are limited to 1 000 000 per second (far above video and the 192000 Hz
OTIO audio uses, far below the overflow): the FCP7 timebase is clamped, an
OTIO rate beyond it uses the default, and one pass after every import resets a
sequence or media rate beyond it, and start timecodes beyond 360 000 000 000
frames, with a warning in the report. The pass covers every format, so
fcpxml.rs is not touched.
Regression tests: tests/rates.rs (FCPXML absurd frameDuration, every export
format) and tests/fcp7.rs (absurd timebases with and without ntsc, absurd
start timecode). With the limits lifted they panic in frames_round, in the
NTSC multiply and in edl.rs rec_frames.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found while testing crates/interchange/src/edl.rs:211-216 (parse, AUD handling; consumed by Ctx::track_index/lay at :341-380 and Builder::ensure_tracks in common.rs:411)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>