Commit Graph
4 Commits
Author SHA1 Message Date
MarekSpodBiedry d702608eaf Count VideoToolbox sessions, frames and declined requests in perf.stats (#981) 2026-10-11 11:35:18 +02:00
JordyUSAandClaude Opus 5.5 3a46156861 Export: CRF (constant quality) bitrate encoding for H.264
Adds BitrateMode::Crf with ExportSettings::crf (0-51, default 23) and
maps it to the built-in encoder's RateControl::Crf, which export never
used. The Export panel offers "CRF (constant quality)" with a Quality
(CRF) slider in place of the bitrate fields; file.exportMedia takes
`crf` and `bitrateMode: "crf"`. H.265 (hardware only) rejects it, and
VideoToolbox / NVENC decline it so the built-in encoder runs. Settings
saved before this read as CRF 23.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:09:05 +07:00
Dario CarneluttiandClaude Sonnet 5.5 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 CarneluttiandClaude Sonnet 5.5 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