Commit Graph

189 Commits

Author SHA1 Message Date
Brandon Thomas f5aa00ff7d Merge branch 'main' into worktree-agent-aacf40607c4b686e0
# Conflicts:
#	xtask/src/main.rs
2026-10-02 13:01:34 -04:00
Brandon Thomas 1f6562c08a M4.8: HEVC transform/SAO speed-up, catch-up decoding, perf.stats
- HEVC inverse transform: sum basis rows of non-zero coefficients with a
  const-generic size (bit-exact, tested against the direct product);
  SAO edge offset gets a check-free interior loop. HEVC CPU/frame -60%.
- H.264/HEVC/VP9 planes are moved into VideoFrames, not copied.
- Catch-up decoding: frame jobs tell sources which frames are late
  (filmcraft_media::cancel::with_catch_up); the GOP cache skips
  non-reference samples of late frames (H.264 nal_ref_idc 0, HEVC
  sub-layer non-reference pictures). Scrubs keep the last 2 s decoded.
- perf.stats: engine query + UI/control method (decode counters,
  playback shown/dropped, frame-worker decode/render ms, cache use).
- Timeline waveform source peak cached; bench seek section and --only.
- docs/performance.md with before/after results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 13:01:16 -04:00
Brandon Thomas 4a931a3400 app icon: owl with ear tufts (owner's ArtCraft drawing), Dock/taskbar/launcher wiring, palette docs
- assets/app-icon/: canonical SVG + light SVG, 1024 PNG, macOS runtime PNG, .icns, .ico,
  hicolor theme, LICENSE.txt and README (palette, geometry, provenance, regeneration).
- packaging/icons.sh regenerates everything with resvg, iconutil and the new `cargo xtask ico`.
- Native app sets the window icon (with_icon) and the Wayland app id; build.rs embeds the .ico
  and VERSIONINFO into filmcraft.exe on Windows (winresource, Windows-host build-dep only).
- packaging/linux/ai.storyteller.filmcraft.desktop with Icon=ai.storyteller.filmcraft.
- Web app: favicon.svg replaced by favicon.png from the same artwork; sidecars and
  ATTRIBUTION.md updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:52:46 -04:00
Brandon Thomas f5ac5989f0 Merge branch 'worktree-agent-a7d751de0d72abab7' into worktree-agent-a6d2cbb6d6b3e5d7a
# Conflicts:
#	crates/edit/src/lib.rs
2026-10-01 23:31:39 -04:00
Brandon Thomas fc18a6962e M10.5: Text-based editing / transcripts
- crates/speech (L2): Transcriber trait, FixedTranscriber, Whisper model catalogue (pinned,
  SHA-256 verified) with optional downloader (feature `download`: ureq + rustls + RustCrypto),
  pure-Rust Whisper inference on candle with word timestamps (feature `whisper`), log-mel, VAD
  word tightening, MFCC speaker clustering. Both features off by default and for wasm.
- project: per-media-item transcripts (Project::transcripts); schema v9 with a no-op v8->v9
  migration and a v8 fixture.
- edit::transcript: sequence transcript derived from clip transcripts, search, paragraphs,
  word ranges, pause/filler detection, ripple delete of many ranges, caption layout.
- engine: transcript.* commands (generate, set, delete, inspect, search, select, extract, lift,
  renameSpeaker, removeFillers, removePauses, createCaptions, models, downloadModel);
  Session::transcriber for hosts/tests; features `whisper` / `speech-download` (also on the
  desktop and CLI apps). Without whisper, transcript.generate fails with a clear error.
- ui: Text panel Transcript tab (Transcribe button, speaker paragraphs of clickable words,
  Shift+click selection -> In/Out, extract/lift/remove fillers/create captions, search) with
  text.transcript.* automation ids; headless UI test.
- docs/transcripts.md, crates/speech/README.md, architecture and project-files updates.
  whisper-tiny measures 12.2% WER over 797 words on local samples.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 23:25:49 -04:00
Brandon Thomas bf67521c4d Merge branch 'main' into worktree-agent-a047c9696e3105eec 2026-10-01 20:43:25 -04:00
Brandon Thomas 243e95ab24 M13.1: wasm groundwork: range readers, pending reads, cooperative frames, stepped export
- filmcraft-media: ByteReader/ReaderOpener (open containers without reading the whole
  file) and the pending flag for asynchronous (web Blob) reads.
- filmcraft-codecs: MP4/MOV and Matroska open from a ByteReader; registry of reader
  openers (platform sources first).
- filmcraft-engine: Services::reader / export_in_memory; streamed imports; media pool
  never caches a still-loading file as offline; Session::pump_jobs advances stepped
  exports on hosts without threads.
- filmcraft-export: Exporter (one batch per step, re-renders on pending reads) used by
  export(); OutputSink for in-memory output.
- filmcraft-ui-egui: FrameServer::pump (time-budgeted cooperative frame jobs on wasm,
  retries jobs whose media is loading); screenshots as base64 on wasm; web-time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:50:06 -04:00
Brandon Thomas fef248a527 M9.7: AV1 decode statistics (per-stage busy time) and perf test with stage breakdown
Decoder::stats() reports frames, tiles and the busy time of setup, tile decoding,
deblocking, CDEF, superres, loop restoration and output. The ignored perf test
measures single-threaded throughput with the thread CPU clock (robust to machine
load), prints ms/frame per stage, and the all-cores wall-clock rate next to the
load average. Adds high-quality and 4x2-tile 1080p fixtures. Decoder::with_threads
and flush() are added as the API the threaded decoder will use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 14:07:55 -04:00
Brandon Thomas dc9c5fd32c Merge branch 'main' into worktree-agent-a98dbfec8c9b949c7 2026-10-01 13:06:51 -04:00
Brandon Thomas 645cfd9ad1 Merge branch 'main' into worktree-agent-a98dbfec8c9b949c7 2026-10-01 12:50:04 -04:00
Brandon Thomas 44f93d615c Merge branch 'main' into worktree-agent-ac059806d5abf3b44 2026-10-01 12:46:50 -04:00
Brandon Thomas 7095a986ff fix: control channel never steals keyboard focus — UI requests and screenshots bring the window forward without activating the app (orderFrontRegardless); --control launches without activation; only ui.focus activates
Agents' ui.* requests used ViewportCommand::Focus, so the user's typing in another app landed in FilmCraft as shortcuts (stray Extract, Mark In/Out, markers…). Verified live: the frontmost app stays frontmost through launch, ui.click, ui.key and ui.screenshot, and the requests still take effect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:53:19 -04:00
Brandon Thomas 35a2d2a861 M9.7: AV1 import from MP4 (av01/av1C) and Matroska/WebM (V_AV1)
Av1Decoder in filmcraft-codecs: feeds the av1C configuration OBUs before the
first sample (and after every reset), converts pictures to 8/16-bit planar
YUV with the stream's colour description, and reports random-access points
from the first frame header of each temporal unit (shown key frame) so GOP
seeking ignores bogus container sync flags. Matroska V_AV1 tracks map to an
av01 sample entry; MP4 labels show the AV1 profile.

All-intra 8-bit MP4 and 10-bit WebM files seek sample-exactly against
libdav1d. Inter frames still return "unsupported" until inter prediction
lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:18:49 -04:00
Brandon Thomas 1813bbaca2 M9.7: AV1 headers, symbol decoder, CDFs, intra decoding, transforms, intra prediction
New L0 crate filmcraft-av1 from the AV1 Bitstream & Decoding Process
Specification v1.0.0 with Errata 1 (tables extracted from the spec's Markdown
source by tools/extract_tables.py).

Stages: OBU parsing, sequence and uncompressed frame headers (all fields),
reference state (set_frame_refs, load_previous, reference update,
show_existing_frame), symbol decoder with CDF adaptation and
init/load/save/frame-end CDF handling, tiles, intra frame mode info
(partitions, segment ids, delta q/lf, CDEF index, modes, angle deltas, CfL,
palette, filter intra, tx size), coefficient decoding, dequantisation,
inverse transforms (DCT 4-64, ADST, identity, WHT), intra prediction (all
modes, edge filter/upsampling, recursive filter, CfL, palette), LR syntax.

All-intra libsvtav1 streams with in-loop filters disabled decode bit-exactly
against libdav1d (8/10-bit, 128x128..1280x720, odd sizes, presets 2-8).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:00:03 -04:00
Brandon Thomas 226c139741 M9.6: DNxHD/DNxHR (SMPTE ST 2019-1 VC-3) decoder and DNxHR encoder
New L0 crate filmcraft-dnx, written from SMPTE ST 2019-1:2016 + Amd 1:2023
(tables extracted from the standard's text by tools/extract_tables.py).

Decoder: every compression ID (DNxHD 1235-1260 incl. field-coded and
macroblock-adaptive interlace, thin rasters, RGB 4:4:4; DNxHR 1270-1274
LB/SQ/HQ/HQX/444), 8/10/12-bit, 4:2:0/4:2:2/4:4:4, DCT and lossless alpha,
macroblock rows in parallel. Matches ffmpeg within IDCT precision (max 2 LSB,
<=50 per million beyond 1, 87-99% identical) on 22 ffmpeg fixtures; follows
ffmpeg where it departs from the standard's text (reconstruction offset,
CID 1271 weights, 4:4:4 signalling) - documented in the README.

Encoder: DNxHR LB/SQ/HQ/HQX(10/12-bit)/444, CBR at the eq. 7.1 frame sizes,
uniform-qsf binary search + per-macroblock refinement; ffmpeg decodes every
profile with -xerror (HQ luma PSNR 58.8-66.3 dB).

Wiring: MOV AVdn/AVdh import (codec label from the CID), export
Format::DnxHr (MOV AVdh, dnxProfile lb|sq|hq|hqx) in the export dialog and
file.exportMedia.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:53:02 -04:00
Brandon Thomas fbaf487237 M5.5: effect masks (ellipse / 4-point polygon / pen Bezier) with keyframable path, feather, opacity, expansion, inverted, modes; opacity masks; WGSL coverage parity; on-monitor editing
- project:😷 MaskPath (cubic Bezier, clip pixels) as ParamValue::Path (vertex-wise keyframe interpolation), Mask, MaskMode, TrackMethod; schema v7 (no-op migration)
- render:😷 analytic antialiased coverage via signed distance + feather falloff in linear light; masked effect = lerp(original, effected, coverage); opacity masks before Motion; adjustment layers
- gpu::GpuMask: same coverage + mix in WGSL compute (max |cpu-gpu| ~3e-6)
- engine masks.* commands (add/remove/set/moveVertex/translate/addVertex/removeVertex/toggleVertexSmooth/select/list); keyframe commands take "mask"
- UI: Effect Controls mask rows; Program monitor overlay (vertices, handles, feather/expansion handles, body drag, pen tool) with automation ids
- goldens: mask_blur, mask_color, mask_inverted, mask_opacity

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:48:47 -04:00
Brandon Thomas 9f4208bb08 Merge main into M11.7–9 (relink, proxies, project manager): GopCache keeps main's continuation algorithm with a same-thread reentrancy guard (nested rayon requests decode privately instead of deadlocking); ProRes export combines profile choice with HDR signalling; project schema v6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:19:19 -04:00
Brandon Thomas a1cc0a6838 M11.9: proxies (create / attach / toggle / reconnect) and ingest settings
- media.createProxies: background job (jobs.list progress) transcoding with our own
  encoders — ProRes 422 Proxy ¼/½, ProRes LT ½, H.264 ¼/½ (audio included) — into
  <media dir>/Proxies or a chosen folder; attached when the job finishes
  (Session::poll_persistence applies finished media jobs).
- media.attachProxies (duration ±1 frame and frame rate must match; size/aspect may
  differ), media.detachProxies, media.reconnectFullRes, media.toggleProxies
  (Preferences ▸ Media ▸ enableProxies; bumps the view revision without dirtying the
  project), media.proxyPresets.
- Proxy frames are smaller; ProxySource reports the original size and the compositor
  derives its pixel scale from the frame, so Motion and effects render the same
  picture (44 dB PSNR vs full res with Motion + Gaussian Blur, 48 dB at ½).
  Export always renders full resolution.
- ExportSettings::prores_profile (proxy / lt / standard / hq).
- project.ingestSettings + file.import: copy (fingerprint-verified), transcode,
  create proxies, copy and create proxies.
- UI: Toggle Proxies button on both monitors (lit when on), Create Proxies dialog,
  Project panel Proxy submenu and P badges.
- Measured (one core, 4K H.264 testsrc2): CPU composite 201 → 35 ms/frame at ¼ with
  ProRes Proxy ¼, 277 → 131 ms at ½ with H.264 ¼; decode 9.2 → 0.7 ms with H.264 ¼.
- Tests: create+attach+toggle same composite modulo scale, attach checks, export
  ignores proxies, ingest copy + proxies, ignored 4K benchmark, headless UI test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:06:56 -04:00
Brandon Thomas a9af6fac71 Merge M8 (LUTs, colour management, Colour Match) into M4.6 playback; project schema v5 for colour management; architecture §5.3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:05:55 -04:00
Brandon Thomas c47c90f070 Merge branch 'main' into worktree-agent-a0342df5d4a386968 2026-10-01 09:03:47 -04:00
Brandon Thomas 1653430c42 M8.8: colour management — sequence working space (Rec. 709 / Rec. 2100 PQ / HLG, wide gamut), Interpret Footage colour space, log/HDR decode with BT.2390 tone mapping, HDR export signalling, HDR scopes
- model: SequenceSettings::color (ColorPipeline: working space, wide gamut, Auto Tone Map Media;
  serde default Rec. 709) and Interpretation::color_space (override; None = metadata)
- render::colorman: source colour space from the override or VUI/colr/MKV metadata, decode tables
  (camera log with super-whites, PQ, HLG + OOTF), gamut matrix, tone mapping into SDR working
  spaces, gamut mapping; working → SDR monitor transform at the top level
  (RenderOptions::working_output keeps working values for HDR export and scopes). Plain Rec. 709
  media in a Rec. 709 sequence keeps the old fast path and stays on the GPU; managed layers and
  HDR/wide-gamut sequences composite on the CPU
- export: H.264 and ProRes of a PQ/HLG sequence encode BT.2020 PQ/HLG and signal it: VUI / ProRes
  header, colr (nclx/nclc), and for PQ mdcv + clli boxes and H.264 SEI (payloadTypes 137/144);
  `sdr: true` (and render previews) export tone-mapped SDR. isobmff reads/writes mdcv and clli
- commands: sequence.colorSettings (Sequence ▸ Color Management…), clip.interpretFootage
  (Clip ▸ Modify ▸ Interpret Footage…, Project panel context menu), color.spaces,
  media.colorInfo; dialogs with automation ids colorDialog.*
- scopes: HDR sequences show a cd/m² waveform on a PQ scale (203 marked) and a BT.2020
  vectorscope from the working-space render (scopes.hdrWaveform)
- display-referred wide-gamut input is desaturated into gamut keeping in-gamut colours exactly;
  the soft compression is reserved for camera gamuts
- tests: colorman unit tests, engine (interpret/undo, PQ working space values and display),
  goldens log_to_rec709 and hdr_tone_map (own renders + sidecars), export PQ/HLG × ProRes/H.264
  read back by our demuxer and ffprobe (color_transfer/primaries/space, mastering display and
  content light side data), headless UI (dialogs, HDR scopes)
- docs: architecture §5.2 (pipeline, HDR export, display colour management: no macOS EDR yet)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:56:47 -04:00
Brandon Thomas 4b83e088eb Merge main into the playback branch (mixer recordStart moves to the end of preroll; GopCache keeps main's random-access key walk-back)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:30:04 -04:00
Brandon Thomas 6a0a3add7f M7.4: Essential Sound model and commands — audio types, per-type settings as clip effects, presets, loudness auto-match, ducking keyframes
- project::essential: Dialogue/Music/SFX/Ambience settings (Loudness, Repair, Clarity, Creative,
  Ducking, Pan, Clip Volume, Mute), our own EQ/reverb/type presets, and apply(): settings become
  ordinary clip effects (EffectInstance::essential) in canonical order; only changed parameters
  are written, so keyframes survive; auto-match gain → clip gain, Clip Volume → Volume offset,
  Pan → Panner
- effect defs: DeEsser, DeReverb (params), Enhance Speech, Stereo Width; render mappings for them,
  and DeNoise amount / DeHummer gain now reach the DSP; Mute; render::audio::clip_signal
- engine essentialSound.* (inspect, setType, clearType, set, applyPreset, savePreset,
  deletePreset, autoMatch, generateDucking), undoable; per-type loudness targets and user presets
  in preferences
- tests: auto-match within 0.001 LU of target (−23 / −16, with and without a chain), ducking
  keyframes within 20 ms on a synthetic dialogue+music project and −15.00 dB in the mix, repair
  metrics (hum −39 dB, rumble −22 dB, noise floor −13 dB, sibilance −19 dB, reverb tail −10 dB),
  render chunking bit-identical and WAV export = render; full Dialogue chain 22× realtime (release)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:28:38 -04:00
Brandon Thomas 9baa34fa45 Merge M10.1–2 + M3.2/M3.11 into M7.2 (audio mixer): preferences gain audio + playback + trim groups; ROADMAP refreshed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 02:17:12 -04:00
Brandon Thomas 14ae01885f M7.2: Audio Track Mixer and Audio Clip Mixer panels, timeline track keyframes, live recording
- Audio Track Mixer: strips for audio tracks, submixes and the Mix with
  effect/send slots (disclosure), input mapping, output assignment, pan
  knob, automation mode, M/S/R (solo safe on submixes), fader with dB
  scale and our own taper, stereo meters fed by the playing mix, value
  hot text, footer transport; horizontal/vertical scrolling. Fader and
  knob drags are mixer.touch while held and mixer.release on let go, so
  they are heard live and recorded in Latch/Touch/Write.
- Audio Clip Mixer: per-track strips for the clip under the playhead
  (clip Volume / Panner, write-keyframes toggle), clipMixer.set with one
  undo step per drag (Session::edit_merged).
- Timeline: per-track "Show Keyframes" button picks clip keyframes or a
  track lane (volume, panner, mute, sends, insert params); the lane is
  drawn across the track, Pen / Cmd-click adds, diamonds drag in time and
  value, right-click deletes.
- Playback starts an automation pass and stopping writes it; the audio
  callback reads the newest project snapshot (LiveMix), so mixer moves
  are heard while playing. Audio Meters read the graph's live meters
  instead of re-mixing at the playhead.
- Automation ids on every control; headless kittest tests drive the
  panels by id and by multi-frame drags (FILMCRAFT_UI_SNAPSHOT_DIR renders
  offscreen PNGs through wgpu).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 02:10:29 -04:00
Brandon Thomas 04e714510b M4.6: GPU path converts layer texels on the frame workers, not on the UI thread
GpuCompositor::upload converted f32 RGBA layers (effects rendered on the CPU, captions,
whole-frame fallbacks) and 16-bit YUV frames (ProRes render previews) to half floats on the UI
thread every time a frame was shown: 8.3 M values per 1080p RGBA layer, 4 M per ProRes frame.
filmcraft_gpu::prepare(plan) now does those conversions on the frame worker that built the plan
(parallel chunks; 16-bit codes through a cached per-bit-depth table) and the plan cache stores
them with the plan (frames::GpuPlan), bounded by count and bytes (1 GiB). composite_prepared()
only copies bytes into textures. The texels are bit-identical (new test compares the read-back
output of both paths for f32, 10-bit 4:2:2 and fallback-image plans).

bench, same-session A/B (GPU path, after-preview Full, 2 rounds, load avg 50–95):
  UI-thread present time p50/p95: plays from previews 11–31 / 34–77 ms → 3.6–5.8 / 4–14 ms;
    live effects play 17–28 / 31–56 ms → 4.1 / 12 ms (first run)
  plays from previews: 184/8, 183/9, 189/3, 169/23 → 192/0, 192/0, 191/1, 192/0 shown/dropped
  live effects play (CPU-bound, ~6 cores at this load): too noisy to compare (0–117 shown either way)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 02:10:14 -04:00
Brandon Thomas 97967d865a Merge main into M10 (text engine + graphics)
# Conflicts:
#	ROADMAP.md
2026-10-01 01:57:41 -04:00
Brandon Thomas daaee5072c M10.2: Type tool with on-monitor text editing, shape and pen tools, layer boxes and handles, graphic editor in Properties / Essential Graphics
- Program monitor overlay for graphic clips: Type tool click creates a text layer (in the
  selected graphic under the playhead or a new clip) and edits it in place with a caret,
  selection highlight, arrows/word/line navigation, Shift-select, Cmd+A/C/X/V, Return,
  Backspace/Delete, Esc; typing is one undo step. Selection tool selects, moves and scales
  layers (bounding box, handles, anchor); double-click edits text. Rectangle/Ellipse tools
  drag out shapes; Pen tool places a closed path. Automation ids program.layer.*.
- Properties (when a graphic is selected) and Essential Graphics: Layers list, Align and
  Transform (align / distribute), Text (source text, font family + style incl. system fonts,
  size, paragraph alignment, tracking, leading, baseline shift, box width, faux bold/italic,
  caps, underline, kerning/ligatures), Shape, Appearance (fill, 2 strokes, background,
  shadow). Automation ids graphics.*.
- Headless UI test (egui_kittest) drives the whole flow through the control channel; with
  FILMCRAFT_UI_SHOTS it renders PNGs via wgpu (works with a locked screen).
- docs/graphics.md; architecture, ROADMAP, ATTRIBUTION (code-drawn glyphs) updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:57:18 -04:00
Brandon Thomas 4918555906 M10.2: graphic clips — text and shape layers in the project model, vector renderer (CPU + GPU plan), graphics.* commands
- project: ItemKind::Graphic (transparent canvas source, hidden from the Project panel,
  unlimited duration); graphic layers are hidden effect instances graphic_text /
  graphic_shape on the clip (serde for free, keyframes on every animatable property,
  Source Text holds), with appearance (fill, two strokes outer/centre/inner, background
  box with radius, drop shadow) and transform (position, anchor, scale, rotation,
  opacity); eval_layer gives a plain LayerSpec. No schema migration: all additive.
- render: graphic_clip rasterises each layer straight to the output transform (crisp at
  any Motion scale/rotation), caches layer rasters, composes a tight image for the GPU
  plan; standard effects on a graphic run at source resolution first.
- engine: graphics.newText (Cmd+T) / newShape (new clip above the footage at the playhead
  or a layer in an existing clip), setText (typing coalesces into one undo step), set,
  selectLayer, deleteLayer, arrangeLayer, align (frame / selection), distribute,
  graphics.list, fonts.list. EditorState.graphic_layers holds the layer selection.
- goldens: graphic_title, graphic_shapes (CPU and GPU parity).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:38:04 -04:00
Brandon Thomas b141c406e9 M10.1: text engine (crates/text): font database with bundled OFL fonts and system-font discovery, harfrust shaping, bidi, line breaking, paragraph layout, glyph cache and rasteriser; captions and Timecode/Clip Name burn-ins use it
- New L1 crate filmcraft-text: fonts (bundled Inter Regular/Medium/SemiBold/Bold/Italic,
  JetBrains Mono, Noto Serif; DirectorySource scans system font folders reading only name/OS2
  tables; family/style resolution with synthetic bold/italic; per-char fallback), layout
  (harfrust kerning/ligatures, unicode-bidi, unicode-linebreak, alignment incl. justify,
  leading, tracking, baseline shift, all/small caps, underline, carets/hit-test/selection,
  cached), raster (moved from captions; active-edge list, shapes, emboldening), render
  (outline + sub-pixel glyph-mask caches; transformed-outline path for rotation/skew),
  mask (distance-transform strokes, blur).
- Captions burn-in now shapes and kerns via the engine (font.rs/raster.rs removed).
- Timecode / Clip Name effects draw real text (full clip names, not seven-segment digits);
  text_burnin golden re-blessed.
- UI takes its font bytes from the text crate (no duplicate copies in the binary).
- New fonts: Inter Bold, Inter Italic (OFL-1.1, rsms/inter v4.1), Noto Serif Regular
  (OFL-1.1, notofonts) with sidecars, ATTRIBUTION.md rows and licence text.
- Perf: 3-line 96 px title at 1080p ~1.6 ms cold / 0.15 ms warm (release).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:22:30 -04:00
Brandon Thomas 5110b694d8 M4.5: fix UI hang after preview render (macOS App Nap starved the hidden app; ui.screenshot waits forever)
Root cause: not a lock. When the window is hidden or behind others (always when the app is
driven over the control channel), macOS App Nap drops every thread of the process to background
priority 4 and defers its timers. On a loaded machine (load avg ~150) a priority-4 process gets no
CPU: after Render In to Out + play the UI thread stayed runnable inside the run loop's timer
callout, every thread at PRI 4 (`ps -M`), 0 % CPU, control channel silent. Relaunched with App Nap
off the same script ran through: render 2–13 s instead of 15 s, every reply immediate (2/2 runs).

- apps/filmcraft/src/app_nap.rs: hold a user-initiated, latency-critical NSProcessInfo activity
  for the life of the process (= NSAppSleepDisabled for a bundle; idle system sleep allowed).
- ui.screenshot: a hidden window or sleeping display never presents, so the screenshot event
  never came and the UI repainted at full speed forever (100 % CPU). It now fails after 10 s with
  "no frame was presented (window hidden or display asleep)" and polls at 60 Hz meanwhile.

Regression test: app_nap::tests (the activity is taken on macOS). The starvation itself needs a
hidden window on a loaded machine and is checked with the control-channel script in the commit
notes (captions.newTrack/add, markIn/Out, Full, renderInToOut wait, stop, playhead.set,
renderBar, ui.screenshot): all replies within 10 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:17:13 -04:00
Brandon Thomas 0aaa4f41de Merge main into M9.8 (VP9): Opus + VP9 together in codecs/mkv; vp9 at opt-level 3 in dev builds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:05:53 -04:00
Brandon Thomas 68e5e91bfe Merge main into the playback branch
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:52:31 -04:00
Brandon Thomas 4eb1ffaa59 Merge branch 'main' into worktree-agent-a4e518618b8b67600 2026-10-01 00:46:36 -04:00
Brandon Thomas 5170376dcb M4.6: headless playback benchmark (cargo xtask bench-playback) and a correct dropped-frame count
- crates/ui-egui/examples/bench_playback.rs drives the Program monitor's own FrameServer,
  prefetch (now FrameServer::schedule_playback, shared with the monitor) and PlaybackMeter at a
  simulated 60 Hz display, optionally compositing on a headless wgpu device. Scenarios:
  h264-1080, stack3 (3 × 1080p, scaled/rotated/opacity), h264-2160, demo, after-preview
  (live play → Render Effects In to Out → 2 plays), seek-storm. Reports latency percentiles,
  on-time ratio, worker/decode wall and thread-CPU time, UI-thread present time, process CPU per
  frame, decoder seeks/samples (codecs::gop_stats) and wasted jobs; --json for machine output.
  Fixtures are generated with ffmpeg into target/fixtures/playback.
- FrameServer records per-job timings (thread CPU via rustix clocks) while profiling is on.
- Dropped/shown were counted per UI refresh: "shown" counted every refresh that had the frame
  (322 "shown" in an 8 s play of 192 frames) and "dropped" counted a frame that arrived a few ms
  after its first refresh. PlaybackMeter counts timeline frames: shown when the exact picture was
  on screen while due, dropped otherwise, including frames passed over without a refresh.

Baseline (GPU path, 8 s, load avg 104–168 on 14 cores; CPU columns are load-robust):
  h264-1080 Full 191/1 shown/dropped, 46 ms CPU/frame; Half 188/4
  stack3 Full 189/3, 102 ms CPU/frame; Half 157/35 (3 extra decoder seeks)
  h264-2160 Full 8/184, 313 ms CPU/frame, 10 seeks; demo Full 114/78, Half 191/1
  after-preview: live 0/192; 1st play after render 124/67, 2nd 119/73 (UI-thread present
  p50 21 ms / p95 45 ms); seek-storm: 0 of 40 seeks shown within 150 ms

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:44:23 -04:00
Brandon Thomas 9db963e0e6 M9.8: VP9 wired into codecs — WebM/MKV V_VP9 and MP4 vp09 (+vpcC) import, 8/10/12-bit 4:2:0/4:2:2/4:4:4 (4:4:0 expanded, RGB to RGBA) output, key-frame-checked GOP random access, Decoder::reset / is_keyframe, oracle seek tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:42:11 -04:00
Brandon Thomas 7dcdef6974 T5: headless scripted UI tests (egui_kittest + control channel)
crates/ui-egui/tests/scripted.rs runs the real FilmcraftApp under
egui_kittest's eframe harness (no window/GPU) and drives it through
ControlRequests, stepping frames until each reply arrives; synthetic
ui.click input is fed through the app's raw_input_hook. Tests: demo
project + widget registry, razor/undo/redo with timeline locate,
source insert, apply Gaussian Blur and see it in Effect Controls,
playback toggle/stop, click a tool button by automation id, error
replies. docs/testing.md documents coverage and limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:39:14 -04:00
Brandon Thomas 8eb8f5ff68 T4: BS.1770 loudness oracle test against ffmpeg ebur128
Seven generated signals (sine, pink noise at 48/96 kHz, speech-like at
48/44.1 kHz, gated stereo with silence and sub-gate passages, fs/4
inter-sample peak) written as float WAV and measured by LoudnessMeter
and ffmpeg ebur128 (metadata, 3 decimals per 100 ms). Tolerances: M/S
+-0.1 LU every 100 ms, I +-0.1 LU, LRA +-0.5 LU, true peak +-0.2 dB.
Measured: M/S <= 0.0005, I <= 0.007, LRA <= 0.04 LU, TP <= 0.045 dB.
On the fs/4 tone ffmpeg's true peak is +0.6 dB above the analytic
value, so that case is checked against the analytic peak (ours -0.053).
testkit gains a float WAV writer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:32:25 -04:00
Brandon Thomas 7655447233 T3: golden-image tests for the renderer + GPU parity; fix stale GPU uploads
crates/golden (test-only, L3): nine procedural 320x180 scenes (transform
and opacity, blend modes, Gaussian Blur, Lumetri basic, Crop, Cross
Dissolve / Dip to Black / Wipe mid-transition, timecode/clip-name text)
rendered on the CPU and compared with committed goldens (PSNR >= 45 dB,
max <= 12, p99 <= 2); FILMCRAFT_BLESS=1 regenerates them with
attribution sidecars. testkit::golden adds PNG I/O, diff metrics and
failure images. The same scenes are composited on the GPU and compared
with the CPU.

GPU parity exposed a real bug: GpuCompositor cached uploads by
pixel-buffer address without owning the buffer, so a new frame
allocated at a freed frame's address was drawn with a stale texture
(whole wrong frames, PSNR ~12 dB). The cache now keeps the buffer
alive; regression test upload_cache_keeps_buffers_alive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:26:14 -04:00
Brandon Thomas 34f53fe9cf Merge main into M11.1–2 (autosave/recovery): previews follow save/open/recover; bare pre-envelope projects with version 1 or 2 load as schema v1 (regression test)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:23:01 -04:00
Brandon Thomas 3704002f89 T2: cargo xtask fixtures pre-generates the oracle fixture matrix
Runs each crate's ignored generate_fixtures test (h264, hevc, isobmff,
matroska, prores) - the same generators the oracle tests use - and
prints made/cached/skipped per fixture plus a summary. Optional crate
filter: cargo xtask fixtures hevc prores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:20:59 -04:00
Brandon Thomas 8780d5ffa2 T1: shared ffmpeg/ffprobe discovery in filmcraft-testkit
New dev-dependency-only crate crates/testkit (L0, no FilmCraft deps):
FILMCRAFT_FFMPEG/FILMCRAFT_FFPROBE, then PATH (incl. .exe), then known
dirs; SKIPPED lines and FILMCRAFT_REQUIRE_ORACLES=1 to make skips fail;
require_ffmpeg!/require_ffprobe!/require_oracles!; fixtures_dir() under
<workspace>/target/fixtures with per-thread temp names and atomic
generation. Oracle helpers in aac, opus, h264, hevc, h264enc, isobmff,
matroska, prores and export migrated (codecs left on its local lookup).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:10:59 -04:00
Brandon Thomas 516978b4d4 M11.2: auto-save ring + crash-recovery journal
- Engine autosave module: Preferences (autoSave.enabled/intervalMinutes=5/maxVersions=20/
  saveCurrentProject/recoveryJournal/recoveryIntervalSeconds), persisted in the per-user data
  dir; prefs.get/set/reset commands.
- Background worker (filmcraft-autosave thread): the UI thread only hands over the Arc<Project>
  snapshot; JSON encoding and atomic writes happen on the worker. Premiere-style auto-saves to
  <project dir>/Auto-Save/<name>-YYYY-MM-DD_HH-MM-SS.fcproj (local time), only when changed,
  rotated to Maximum Project Versions, optionally also saving the project.
- Recovery journal: debounced snapshot of unsaved changes in <data>/Recovery/<session>/ guarded
  by an OS file lock; on launch, sessions whose lock is free and that left a snapshot are offered.
  Clean quit removes the journal (or keeps it, marked cleanExit, if changes were unsaved).
- Commands: file.recover, file.discardRecovery, file.recoveryList, file.autoSaveNow,
  file.autoSaveStatus, file.listAutoSaves.
- UI: Preferences ▸ Auto Save page (Edit ▸ Preferences, Cmd+,; FilmCraft ▸ Settings… on macOS),
  "Recover Unsaved Changes" dialog at startup, Revert confirmation; all with automation ids.
- Desktop: --recover / --no-recover / --data-dir; local-time offset via chrono (clock).
- Verified in the app: edits, kill -9, relaunch, dialog, Recover restores the edits (unsaved, original path).
- docs/project-files.md: auto-save, recovery and measured costs (2,000 clips: 2.5 ms encode,
  1.4 MB, ~30 ms atomic write+fsync, all off the UI thread). ROADMAP M11 updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:10:23 -04:00
Brandon Thomas 9e54812b2a Merge branch 'worktree-agent-ae361fad8d71a0eef'
# Conflicts:
#	crates/engine/src/commands.rs
#	crates/export/src/lib.rs
#	crates/ui-egui/src/frames.rs
#	crates/ui-egui/src/state.rs
2026-10-01 00:08:58 -04:00
Brandon Thomas b0ddca7169 Merge branch 'worktree-agent-a726528c34396e2d2'
# Conflicts:
#	ROADMAP.md
2026-10-01 00:07:18 -04:00
Brandon Thomas 9eb12c0043 M10.4: caption commands in the engine (captions.* — tracks, add at playhead, split/merge/trim/move/delete, text/speaker/timing, style, next/previous, show/hide, list), file.import detects .srt/.vtt/.scc into a new caption track, File ▸ Export ▸ Captions… (SRT/VTT/SCC), Clear/Ripple Delete on selected captions; caption overlays in render + GPU frame plans; burn-in on export (ffmpeg-oracle test)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:06:29 -04:00
Brandon Thomas ba4a04e031 M11.1: .fcproj schema versioning + migrations, atomic saves
- New crate filmcraft-format (L3): files are an envelope {format, schema_version, generator,
  project}; a chain of single-step JSON migrations (v1 bare Project → v2 envelope) upgrades old
  files on load; newer-than-supported files are refused with a clear "update FilmCraft" error;
  damaged/foreign files report as such.
- atomic_write: temp file in the same dir + fsync + rename + dir fsync; used for every project
  write (FsServices), so a crash mid-save never corrupts the project.
- Engine: file.save/saveAs/open go through the format crate; new file.saveCopy (Save a Copy…,
  Cmd+Alt+S) and file.revert; the first save over an upgraded file keeps
  "<name> (schema vN backup).fcproj". Project.version dropped (the envelope carries it).
- Hand-made v1 fixtures (minimal + edit without later serde-default fields) in
  crates/format/tests/fixtures; 2,000-clip encode/decode timing test.
- docs/project-files.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:54:04 -04:00
Brandon Thomas 740fcd95cb M4.5: render-bar segments + render previews in the engine — segments cut at every video edit point, 128-bit content hash relative to the segment start (clips, sources, effects + keyframes, transitions, sequence settings; stable across save/load and ripple moves), measured yellow/red cost estimate; content-addressed ProRes preview cache per project (temp folder until first save), Render Effects In to Out (Enter), Render In to Out, Render Selection, Render Audio (float WAV previews mixed into playback), Delete Render Files (In to Out), sequence.renderBar query; renders run as cancellable jobs on the export pipeline
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:43:26 -04:00
Brandon Thomas 421af286dd M10.4: caption tracks in the sequence model (project v2) + filmcraft-captions (SRT/WebVTT/SCC read+write, CEA-608 pop-on/roll-up/paint-on decoder, pop-on encoder with frame-exact load scheduling, burn-in layout + own rasteriser over skrifa outlines with Inter) + caption edit ops (add/split/merge/trim/move/delete, sync-locked insert/extract)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:42:06 -04:00
Brandon Thomas 608a83f33e M9.13: Opus in WebM/MKV and MP4 import
crates/codecs decodes Opus with filmcraft-opus (48 kHz output):
- Matroska/WebM A_OPUS: CodecPrivate = OpusHead. CodecDelay removes the
  pre-skip exactly (header pre-skip when CodecDelay is absent); packet starts
  are accumulated from TOC durations because block timestamps are only
  tick-accurate. Random access decodes max(SeekPreRoll, 320 ms) first.
- MP4/MOV Opus + dOps: edit list removes pre-skip (dOps pre-skip without
  one); same pre-roll on random access.
- Family-1 surround reordered from Vorbis to WAV/SMPTE channel order;
  corrupt packets are concealed instead of failing.
Tests (ffmpeg/libopus fixtures, skipped when absent): WebM stereo, MKV mono
VoIP (SILK/hybrid), MKV 5.1 multistream, MP4 stereo; sample-aligned against
libopus (52-89 dB sequential, 45-89 dB after random access).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:37:19 -04:00
Brandon Thomas 6f13cbe6ea Merge branch 'main' into worktree-agent-a2fb03c37eff0a53c 2026-09-30 23:14:19 -04:00
Brandon Thomas bfc4ad47b5 Merge branch 'main' into worktree-agent-adeb64ed6481c199b 2026-09-30 23:14:17 -04:00
Brandon Thomas 0594cdf8b6 M11: interchange in the engine — file.import detects and merges EDL / FCP7 XML / FCPXML / OTIO (links media on disk, rebases EDL source timecode); File ▸ Export ▸ EDL, Final Cut Pro XML, FCPXML, OpenTimelineIO
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:45:22 -04:00
Brandon Thomas 13beb09833 Merge branch 'worktree-agent-ae43da33282300438' 2026-09-30 22:41:15 -04:00
Brandon Thomas 916de99fda M9.8: filmcraft-vp9 clean-room VP9 decoder (profiles 0-3, tiles, superframes, scaling) with ffmpeg oracle tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:22:12 -04:00
Brandon Thomas ed47db6861 M9.13: Opus decoder (WIP: range decoder, packet parsing, CELT core, SILK tables)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:21:51 -04:00
Brandon Thomas dc9e3933a8 M7.3: clip audio effects run on filmcraft-audio-dsp (Amplify, Dynamics, Hard Limiter, Delay, Parametric EQ, High/Low/Bandpass, DeNoise, DeHummer, Studio Reverb, Invert, Pitch Shifter) with keyframed params, latency compensation and a continuation cache with pre-roll for random access
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:40:58 -04:00
Brandon Thomas c14a7d44a4 M11.3: EDL — filmcraft-interchange crate with CMX 3600 import/export
New L2 crate filmcraft-interchange (roxmltree for XML reading). API: import/import_with,
export, export_edl_per_track, detect, merge_into, rebase_source_timecode, Report.
EDL: drop-frame FCM, dissolves/wipes/keys, BL fades, V/A/AA/B/AA/V/A3/A4 channels,
M2 speed/reverse/freeze, reel modes (8/32), clip name/source file/effect/LOC comments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:38:19 -04:00
Brandon Thomas de7e84307d M7.1: BS.1770 loudness in Audio Meters (momentary/short-term/integrated LUFS, true peak) fed with contiguous programme audio; matches ffmpeg ebur128
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:33:53 -04:00
Brandon Thomas 498ac6da23 Merge branch 'worktree-agent-a4193d1e7345108d5' 2026-09-30 11:12:22 -04:00
Brandon Thomas d3ed28ed61 Cargo.lock: hevc in codecs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:12:22 -04:00
Brandon Thomas 2e6adb1a20 Merge branch 'worktree-agent-a14267622437e4bbe' 2026-09-30 11:08:28 -04:00
Brandon Thomas 51acfddf66 Merge M9.1/M9.2: filmcraft-hevc decoder (Main/Main 10, bit-exact on 41 fixtures) 2026-09-30 11:08:07 -04:00
Brandon Thomas 627c230871 M7.1: BS.1770 loudness meter
New crate filmcraft-audio-dsp (L1, dependency-free): K-weighting for any
sample rate via bilinear transform, momentary/short-term/integrated
(gated) loudness, LRA (Tech 3342), sample and true peak (polyphase 4x),
normalisation helper, RBJ biquads, radix-2 FFT, parameter smoothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:58:11 -04:00
Brandon Thomas 77a096884b M9.9: Matroska/WebM demuxer (WIP: EBML reader, metadata, cluster scan, packets, seek)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:57:02 -04:00
Brandon Thomas d0304c41b8 M9.1: filmcraft-hevc — clean-room H.265 decoder (Main / Main 10)
Parameter sets (VPS/SPS/PPS incl. VUI, scaling lists, short/long-term RPS,
tiles, WPP entry points), slice segment headers, POC / RPS / DPB management
with bumping, CABAC for all Main/Main10 syntax elements, coding / transform
quadtrees, AMP, PCM, transform skip, lossless bypass, intra prediction (35
modes, substitution, filtering, strong smoothing), merge / AMVP / TMVP,
8-tap / 4-tap interpolation, weighted prediction, DCT 4..32 / DST, scaling,
deblocking and SAO run row-pipelined, frame-threaded decoding.

Syntax tables extracted from the ITU-T H.265 text by tools/extract_tables.py.
41 libx265 / VideoToolbox fixtures bit-exact vs ffmpeg (single and
multi-threaded).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:11:22 -04:00
Brandon Thomas 3f3265bb35 M6: H.264 MP4 export (own encoder, High profile, VBR, B-frames with edit list) + AAC
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:38:45 -04:00
Brandon Thomas bd816ead68 Merge M6.1: filmcraft-h264enc encoder 2026-09-30 09:35:35 -04:00
Brandon Thomas 7103b58df9 M6.1: filmcraft-h264enc — clean-room H.264 encoder (High/Main/Baseline, CABAC/CAVLC, intra/inter mode decision, deblocking, RC)
- SPS/PPS/AUD/SEI with VUI (SAR, colour description, timing, reorder), avcC, Annex-B or length-prefixed packets
- Intra 16x16/4x4/8x8 + chroma, hexagon ME with half/quarter-sample refinement, 16x16/16x8/8x16/8x8, P_Skip
- B-frames (1-3, spatial direct/B_Skip, L0/L1/Bi), variance AQ, scene-cut IDR
- 4x4/8x8 transforms, deadzone quant, decimation; normative deblocking in the loop
- CABAC (init tables checked against the spec text) and CAVLC
- Rate control: QP, CRF-like, 1-pass ABR + VBV, closed-loop 2-pass VBR
- Slice-parallel encoding with rayon, concurrent B-frames, parallel lookahead/hpel
- ffmpeg-oracle tests: zero decode errors, exact frame counts, decoder output bit-identical to reconstruction

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 09:32:20 -04:00
Brandon Thomas efc617cb97 M6.2: own AAC-LC decoder replaces the symphonia bootstrap for AAC; AAC encoder for MP4 export
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:38:47 -04:00
Brandon Thomas b80de3ea96 Merge M6.2: filmcraft-aac encoder + decoder 2026-09-30 07:37:46 -04:00
Brandon Thomas 627931fc72 UI fidelity pass from the Premiere 26 black-box reference: measured palette and label colours, square panels with 4 pt gutters, tab strips with underline + menu glyph, header layout, native macOS menu bar (muda), status/hint bar, Properties panel, timeline restyle (clip bodies, name band, fx badge, head thumbnails, rectified waveforms, hatched transitions, track header layout with patch/target buttons, markers row, 30 pt toolbar, zoom bar knobs), monitor controls, meters, tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:37:38 -04:00
Brandon Thomas c2872fbd8d M6.2: filmcraft-aac — clean-room AAC-LC encoder and decoder
Encoder: transient-driven window switching (long/start/short/stop, grouping),
sine/KBD MDCT, MDCT-domain psychoacoustic model (Bark spreading, SFM tonality,
ATH, PE), TNS, per-band M/S, lambda rate-distortion loop with measured-error
scalefactor search and DP sectioning over all codebooks, bit reservoir with
fill elements (exact CBR), VBR quality scale, 1-8 channels (configs 1-7 + PCE
for 7ch), ASC + optional ADTS, 1024-sample priming reported.

Decoder: full AAC-LC syntax incl. PNS (correlated M/S noise), intensity stereo,
TNS, M/S, pulse data, both window shapes, PCE/DSE/FIL, ADTS helpers; never
panics on malformed input.

Tests use ffmpeg only as an oracle: our streams decode cleanly in ffmpeg
(CBR within 0.1%), our decoder matches ffmpeg to ~1e-7 on ffmpeg-encoded
streams (8-96 kHz, mono..7.1, IS/MS/TNS), plus fuzzing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:30:13 -04:00
Brandon Thomas b7b7042b87 M5.8: wgpu compositor — frame plans (render crate), YUV/RGB layer sampling with footprint supersampling in WGSL, linear-light premultiplied compositing, upload cache; Program monitor composites on the GPU (FILMCRAFT_CPU_COMPOSITE=1 to disable)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:16:32 -04:00
Brandon Thomas f4d3efe32a M9.5: ProRes decode in the codec hub and ProRes 422 HQ export; decoder colour metadata takes precedence unless the container has an explicit colr
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:05:42 -04:00
Brandon Thomas 4faf2c295a Merge M9.5: filmcraft-prores decoder + encoder 2026-09-30 07:04:08 -04:00
Brandon Thomas eae1c8ad92 M9.5: filmcraft-prores decoder + encoder
Clean-room ProRes (SMPTE RDD 36) codec: 422 Proxy/LT/Standard/HQ and
4444/4444 XQ decode incl. alpha and interlaced fields, slice-parallel;
progressive encoder with frame-level quantiser rate control targeting
Apple nominal rates. Oracle tests vs ffmpeg (within 1 LSB on all 29
fixtures), round-trip, fuzz and ignored perf tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:02:58 -04:00
Brandon Thomas 0c1b413595 M1/M2: wire filmcraft-h264 into the codec hub (MP4/MOV H.264 with B-frames, GOP-aware seeking)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:01:36 -04:00
Brandon Thomas 11709186ea Merge M2: filmcraft-h264 pure-Rust H.264 decoder (bit-exact, frame-threaded) 2026-09-30 06:58:44 -04:00
Brandon Thomas 01b1ba1a0b M6.5/M6.6: export pipeline (parallel render → MJPEG/PCM MOV, PNG sequence, GIF, WAV) as background engine jobs; Export mode wired; control channel defers requests until elements render
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:58:34 -04:00
Brandon Thomas 3eac0a2ee7 M14: MCP server (headless + bridge to live app), filmcraft-cli (probe/commands/render/run/mcp), .mcp.json, control protocol docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:50:31 -04:00
Brandon Thomas 8194dac6a8 M1.4–M1.8: filmcraft-codecs hub — MP4/MOV sources with GOP-aware seeking and frame cache, MJPEG, PCM, AAC/MP3/FLAC/ALAC/Vorbis (symphonia bootstrap), standalone audio files; engine registers openers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:42:53 -04:00
Brandon Thomas 235c8a9bbd M0.10/M0.11: egui shell — docking workspaces, header/menus, Project, Source/Program monitors, Timeline with all edit tools, Tools, Effects, Effect Controls, Lumetri, meters, mixer, control channel, desktop app with cpal audio
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:29:18 -04:00
Brandon Thomas a2ac32916b M2.1: H.264 NAL/SPS/PPS/slice header parsing
New crate filmcraft-h264 (L0, depends only on filmcraft-bitstream):
- SPS incl. VUI/HRD, scaling lists with fall-back rules A/B, frame cropping,
  high-profile chroma_format_idc / bit depth fields, DPB size from level
- PPS incl. transform_8x8_mode, scaling lists, slice groups (parse only)
- slice header: all fields incl. ref_pic_list_modification, pred_weight_table,
  dec_ref_pic_marking
- POC types 0/1/2 (incl. MMCO5 handling and frame_num gap hooks)
- default scaling / QPc / deblocking tables from the public ITU-T spec
- ffmpeg/libx264 fixture generator for tests (skips when ffmpeg is absent)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:12:38 -04:00
Brandon Thomas ba7fd65730 Merge M1.2: filmcraft-isobmff 2026-09-30 06:05:50 -04:00
Brandon Thomas 37193b63b7 M0.9: engine session, history, media pool, ~110 commands, demo project
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:05:45 -04:00
Brandon Thomas 8d83799cc0 M0.3–M0.8: geom, color, frame, media generators, project model, edit algebra, CPU renderer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 05:58:41 -04:00
Brandon Thomas 527f2aa1e6 M1.2: filmcraft-isobmff MP4/MOV demux + mux
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 05:58:32 -04:00
Brandon Thomas 936b28e4c4 M0.1/M0.2: workspace skeleton, time and bitstream crates
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 05:33:20 -04:00