M13.4: HEVC / AV1 output modules (MP4 hvc1/av01, WebM AV1), codec + Opus options in engine, UI, CLI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-10-03 05:01:43 -04:00
co-authored by Claude Opus 5.5
parent 3a8b401e81
commit 280f7d509c
15 changed files with 906 additions and 49 deletions
+10 -7
View File
@@ -1,4 +1,5 @@
//! Movie export: FilmCraft H.264 → MP4 (+ AAC) and ProRes → MOV (+ PCM), muxed by
//! Movie export: FilmCraft H.264, HEVC (`effectcraft-hevcenc`) and AV1 (`effectcraft-av1enc`)
//! → MP4 (+ AAC) and ProRes → MOV (+ PCM), muxed by
//! FilmCraft's ISO BMFF / QuickTime writer.
use std::io::Write;
@@ -18,14 +19,14 @@ fn mux_err(e: impl std::fmt::Display) -> ExportError {
ExportError::Io(e.to_string())
}
struct Packet {
data: Vec<u8>,
key: bool,
pub(crate) struct Packet {
pub(crate) data: Vec<u8>,
pub(crate) key: bool,
/// pts − dts in the track timescale.
cto: i32,
pub(crate) cto: i32,
}
trait VideoEncoder {
pub(crate) trait VideoEncoder {
fn sample_entry(&self) -> SampleEntry;
fn encode(&mut self, rgba: &[u8], index: u64) -> Result<Vec<Packet>>;
fn flush(&mut self) -> Result<Vec<Packet>>;
@@ -226,9 +227,11 @@ pub(crate) fn movie(job: &Job, comp: &Comp, w: u32, h: u32, st: &mut State) -> R
let channels = if fmt == OutputFormat::ProRes { job.output.channels } else { Channels::Rgb };
let mut venc: Box<dyn VideoEncoder> = match fmt {
OutputFormat::H264 => Box::new(H264::new(w, h, rate, job.output.bitrate_kbps)?),
OutputFormat::Hevc => Box::new(crate::hevc_av1::Hevc::new(w, h, rate, job.output)?),
OutputFormat::Av1 => Box::new(crate::hevc_av1::Av1::new(w, h, rate, job.output)?),
_ => Box::new(ProRes::new(w, h, job.output.prores_profile, channels)),
};
let brand = if fmt == OutputFormat::H264 { Brand::Mp4 } else { Brand::Mov };
let brand = if fmt == OutputFormat::ProRes { Brand::Mov } else { Brand::Mp4 };
let batch = batch_size();
let render = |k: u64| -> Vec<u8> { rgba8(&render_frame(job, comp, k), comp, channels, w, h) };