Commit Graph

77 Commits

Author SHA1 Message Date
Jeremy Yao 1d1cec80b1 graphics: draw with the newer driver when Windows lists one GPU through two versions of it (#609)
A PC whose GPUs were installed from different driver packages of one vendor
(an ASUS G513QY: the integrated Radeon on the 2021 package, the RX 6800M on a
2026 one) gives the Vulkan loader two versions of that vendor's driver, and
the RX 6800M is listed once through each. wgpu's request_adapter takes the
first discrete entry, the 2021 driver's, and the window drawn through it dies
inside amdvlk64.dll (0xc0000005) before it paints: the main thread is in the
2021 driver, the fault on a thread of the 2026 one, no Rust frame anywhere.
Left to the #820 ladder, two crashed launches end in DirectX 12 only.

filmcraft_gpu::adapter::choose is wgpu's own rule (the adapters that can draw
to the surface, by device type for WGPU_POWER_PREF, then as enumerated) with
one addition: when the adapter that rule picks is listed again by the same
driver (same backend, device type, PCI vendor and device and driver name; the
same bus id when both report one), the entry exposing the most wgpu features
is used, i.e. the newer version (68 against 60 here, a strict superset).
Without such a duplicate the choice is wgpu's own, and entries of one GPU from
different drivers (RADV and AMDVLK, a vendor's driver and Dozen) are left
alone.

graphics::apply installs it as egui-wgpu's native_adapter_selector in the
default mode on Windows, as #609 was asked to be rebased onto the #827
start-up. DirectX 12 only, software mode and the other platforms keep their
adapter choice, and the ladder is untouched. The adapters and the choice go
to the log.

Tests: the laptop's listing (wgpu's rule picks the entry that crashed, choose
the other one), listings without two versions of one driver over every power
preference (choose equals wgpu's rule), surface, bus id and driver cases, and
one against the adapters of the machine running the tests (the rule is what
request_adapter returns there).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:31:02 -04:00
Brandon Thomas 3284ddb993 Merge main into #931 (README, engine Cargo.toml)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:54:47 -04:00
Brandon Thomas f704b46906 Merge pull request #1064 from MrCloudy2/feat/vp8-decoder-432
#432: VP8 video decodes (clean-room pure-Rust VP8 decoder), so VP8 WebM no longer shows black
2026-10-11 21:02:52 -04:00
Brandon Thomas c7f6eccb18 Merge remote-tracking branch 'origin/main' into fix-650 2026-10-11 21:00:53 -04:00
MrCloudy2 53a0d959fe #432: VP8 video decodes (clean-room pure-Rust VP8 decoder)
VP8 WebM showed black video: there was no VP8 decoder. New L0 crate
filmcraft-vp8, implemented from RFC 6386 sections 1-19 (tables extracted
from the RFC text, nothing from the attached reference decoder): every
coding tool, versions 0-3, hidden altref frames, size changes. Bit-exact
with libvpx on 62 libvpx VP8 test vectors, real-world FATE samples and
generated fixtures; never panics on corrupted input.

Wired into codecs for Matroska / WebM (V_VP8, including the alpha layer
of transparent WebM) and MP4 (vp08). VP8 colour is BT.601 (RFC 6386 9.2).
A hidden altref frame is a WebM block of its own with the time of the
frame that follows it: the VP8 time lookup now moves on to that shown
frame instead of repeating the previous one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:13:07 +02:00
liangforstudy 979e9a0c56
#402: animated GIF and APNG import as clips, with transparency
APNG and animated GIF files opened as stills showing only their first
frame. They now open as movie clips (crates/media/src/animated.rs):

- every frame is decoded and composited onto the full canvas by the
  image crate (APNG blend/dispose ops, GIF disposal), keeping alpha
- each frame lasts its own delay; GIF delays <= 10 ms play as 100 ms
  and APNG delays < 10 ms as 10 ms, as browsers do
- consecutive identical frames are merged; the clip is one pass of the
  animation and its timebase is the most common frame length
- hostile input: at most 10,000 frames / 1 GiB of decoded pictures; a
  damaged frame ends the clip at the frames before it; files with one
  frame (or none that decode) still open as stills, as before

Tests: media unit tests (timing, transparency, merging, single-frame
files stay stills, truncated/bit-flipped files never panic) and an
engine test that imports an animated GIF and reopens it from a saved
project.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkQ2PDrNFjs9Vm8T44tdjA
2026-10-11 10:44:15 +08:00
Brandon Thomas 2ff3f5e266
Release prep: 0.6.0 and a Linux riscv64 release build (#830)
- release.yml: new `linux-riscv64` job, cross-compiled on ubuntu-24.04 against
  ports.ubuntu.com riscv64 libs (ported from GridCraft), tar.gz only, CLI
  smoke-tested under QEMU. Installs libasound2-dev:riscv64 for cpal/ALSA; the
  VA-API and NVDEC/NVENC paths are loaded with libloading at run time, so they
  need no riscv64 libraries. The draft-release job now needs it, so its tarball
  is uploaded and covered by SHA256SUMS.txt.
- packaging/linux/package.sh: CROSS_ARCH / CROSS_TARGET / CROSS_COMPILE /
  EMULATOR support, as in GridCraft.
- README and docs/releasing.md list the riscv64 tarball.
- cargo xtask version set 0.6.0 (Cargo.toml, Cargo.lock); refresh contributors.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:28:41 -04:00
Brandon Thomas f114b5f10c Revert #783 (Linux H.265 through NVENC): intermittent heap corruption in the CLI
With NVENC registered on Linux, `filmcraft-cli --test cli` aborts in 2 of 45 runs on an RTX 3090
(`malloc(): mismatching next->prev_size`, `malloc(): unaligned fastbin chunk detected`) right
after an export finishes; 0 of 30 runs fail with this reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:01:15 -04:00
SilentYeti c635d9af9e Linux: H.265 export through NVENC
The NVENC HEVC encoder (Main 8-bit SDR and Main 10 HDR PQ / HLG) was gated to
Windows. It now also runs on 64-bit Linux, on the CUDA device the H.264 encoder
already uses: the H.265 format and HDR probes are registered there and the
HEVC tests run on both systems.

NVENC registration on Linux now happens after the VA-API probe. Started beside
it, the background HEVC probe's first cuInit could deadlock with
libva-nvidia-driver, which calls cuInit from its library constructor under the
loader lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:41:04 -07:00
Brandon Thomas 3ad5a59321
Progress docs: target-app parity, gaps, alpha gate, readiness by audience (#700)
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and feature, format, hardware, UI and localization parity docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:09:14 -04:00
JordyUSA 0797ab4ed9 #598: import AVI files (Motion JPEG, H.264, HEVC, uncompressed; PCM, MP3, MP2, AC-3)
AviSource maps AVI streams onto the decoders, opened from bytes or a
streaming reader (Media Browser probe):
- Video: Motion JPEG, H.264 and HEVC (Annex B, our decoders) and
  uncompressed BGR24 / BGRX32 / YUY2 / UYVY / I420 / YV12 / NV12 / grey
  (new RawVideoDecoder). Empty "drop frame" chunks hold the picture
  before. AVI has no timestamps: H.264 with B-frames is stored in decode
  order, so the presentation order comes from the pictures' order counts
  (mxf::avc_presentation_order), keeping the slots the pictures occupy.
  A writer that kept a fine time base (ffmpeg copying an MP4's 1/600)
  fills the slots between pictures with empty chunks; the reported frame
  rate is the one the pictures play at. DivX / Xvid and DV are named and
  report that they have no decoder; their sound plays.
- Audio: PCM (integer and float) from the chunks; MPEG audio and AC-3
  frames, which AVI chunks need not follow, found again across chunk
  boundaries with the new filmcraft_mpegts::frame_bytes.
- Motion JPEG frames without Huffman tables (the AVI1 convention) decode
  with the standard ITU-T T.81 Annex K tables (also for MOV).

Tests against ffmpeg's decode of the same files: H.264 with B-frames
bit-exact under random access, also copied from a 1/600 MP4;
uncompressed video and PCM bit-exact; JPEG and MP3 / MP2 / AC-3 within
decoder tolerance; drop frames; DivX; JPEG without tables equal to the
same frame with them. Engine: an AVI imports, makes a sequence, plays
picture and sound, and probes without reading it whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:21:30 +07:00
SilentYeti 3df0b9bb36 Merge remote-tracking branch 'origin/main' into nvdec-linux
tests/setting.rs: keep the check against the backend register() reported
(main's fix expects VA-API on Linux, which NVDEC now sits in front of).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:30:22 -07:00
SilentYeti 03a840d28b Linux: NVDEC hardware decoding for H.264 and HEVC
Adds a second Linux decoder backend, crates/platform/src/nvdec, that talks to
NVIDIA's driver directly (libnvcuvid + the CUDA driver, both loaded at run
time). It is registered in front of VA-API: what NVDEC declines still reaches
VA-API, then the software decoders. H.264 8-bit and HEVC 8/10-bit, 4:2:0
progressive.

NVIDIA's parser takes Annex B access units, so there is no host-side DPB.
Pictures are read back as NV12 / P016 through the existing biplanar path and
are bit-exact with the software decoders. The CUDA context is the one
nvenc::device already retains; it gains push/pop and copy-to-host. A seek
recreates the parser and keeps the decoder.

Also fixes tests/setting.rs, which expected the Media Foundation backend name
on Linux, and updates the Hardware decoding tooltip and its Spanish row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 23:17:11 -07:00
Vikram Bhaskaran c855c50ba9
Export sequence markers to a spreadsheet-safe CSV.
The report is sorted, uses the sequence timecode, escapes formula-like text, and does not change the edit.
2026-10-10 04:37:44 +11:00
Brandon Thomas f267a941fb Merge origin/main into feat/nvenc-export
main gained NVENC H.265 Main / Main 10 (#328, #360), export stage timings
(#370) and VA-API decoding (#358). Resolution: main's NVENC session, FFI and
export factory, with this PR's changes ported onto them:
- ffi: the portable Guid (now also for the HEVC GUIDs), NV_ENC_DEVICE_TYPE_CUDA;
- session: device.rs (Direct3D 11 / retained CUDA primary context), the
  Linux libnvidia-encode.so.1 loader, Device::KIND;
- export: factory_with and its tests, the even-size check, the saturating
  max bitrate; H.265 through NVENC stays Windows-only (the factory declines
  it on Linux, where nothing probed or tested it);
- Cargo.toml: main's Linux libloading dependency covers both users;
- docs: README / ROADMAP / architecture now say NVENC H.264 runs on Windows
  and Linux; ADR and platform README keep both addenda / test rows;
- abi_tests: note why the MSVC-generated expectations hold on LP64 Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:12:46 -04:00
Brandon Thomas c9e2bfcac0 Merge origin/main into m3/nvenc-hevc-main10
Export panel: the HEVC profile labels go through tl! with Spanish entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:04:58 -04:00
Brandon Thomas 7050055a58 README: move the Gentoo overlay into Downloads > Linux
The Gentoo paragraph sat after the build-from-source and control-protocol
notes; it belongs with the other Linux install options. Mark it clearly as
community-maintained.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:54:46 -04:00
Brandon Thomas c21c86089f Merge remote-tracking branch 'origin/main' into fix-247
# Conflicts:
#	contributors/people.toml
2026-10-09 09:52:32 -04:00
Brandon Thomas 6ebc21f093 Merge remote-tracking branch 'origin/main' into fix-360
# Conflicts:
#	README.md
#	ROADMAP.md
#	crates/platform/README.md
2026-10-09 09:46:48 -04:00
Brandon Thomas 18f5bad7a8
Merge pull request #328 from SaymonMaster14/m2/nvenc-hevc
Windows: NVENC H.265 (HEVC) Main hardware encoding for Export
2026-10-09 09:46:13 -04:00
Brandon Thomas b3f2a89944 Windows: default to Vulkan | DX12 | Metal (drop only GL) instead of forcing DX12
Forcing DX12 compiles shaders through FXC, which rejects fx.wgsl (silent CPU
fallback), and leaves machines without DX12 with no backend. Leaving GL out is
what avoids the AMD atio6axx.dll crash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:44:20 -04:00
Brandon Thomas aff136ff67 Merge remote-tracking branch 'origin/main' into fix-365
# Conflicts:
#	apps/filmcraft/src/main.rs
2026-10-09 09:44:20 -04:00
Brandon Thomas 570d06d5bd Merge remote-tracking branch 'origin/main' into fix-328
# Conflicts:
#	Cargo.lock
#	README.md
#	ROADMAP.md
#	crates/platform/Cargo.toml
#	crates/platform/README.md
#	docs/architecture.md
2026-10-09 09:34:12 -04:00
Brandon Thomas 5d69487925
Merge pull request #307 from justjohn12345/pr/bugfix
Keyframes: Properties gets Premiere's navigator, Effect Controls a time ruler
2026-10-09 09:23:44 -04:00
Brandon Thomas d16f9adb0a
Merge pull request #387 from txiki739/fix/linux-tar-installer
#214: install script for the Linux tarball
2026-10-09 09:23:02 -04:00
txiki739 ae09ba904c #214: install script for the Linux tarball
The tarball now ships install.sh. It installs filmcraft, filmcraft-cli,
the desktop entry, icons, MIME type, metainfo and docs under ~/.local
without sudo; --prefix takes any absolute path (sudo ./install.sh
--prefix /usr/local for all users). Running it again updates.

The desktop entry's Exec/TryExec point at the installed binary's
absolute path, escaped per the Desktop Entry spec, so the menu entry
works without ~/.local/bin on PATH. The script checks the bundle is
complete before writing, refuses /, prefixes inside the extracted
bundle and characters launchers cannot express (=, %, control
characters), and treats the cache refresh tools as optional.

packaging/linux/test_install.py covers install and update, launching
through gio, bad arguments, an incomplete bundle, --help and a real
package.sh tarball build; Packaging lint runs it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:54:20 +02:00
Davi Andrei dbae11b843 Windows: NVENC H.265 Main 10 HDR (PQ / HLG) export
HDR sequences export as real 10-bit HEVC Main 10 through NVENC where the GPU
reports 10-bit HEVC: float BT.2020 R'G'B' -> rgbf_to_yuv420_10 -> P010 input;
VUI BT.2020 + PQ/HLG; HDR10 mastering-display / content-light as SEI on every
IDR (PQ); colr/mdcv/clli in the sample entry. New register_hdr_probe /
hdr_available in the export crate; macOS and GPUs without 10-bit keep
tone-mapping HDR sequences to 8-bit SDR HEVC. ABI asserts extended and
re-verified against nvEncodeAPI.h 12.1 (0 drift). 8-bit SDR HEVC unchanged;
the two #328 tests that asserted HDR is declined now expect Main 10.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:38:14 -03:00
JordyUSA e741267125 HW5: Linux VA-API HEVC hardware decoding, Main and Main 10 (#30)
HEVC through VA-API the same way as H.264: the software HEVC decoder's
parsers and DPB (now generic over the picture type in filmcraft-hevc:
POC, reference picture sets, reference lists, output order, RASL
handling) drive the stateless hardware. Main, Main 10 and Main Still
Picture, 4:2:0 8/10-bit (P010 read-back); scaling lists, tiles, WPP,
dependent slices, weighted prediction. Missing references and range
extensions go to the software decoder.

Tests: hardware parity on HEVC Main / Main 10 incl. open GOP, scaling
lists, slices+WPP, weighted prediction, tskip+AMP, 1080p/2160p (streamed
comparison to stay within memory); HEVC front end against a recording
stand-in on every OS; ABI checks extended to va_dec_hevc.h. Benchmark on
Iris Xe: 4K HEVC 203 -> 10 ms CPU per frame, 4K Main 10 212 -> 18 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:00:30 +07:00
JordyUSA 3496e553e7 HW5: Linux VA-API H.264 hardware decoding (#30)
Stateless VA-API decoding with FilmCraft's own H.264 host side: the
software decoder's SPS/PPS/slice-header parsers and its DPB (now generic
over the picture type in filmcraft-h264) drive the GPU, so reference
marking, reference lists and output order are shared and the pictures are
bit-exact with the software decoder. libva is loaded at run time; no libva
or driver means software decoding as before. frame_num gaps (open-GOP
seeks) get the software decoder's stand-in frames. HybridDecoder keeps the
transparent software fallback.

Tests: hardware parity on 7 H.264 streams incl. 1080p/2160p, seeks,
flushes, forced failures, fuzzing, concurrency; front end against a
recording stand-in on every OS; ABI checks against va.h. Docs: platform
README, ADR 0001 addendum, architecture, performance (H.264 2160p CPU per
frame 417 -> 11 ms on Iris Xe), roadmap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:35:57 +07:00
DWAA1660 8d6461705e
Fix #179: default Windows startup to DirectX 12
eframe's default wgpu instance enables PRIMARY | GL on Windows. Creating
the OpenGL backend can crash inside AMD's atio6axx.dll before the window
appears, so the app flashes in Task Manager and exits. When WGPU_BACKEND
is not set, the Windows instance now enables only DirectX 12; an explicit
WGPU_BACKEND is still honoured. macOS, Linux and web are unchanged.

Same fix as storytold/designcraft#168.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyVbT6Vv4BwWZ4hY8973qD
2026-10-08 17:52:30 -06:00
Davi Andrei deebe2e5b2 Windows: NVENC H.265 (HEVC) Main hardware encoding for Export
One NVENC session, ring and NV12 path now serve H.264 and HEVC (Codec enum,
Profile::HevcMain). HEVC Main 8-bit 4:2:0 SDR BT.709, MP4/MOV hvc1, parameter
sets only in an hvcC built from the SPS the encoder wrote. The H.265 format is
available through a cached NVENC probe; choosing it is the opt-in, declines are
counted errors. ABI asserts regenerated from nvEncodeAPI.h 12.1 (no drift) and
extended for HEVC; tests, docs and roadmap updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 16:28:50 -03:00
justjohn12345 a6b21fe7cb Keyframes: Properties gets Premiere's navigator, Effect Controls a time ruler
Properties panel: the diamond on a row was the stopwatch (effects.toggleAnimation),
so clicking it on a keyframe dropped every keyframe and kept the value at the
playhead. It is now Add/Remove Keyframe (effects.addKeyframe), as in Premiere:
it turns animation on with a keyframe at the playhead, adds one there, or removes
the one there, and the value falls back to what the remaining keyframes give in
Properties, Effect Controls and the Program monitor. An animated row shows the
navigator (previous / diamond / next); the diamond is filled only while the
playhead is on a keyframe. Crop's diamonds work too (the effect is applied first).

Effect Controls: the keyframe lane has a time ruler (ticks and sequence timecode
over the clip's stretch of the sequence) with the playhead's handle on it; click
or drag the ruler to move the playhead. The playhead is drawn only while it is on
the clip. Both panels share one navigator widget, with automation ids
<panel>.<effect>.<param>.addKeyframe / .prevKeyframe / .nextKeyframe, plus
effectControls.ruler and effectControls.playhead.

Tests: engine add/remove at the playhead with undo, redo and bad parameters;
headless UI tests of the navigator, Crop and the ruler; ruler labels and limits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:06:25 -04:00
Brandon Thomas 207b179428
README Downloads: where to get it first, then builds with Windows before macOS (#271)
Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:50:42 -04:00
Brandon Thomas 86a531ad22
Release: FreeBSD, Flatpak (x86_64 + aarch64) and AppImage zsync; README Downloads (#267)
- release.yml: new `flatpak` jobs (x86_64 on ubuntu-24.04, aarch64 on ubuntu-24.04-arm) that
  repackage the Linux tarball as filmcraft-<v>-linux-<arch>.flatpak, and a `freebsd` job that
  builds filmcraft-<v>-freebsd-x86_64.tar.gz in a FreeBSD 14.3 VM; both feed the draft release.
- AppImages embed gh-releases-zsync update information and ship a .zsync beside them; the
  Linux job checks both.
- Jobs that sign nothing (version, Linux, Flatpak, FreeBSD, web) no longer use the `release`
  environment, so a dispatch on a branch dry-runs them; the signing jobs and the draft-release
  job stay in the environment, so nothing is published from a branch.
- packaging/linux/flatpak-bundle.sh + bundle manifest (same runtime and finish-args as the
  Flathub manifest; packaging-lint checks they agree), packaging/freebsd/package.sh (with a
  --dry-run that packaging-lint runs), and a nightly FreeBSD build workflow.
- README: Downloads section listing every build; docs/releasing.md updated.

Co-authored-by: Brandon Thomas <shared2@storyteller.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:41:42 -04:00
Gert Pellin 7a042cd72f README: install on Gentoo from the ::snakebyte overlay 2026-10-08 11:25:54 +02:00
Brandon Thomas 853f03b1aa M-HW: NVENC on top of the shared hardware-encoding setting (#183); never-crash fixes
Merge origin/main into the NVENC branch. #183 already provides the
HardwareEncoding enum, ExportSettings.hardware_encoding, the
hardwareEncoding export param and the Export > Video > Hardware Encoding
checkbox, so the duplicates from this branch are dropped and NVENC uses
them. filmcraft-export is now an all-platform dependency of
filmcraft-platform (VideoToolbox and NVENC both register encoders).

Never-crash fixes in the NVENC backend:
- submit() rejects a driver input pitch narrower than a row (and unlocks
  the buffer); fill_nv12 uses get_mut instead of slicing rows.
- composition offsets use saturating math and i32::try_from; frame-rate,
  size and timestamp casts are checked; sizes above u16::MAX decline.
- Annex B scanning and NAL type checks use get()/first().
- A failed nvEncOpenEncodeSessionEx that returns a handle destroys it.

ffi.rs carries NVIDIA's MIT notice for nvEncodeAPI.h, listed in
ATTRIBUTION.md under a new "Third-party source code" section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 18:16:12 -04:00
Brandon Thomas fcf1c45583 Merge pull request #141 from SaymonMaster14/feat/windows-media-foundation-hwdecode
Windows: Media Foundation/D3D11 hardware H.264 + HEVC decode

# Conflicts:
#	README.md
#	ROADMAP.md
#	crates/platform/Cargo.toml
#	crates/platform/src/lib.rs
#	docs/architecture.md
#	docs/performance.md
2026-10-07 17:48:06 -04:00
Dario Carnelutti 790b3a0697 platform: H.265 (HEVC) export with VideoToolbox
Adds `Format::Hevc` (Export > Format > H.265 (HEVC); `"format": "hevc"` in
`file.exportMedia`): HEVC Main, 8-bit 4:2:0, in MP4 (`hvc1`) or QuickTime, with AAC audio,
encoded by the macOS hardware encoder. There is no built-in H.265 encoder (one in pure Rust
is a project of its own, and x265 is GPL), so the format exists only where the OS has one.

- `videotoolbox_encode`: the session wrapper creates HEVC sessions too (`VtProfile::HevcMain`;
  the profile also says which codec). Keyframes are the HEVC random access points (NAL types
  16 to 21); the parameter sets are VPS / SPS / PPS; the `hvcC` record in the MP4 sample
  entry is the one VideoToolbox writes (sample description extension atoms), so profile,
  level and flags are the encoder's own. `VtEncoder::uses_hardware()` asks VideoToolbox
  whether the session runs on a hardware encoder (a test checks H.264 and HEVC), so a
  requirement dropped by accident could never become a silent software encode.
- `hardware_encode`: one adapter for both codecs. Choosing the format is the opt-in (the
  `hardware_encoding` setting is for H.264). `hevc_available()` (one small hardware session,
  created once) is registered with the new `filmcraft_export::register_format_probe`, so
  `available(Format::Hevc)`, the format list of Export mode and `exportFormats` follow the
  machine. `Format::has_builtin_encoder` says which formats need such a probe.
- `export`: `Format::is_h26x` where H.264 and H.265 behave alike (MP4 or QuickTime, AAC, size
  estimate, summary line). Two-pass VBR is refused up front ("H.265 export has no two-pass
  mode") and HDR sequences export as SDR, because there is no encoder to fall back to.
- Export mode: H.265 shows H.264's multiplexer, audio, metadata and bitrate controls, without
  profile, level, two-pass or the hardware checkbox, and says "Encoder: Hardware".

Apple M1 (8 cores), 1080p25, a 9:29 timeline (camera clip, ProRes 4444 overlays, AAC,
loudness): hardware H.265 at 10 Mb/s 195 s, hardware H.264 at 20 Mb/s 204 s (CPU 1029 s and
1042 s; the same H.264 export took 193 s and 200 s on other runs). It is not faster: the codec
that compresses further is the more expensive one (raw encoders: 166 and 189 frames/s), and
the export is bound by the CPU compositor, not by the media engine.

Quality per bit, 30 s of the same timeline against a ProRes 422 HQ export (average PSNR over
the three planes, SSIM): 20 Mb/s 46.88 dB / 0.9902 (H.264) and 46.91 dB / 0.9903 (H.265);
10 Mb/s 44.96 / 0.9863 and 45.09 / 0.9863; 6 Mb/s 43.72 / 0.9833 and 44.31 / 0.9843; 4 Mb/s
42.91 / 0.9807 and 43.64 / 0.9825; 3 Mb/s 42.37 / 0.9786 and 43.05 / 0.9807. The same picture
at 10 Mb/s and above; at 3 to 6 Mb/s H.265 needs 22 to 31 % less bitrate for the same PSNR.
Both formats therefore keep the same default bitrate. Details in docs/performance.md (HW3).

Tests: tests/hardware_encode.rs gets the HEVC counterparts of the H.264 ones (what is taken
and declined, a round trip through our HEVC decoder with luma PSNR above 30 dB, keyframes, MP4
and QuickTime exports with AAC, ffmpeg / ffprobe reading `hevc` / `Main` / `hvc1` /
`yuv420p` / BT.709, exact sizes, hostile configurations, encoders dropped at any point, the
format list agreeing with the probe, sessions on the hardware encoder); settings_tests.rs
checks names, ids, defaults, the summary, two-pass refusal and the probe; export_ui.rs the
controls H.265 shows and hides.

Stacked on the hardware H.264 encoder (the first commit of this branch).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 14:00:08 -06:00
Dario Carnelutti 4cab6bc5da platform: opt-in hardware H.264 encoding with VideoToolbox
Export encodes H.264 on the CPU with the built-in encoder, which is most of the time
of an export (about two thirds of the busy CPU in a profile of a 20 s export). On
macOS the media engine can do it: a VideoToolbox compression session behind
`filmcraft_export::VideoEncoder`, registered by `filmcraft_platform::register()`.

- `ExportSettings::hardware_encoding` (`HardwareEncoding::Off` | `Auto`; Export > Video >
  Hardware Encoding, `"hardwareEncoding": "off|auto"` in `file.exportMedia`, a boolean is
  understood too), off by default: the built-in encoder's output is byte-identical on
  every machine, a hardware encoder's is not.
- `videotoolbox_encode` (FFI, same containment as the decoder: SAFETY comments, no
  panic across the callback, safe API) and `hardware_encode` (safe adapter and factory).
- The factory declines, so the built-in encoder is used, for other formats, MXF, two-pass
  VBR, HDR, odd sizes, non-square pixels and any configuration VideoToolbox cannot create a
  hardware session for. An encoder that fails mid-export stops it with an error: unlike a
  decoder, it cannot hand a half-written stream to another one.
- No B-frames: on real 1080p footage the quality is the same with and without them
  (+-0.3 dB at equal bitrate) and the bitrate lands closer to the target, and without
  them every frame is presented at its decode time (no composition offsets, no edit list).
- `export::register_encoder` ignores a factory registered twice; `encoder_registered`.

Apple M1, 8 cores, single runs: a 9:29 timeline (camera clip, ProRes 4444 overlays with
alpha, AAC, loudness) exports in 311 s instead of 793 s (2.5x faster); its densest 134 s
in 84 s instead of 395 s (4.7x). The outputs compare at SSIM 0.990 / PSNR 46.5 dB. The encoder
alone runs 200 fps at 1080p (docs/performance.md).

Tests (tests/hardware_encode.rs): what is taken and declined, a round trip through our
software decoder, an export that decodes in our decoder and in ffmpeg, the fallback for
everything hardware declines, exact output sizes, an empty range, hostile configurations
and encoders dropped at any point; the engine's `hardwareEncoding` parameter.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 13:34:51 -06:00
Brandon Thomas 86f3375775
Rename PrintCraft to PdfCraft (storytold/pdfcraft) (#177)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 14:45:32 -04:00
Davi Andrei 11b199dbcd Docs: NVENC H.264 hardware encoding
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMorBHwct72udS2LiC3ZHp
2026-10-07 15:42:28 -03:00
Brandon Thomas fa67dfa372 Docs: releasing guide, CLI export options, README and CLAUDE.md drift (#85, #86, #87, #88, #99)
- docs/releasing.md (#99): release.yml points readers to it twice and it didn't exist. Written from
  the workflow and packaging scripts as they are (macOS, Windows x64/x86/arm64, Linux x86_64/aarch64
  with the glibc 2.35 floor, web; draft release, secrets).
- filmcraft-cli help (#86): export lists --scale, --quality, --no-audio and --queue, and apv among
  the formats.
- README (#87): more than 650 engine commands (671 today), not about 135.
- README (#88): the web line says the browser app ships with every release and links docs/web.md.
- CLAUDE.md (#85): the Illustrator-class sibling is ../vectorcraft (formerly DrawCraft).

Fixes #85
Fixes #86
Fixes #87
Fixes #88
Fixes #99

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:49:08 -04:00
Davi Andrei 932cdb77f5 Docs: Windows hardware decoding (platform README, ADR 0001, architecture, performance, roadmap)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMorBHwct72udS2LiC3ZHp
2026-10-07 10:07:40 -03:00
Brandon Thomas 7811da4ec0
Merge pull request #122 from coygeek/docs/add-star-history
docs: add star history chart to README
2026-10-07 05:57:38 -04:00
Coy Geek 8d5acae231 docs: add star history chart to README
Show FilmCraft GitHub star growth with a linked Star History chart at the bottom of the README. Preserve the date view and top-left legend.
2026-10-06 19:33:01 -07:00
EthanSuquet 3eae70b11e h264enc: strict ffmpeg oracle that sees damaged slices (#74)
ffmpeg prints "corrupt decoded frame" as a warning, so the oracle's
`-v error -ec 0` decode let a stream with a whole slice missing pass
silently. Switching that decode to `-v warning` is not enough: with
`-ec 0`, ffmpeg 7.1/8.1 flags every picture that has more than one
slice, libx264's multi-slice streams included, while the pixels are
unchanged. That is the 119/120 in #74; the encoder's bitstream is not
at fault (VideoToolbox decodes the same streams bit-identically, and
ffmpeg with strict error detection reports nothing).

The oracle now decodes with ffmpeg's default concealment, `-v warning`
and `-err_detect +crccheck+bitstream+buffer+explode`, fails on any
output or a non-zero exit, and still compares every pixel with the
encoder's reconstruction. A negative control drops and truncates
slices (CAVLC and CABAC, 3 slices) and checks the oracle reports each
one; it fails with the old flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 16:02:53 -04:00
Brandon Thomas 7f8e102b13 Fonts: the Japanese interface uses craft-fonts first; absolute CRAFT_FONTS_DIR
The merged Japanese interface (#38) looked only for a system font. When
FilmCraft is built with craft-fonts, theme::install already appends the
Japanese faces to every font family, so switching to Japanese uses them
(no system scan) and works on the web too; otherwise it falls back to an
installed system font as before. Docs use an absolute CRAFT_FONTS_DIR
(build.rs runs in crates/text, so a relative path resolves from there).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:26:14 -04:00
Brandon Thomas 9953befe28 Fonts: use craft-fonts as an optional build input
crates/text/build.rs embeds the fonts of a storytold/craft-fonts checkout
named by CRAFT_FONTS_DIR as filmcraft_text::fonts::CRAFT_FONTS (native:
all of them; wasm32: only BIZ UDPGothic Regular). Unset, CRAFT_FONTS is
empty and nothing changes. A bad CRAFT_FONTS_DIR is a warning, or an
error with CRAFT_FONTS_REQUIRED=1. Never a Cargo dependency, no network.

- UI: the Japanese faces are the last fallback of every egui font family
  (BIZ UDPGothic first, Bold first in the semibold/medium families).
- Text engine: registered after the bundled faces; fallback_for picks
  them after the bundled faces and before system faces (Mincho for serif
  text, Gothic otherwise, nearest weight).
- Tests: Japanese glyphs (no tofu) in the UI and title paths, skipped
  without craft-fonts; the theme works with CRAFT_FONTS empty.
- Release: every build job checks out craft-fonts at a pinned commit and
  builds with CRAFT_FONTS_DIR + CRAFT_FONTS_REQUIRED; packages carry
  OFL-<family>.txt. NOTICE, ATTRIBUTION.md (optional build input), AGENTS.md,
  CLAUDE.md, README and docs/contributing.md describe it.

FilmCraft main bundles no Japanese font, so no font files move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 11:40:29 -04:00
Brandon Thomas e9a0c49d15 Docs: hardware decode on macOS and 31 GPU effects landed (#30)
ROADMAP honest assessment, Where we are lacking and Running now; README status and codec note. 35 crates (platform).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 07:50:45 -04:00
Brandon Thomas 3d4e6d77bb Docs: honest parity assessment in ROADMAP, README and agent docs
ROADMAP now reports two numbers: the feature checklist (~87%, what exists)
and ready for real work (~50-60%, an honest estimate). Adds a by-dimension
assessment with evidence, a prioritised "Where we are lacking" list (hardware
acceleration, a measured parity tool, real-world media corpus, workflow
acceptance tests, Windows/Linux runtime CI, delivery codecs, plugins, AI, web),
and where we're going. Fixes stale rows (M5 effect count, Running now) and logs
2026-10-05.

README: the stale "45%" status replaced with both numbers and the biggest
gaps; the codec note now lists what imports today and what's missing.

docs/agents.md: agents read the honest assessment first, prefer its gaps,
and report progress as measured vs estimated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 06:04:09 -04:00