mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-24 10:10:05 -06:00
Never crash: filmcraft-export without expect()/unreachable!()
The five 'mux created' / 'audio' expects in the stepped exporter now return an ExportError::Encode instead of panicking if the writer or audio pipeline is missing, and the non-stepped dispatch returns Unsupported instead of unreachable!(). The crate root gets the never-crash deny attribute, so every FilmCraft production crate now carries it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
508a5a933f
commit
136424dc93
@@ -189,7 +189,7 @@ impl Exporter {
|
||||
if n == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let mux = self.mux.as_mut().expect("mux created");
|
||||
let mux = self.mux.as_mut().ok_or_else(|| ExportError::Encode("internal: the container writer was not created".into()))?;
|
||||
match self.aenc.as_mut() {
|
||||
Some(a) => {
|
||||
for au in a.encode(&buf)? {
|
||||
@@ -221,7 +221,7 @@ impl Exporter {
|
||||
if let Some(m) = self.mxf.as_mut() {
|
||||
return m.write_video(packets);
|
||||
}
|
||||
let mux = self.mux.as_mut().expect("mux created");
|
||||
let mux = self.mux.as_mut().ok_or_else(|| ExportError::Encode("internal: the container writer was not created".into()))?;
|
||||
for p in packets {
|
||||
mux.write_sample(self.vt, WriteSample { data: &p.data, duration: p.duration, composition_offset: p.composition_offset, is_sync: p.key })
|
||||
.map_err(|e| ExportError::Io(e.to_string()))?;
|
||||
@@ -282,7 +282,7 @@ impl Exporter {
|
||||
if !self.settings.part_of_batch {
|
||||
progress.set_status("Measuring loudness");
|
||||
}
|
||||
let a = self.audio.as_mut().expect("audio");
|
||||
let a = self.audio.as_mut().ok_or_else(|| ExportError::Encode("internal: the audio pipeline was not created".into()))?;
|
||||
a.measure(&self.settings, sources, &|| progress.cancel.load(Ordering::Relaxed))?;
|
||||
if filmcraft_media::pending::take() {
|
||||
return Ok(Step::Pending);
|
||||
@@ -361,7 +361,7 @@ impl Exporter {
|
||||
self.write_audio(mixed)?;
|
||||
if let (Some(at), Some(a)) = (self.at, self.aenc.as_mut()) {
|
||||
let fs = a.frame_size();
|
||||
let mux = self.mux.as_mut().expect("mux created");
|
||||
let mux = self.mux.as_mut().ok_or_else(|| ExportError::Encode("internal: the container writer was not created".into()))?;
|
||||
for au in a.flush()? {
|
||||
mux.write_sample(at, WriteSample { data: &au, duration: fs, composition_offset: 0, is_sync: true })
|
||||
.map_err(|e| ExportError::Io(e.to_string()))?;
|
||||
@@ -370,7 +370,12 @@ impl Exporter {
|
||||
let (bytes, extra_files) = match self.mxf.take() {
|
||||
Some(m) => m.finish(&self.settings)?,
|
||||
None => {
|
||||
let w = self.mux.take().expect("mux created").finish().map_err(|e| ExportError::Io(e.to_string()))?;
|
||||
let w = self
|
||||
.mux
|
||||
.take()
|
||||
.ok_or_else(|| ExportError::Encode("internal: the container writer was not created".into()))?
|
||||
.finish()
|
||||
.map_err(|e| ExportError::Io(e.to_string()))?;
|
||||
(w.finish(&self.settings)?, Vec::new())
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
//! [`ExportSettings`] carries every Export-mode setting (frame size, rate, bitrate encoding, audio
|
||||
//! format, multiplexer, captions, effects, metadata) as serde data; [`presets`] defines the
|
||||
//! built-in presets.
|
||||
#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable))]
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
@@ -1116,7 +1117,10 @@ pub fn export(project: &Arc<Project>, seq: ItemId, settings: &ExportSettings, so
|
||||
}
|
||||
(total, count)
|
||||
}
|
||||
Format::H264 | Format::ProRes | Format::DnxHr | Format::Mjpeg | Format::MxfOp1a | Format::MxfOpAtom => unreachable!("stepped export"),
|
||||
Format::H264 | Format::ProRes | Format::DnxHr | Format::Mjpeg | Format::MxfOp1a | Format::MxfOpAtom => {
|
||||
// Handled by the stepped exporter above; reaching here would be a dispatch bug.
|
||||
return Err(ExportError::Unsupported(format!("{:?} must run as a stepped export", settings.format)));
|
||||
}
|
||||
};
|
||||
let secs = t0.elapsed().as_secs_f64();
|
||||
if !settings.part_of_batch {
|
||||
|
||||
Reference in New Issue
Block a user