use std::process::Command;
#[derive(Debug)]
pub struct HardwareCaps {
pub best_hevc_encoder: String,
pub hevc_is_hw: bool,
pub best_h264_encoder: String,
pub h264_is_hw: bool,
pub best_av1_encoder: String,
pub av1_is_hw: bool,
pub best_prores_encoder: String,
pub prores_is_hw: bool,
}
pub fn probe_hardware() -> HardwareCaps {
let output = match Command::new("ffmpeg").arg("-encoders").output() {
Ok(o) => {
let stdout = String::from_utf8_lossy(&o.stdout);
let stderr = String::from_utf8_lossy(&o.stderr);
format!("{}{}", stdout, stderr).into_bytes()
}
Err(e) => {
tracing::warn!("ffmpeg not found or failed to probe encoders: {}", e);
return HardwareCaps {
best_hevc_encoder: "libx265".to_string(),
hevc_is_hw: false,
best_h264_encoder: "libx264".to_string(),
h264_is_hw: false,
best_av1_encoder: "libaom-av1".to_string(),
av1_is_hw: false,
best_prores_encoder: "prores_ks".to_string(),
prores_is_hw: false,
};
}
};
let stdout = String::from_utf8_lossy(&output);
let (hevc_enc, hevc_hw) = probe_one(
&stdout,
&["hevc_nvenc", "hevc_amf", "hevc_qsv", "hevc_videotoolbox"],
"libx265",
);
let (h264_enc, h264_hw) = probe_one(
&stdout,
&["h264_nvenc", "h264_amf", "h264_qsv", "h264_videotoolbox"],
"libx264",
);
let (av1_enc, av1_hw) = probe_one(
&stdout,
&["av1_nvenc", "av1_amf", "av1_qsv", "libsvtav1"],
"libaom-av1",
);
let (prores_enc, prores_hw) = probe_one(
&stdout,
&["prores_videotoolbox"],
"prores_ks",
);
tracing::info!(
"Encoder detection: HEVC={} (hw={}), H264={} (hw={}), AV1={} (hw={}), ProRes={} (hw={})",
hevc_enc, hevc_hw, h264_enc, h264_hw, av1_enc, av1_hw, prores_enc, prores_hw
);
HardwareCaps {
best_hevc_encoder: hevc_enc,
hevc_is_hw: hevc_hw,
best_h264_encoder: h264_enc,
h264_is_hw: h264_hw,
best_av1_encoder: av1_enc,
av1_is_hw: av1_hw,
best_prores_encoder: prores_enc,
prores_is_hw: prores_hw,
}
}
fn probe_one(ffmpeg_output: &str, priority: &[&str], fallback: &str) -> (String, bool) {
for name in priority {
if ffmpeg_output.contains(name) {
let is_hw = !name.starts_with("lib");
return (name.to_string(), is_hw);
}
}
(fallback.to_string(), false)
}