A tiny header naming ~1000 channels on a 64M-pixel line sized each chunk
buffer at hundreds of GB and Vec::with_capacity aborted the process.
Chunks over 256 MB are refused, and the RLE / zlib buffers reserve with
try_reserve_exact. Regression test: huge_scan_lines_are_refused_before_allocating.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Split from #728 on current main. Full validation is recorded in the draft PR; the trim and mask-modifier failures reproduce on unchanged main.
Co-Authored-By: Codex <noreply@openai.com>
Two more built-in presets follow Default in Settings > Labels > Label
Color Presets. Bright is 16 saturated hues spaced around the colour
wheel plus a gray, named Red to Gray. Roles names the labels after what
clips are (B-Roll, Footage, Dialogue, Graphics, Interview, Sequence,
Visual Effects, Bin, Titles, Music, Sound Effects, Voice-Over, Captions,
Ambience, Color Grade, Stock), ordered so the label defaults for new
video, movies, audio, stills, sequences, Dynamic Link items, bins and
captions land on the matching role. Like Default they can be chosen
and reverted to but not deleted, and an imported preset with one of
their names is renamed "<name> (imported)".
A Label Color Presets row under Label Defaults picks the 16 label names
and colours from a preset. The dropdown lists the built-in "Default"
(the labels FilmCraft ships with) and the presets in the Label Presets
folder beside the preferences, and reads "<name> (Modified)" once the
labels differ from the chosen preset. Icon buttons: Revert (back to the
preset's colours and names), Import (copies a preset file into the
folder and selects it), Export (saves the dialog's labels to a file
named as the preset), Show Folder, and Delete (user presets only).
Choosing a preset or reverting applies on OK like the other fields;
Cancel discards it.
Presets are small JSON files: a name and 16 labels, each a name and a
labels, names trimmed and at most 64 characters, valid colours); a bad
file shows its error in the dialog and changes nothing. The same is
reachable as labels.presets, labels.importPreset, labels.exportPreset
and labels.deletePreset, with the selection stored as labels.preset.
timeline.place kept a sub-frame start and rounded the duration to whole
frames, so the clip ran past time + duration and the sequence ended
between frames. The start and the end now each snap to the nearest frame,
as a timeline drag already does. sequence.inspect's durationFrames now
comes from the same frame_span export uses, so the two always agree.
Fixes#1101
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The interface had no face for Arabic or Hebrew, so caption text, track and media names showed
missing-glyph boxes in the Text panel and on the timeline while the Program monitor drew them.
crates/ui-egui/src/rtl.rs adds the craft-fonts Arab / Hebr faces, else one installed face per
script (Noto Sans Arabic, SF Arabic, Segoe UI...), as the last fallbacks of every UI font family,
as cjk.rs does for Chinese.
egui already shapes each font run with harfrust, so the letters join, but it lays runs out left to
right with no bidi pass and multi-word Arabic read backwards. rtl::Lines lays captions out in
reading order: lines are broken on the logical text as egui wraps it, each line is reordered with
unicode-bidi (UAX #9, as crates/text does for titles) and every right-to-left word is its own
layout section for egui's shaper. Caption blocks on the timeline and the Text panel caption list
use it; a caption being edited keeps egui's logical order, since TextEdit places the caret by
character index. Left-to-right text is laid out exactly as before.
Exports and rendered frames now record which offline items (missing,
made offline, unreadable) they drew the placeholder slate for. The engine
reports them as `offlineMedia` in file.exportMedia (wait), jobs.list
export entries and export.queue items; the bridge and MCP long exports
pass it through. filmcraft-cli export and render name each item on
stderr and exit 1, unless --allow-offline accepts the placeholders.
Fixes#1054
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
German (de) landed in #630: the localization parity table and the
ROADMAP language table now list it as menus only, 371 of 3,498 strings
(10.6%), native-reviewed. The localization dimension counts 2
menus-only and 5 none, and 5 of Premiere's 10 languages well and 2
partly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: .dng files were not importable, and a DNG (a TIFF) would have
gone to the TIFF decoder, which reads at best the embedded preview. A
CinemaDNG shot (a folder of numbered DNG frames) could not be edited.
Fix: "dng" joins the importable still extensions. filmcraft-media
develops DNGs with filmcraft-dng into scene-linear Rec. 709 float
frames (transfer Linear, like OpenEXR), so highlights above 1.0 reach
the compositor. A single DNG is a still; a numbered folder imports
through the existing image-sequence path as one clip, whose frame rate
and start time code come from the first frame's CinemaDNG FrameRate and
TimeCodes tags (else Settings > Media > Indeterminate Media Timebase).
Lossy and JPEG XL DNGs are refused as unsupported by name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem: camera RAW is at 0% (docs/codec-parity.md, #383). CinemaDNG,
the one cinema RAW format with a public specification, could not be
read at all.
Fix: new L0 crate filmcraft-dng, written from the public DNG 1.4-1.7,
TIFF 6.0 / TIFF-EP, ITU-T T.81 and CinemaDNG specifications only (no
other decoder's source read; editions in the crate README):
- TIFF container with SubIFDs, bounded (64 IFDs, 4 levels, cycles end
the walk) and checked offsets; the main raw IFD is the largest
NewSubFileType 0 CFA / LinearRaw image.
- Raw data: 1-16-bit uncompressed (MSB-first packing) and lossless JPEG
(process 14, predictors 1-7, 1-4 components, point transform, line
restarts), strips and tiles, tiles decoded in parallel; allocations
capped by size and by the data present.
- Processing per the DNG model: ActiveArea, LinearizationTable, per-site
black levels with deltas, white levels, as-shot white balance with
neutral highlight clipping, Malvar-He-Cutler Bayer demosaic (bilinear
for other patterns), DefaultCrop, ColorMatrix / CameraCalibration /
ForwardMatrix with illuminant interpolation, Bradford to linear
Rec. 709, BaselineExposure; output scene-linear RGBA floats.
- CinemaDNG FrameRate, TimeCodes and ReelName tags.
- A test-only writer (feature `writer`) synthesises DNGs. Tests: raw
samples bit-exact for every depth / predictor / layout, processing
against hand-computed values, hostile files (every truncation, 12k
mutations, cyclic IFDs, huge sizes, bad offsets), and LibRaw's
unprocessed_raw as an external oracle reading the same samples
(skipped when not installed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pressing Escape during an active drag in the Timeline cancels the operation without committing changes on mouse release. For ruler scrub, restores the playhead to its starting time.
While the Program or Source monitor plays and its time ruler is zoomed
in, the zoom range follows the playhead the same way the Timeline does,
honouring Settings > Timeline > Timeline Playback Auto-Scrolling: page
scrolling moves the range so the playhead is near its left edge when it
runs off the right edge or jumps before the left one; smooth scrolling
keeps the playhead in the middle; no scrolling leaves the range alone.
The range keeps its width. Scrubbing, clicking and moving the playhead
while stopped never move it.
The Program and Source monitors get a zoom scroll bar under their time
ruler, drawn like the Timeline's: drag a handle at either end of the
thumb to zoom in or out (down to five frames), drag the middle to
scroll, or press beside the thumb to move it there. The ruler then
shows only that part: playhead, markers, In/Out handles and ticks are
mapped to it, clicks and scrubs set a time within it, and anything
outside it is not drawn. Each monitor keeps its own range in its view
state (time_zoom).
The transport buttons are now 28 pt square with larger icons, spaced
6 pt apart and centred; on a narrow monitor the spacing tightens before
buttons move to the overflow menu.
Problem: the post stage of a VP9 frame (band assembly, loop filter,
publication) ran on one thread. Later frames wait per band for their
references, so the serial loop filter (~30 % of the profile) set the
pace of every inter frame; 16 threads were only ~1.8x one thread.
Fix: rows of a frame's loop filter run as a wavefront, row r two
superblocks behind row r - 1 (what the raster order of 8.8.1 allows),
taken by the post thread and helper jobs on the decoder's pool. No lock
is held while a superblock is filtered: each row filters its own band
and rows exchange copies of the 8 rows the filter reaches across a band
boundary. Output stays bit-identical; one thread / wasm run the rows in
order as before. A row is only taken by a running thread, so waits
always make progress, and helpers run under catch_unwind (a failure
publishes placeholder bands as before). New conformance fixture
narrow_tall (2 superblock columns) and a repeated multi-thread 1080p
decode test. 1.2-1.5x faster with 16 threads on a shared machine.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review on #827: a start marker left pending by any early exit (force-quit,
hang, unrelated crash, two launches racing) moved the user down a rung for
good, with no way back but deleting a file.
- Each start writes its own attempt file (graphics-start/<pid>-<n>.json)
that is removed after two painted frames, on a normal exit, or 15 s after
launch whatever happened. A later launch only counts attempts that are
older than that window, so a hang, a later crash or force-quit, and an
instance that is still starting are never failures.
- graphics-start.json now holds {mode, failures}: two failed starts in a row
in the same mode move on to the next one; a start that paints resets the
count. A wgpu start-up error still moves on at once.
- All files are written to a per-process temp name and renamed into place,
so concurrent launches never see or leave half a file.
- A fallback mode shows a notice (graphics.notice) with Use Default Graphics
(graphics.notice.reset) and Close; es, fr, ja and zh-cn strings.
- --graphics default|dx12|software picks a mode by hand and keeps it;
`--graphics default` undoes a fallback. Modes this platform lacks are
refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ffmpeg's CLI handles Matroska priming differently by version: 9.x trims
CodecDelay, 2023-24 static builds keep the priming samples (AAC 1024,
AC-3 / E-AC-3 256, MP3 1105), so a +-40-sample best-lag search against
its decode landed on a spurious minimum (4 or 24 samples).
matroska_audio_oracle now has ffmpeg encode a reference signal we
generate (low-passed xorshift noise) and asserts our decode lines up
with that signal to the sample, the stream's own CodecDelay trimmed:
version-independent, and it fails on the old ms-rounded trim (-16).
ffmpeg's decode is compared after a best-lag search bounded by the
CodecDelay; its lag is reported, the waveform must match (< 1e-3).
E-AC-3 joins the cases. eac3_oracle's .mkv case accepts lag 0 or the
256-sample priming; MP4 / MOV / TS stay strictly at lag 0.
Verified with ffmpeg 9.0.2 and the static N-71064 (2024-06) build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>