1use std::process::Command;
2
3#[derive(Debug)]
5pub struct HardwareCaps {
6 pub best_hevc_encoder: String,
8 pub hevc_is_hw: bool,
10
11 pub best_h264_encoder: String,
13 pub h264_is_hw: bool,
15
16 pub best_av1_encoder: String,
18 pub av1_is_hw: bool,
20
21 pub best_prores_encoder: String,
23 pub prores_is_hw: bool,
25}
26
27pub fn probe_hardware() -> HardwareCaps {
31 let output = match Command::new("ffmpeg").arg("-encoders").output() {
32 Ok(o) => {
33 let stdout = String::from_utf8_lossy(&o.stdout);
35 let stderr = String::from_utf8_lossy(&o.stderr);
36 format!("{}{}", stdout, stderr).into_bytes()
37 }
38 Err(e) => {
39 tracing::warn!("ffmpeg not found or failed to probe encoders: {}", e);
40 return HardwareCaps {
41 best_hevc_encoder: "libx265".to_string(),
42 hevc_is_hw: false,
43 best_h264_encoder: "libx264".to_string(),
44 h264_is_hw: false,
45 best_av1_encoder: "libaom-av1".to_string(),
46 av1_is_hw: false,
47 best_prores_encoder: "prores_ks".to_string(),
48 prores_is_hw: false,
49 };
50 }
51 };
52 let stdout = String::from_utf8_lossy(&output);
53
54 let (hevc_enc, hevc_hw) = probe_one(
55 &stdout,
56 &["hevc_nvenc", "hevc_amf", "hevc_qsv", "hevc_videotoolbox"],
57 "libx265",
58 );
59
60 let (h264_enc, h264_hw) = probe_one(
61 &stdout,
62 &["h264_nvenc", "h264_amf", "h264_qsv", "h264_videotoolbox"],
63 "libx264",
64 );
65
66 let (av1_enc, av1_hw) = probe_one(
67 &stdout,
68 &["av1_nvenc", "av1_amf", "av1_qsv", "libsvtav1"],
69 "libaom-av1",
70 );
71
72 let (prores_enc, prores_hw) = probe_one(
73 &stdout,
74 &["prores_videotoolbox"],
75 "prores_ks",
76 );
77
78 tracing::info!(
79 "Encoder detection: HEVC={} (hw={}), H264={} (hw={}), AV1={} (hw={}), ProRes={} (hw={})",
80 hevc_enc, hevc_hw, h264_enc, h264_hw, av1_enc, av1_hw, prores_enc, prores_hw
81 );
82
83 HardwareCaps {
84 best_hevc_encoder: hevc_enc,
85 hevc_is_hw: hevc_hw,
86 best_h264_encoder: h264_enc,
87 h264_is_hw: h264_hw,
88 best_av1_encoder: av1_enc,
89 av1_is_hw: av1_hw,
90 best_prores_encoder: prores_enc,
91 prores_is_hw: prores_hw,
92 }
93}
94
95fn probe_one(ffmpeg_output: &str, priority: &[&str], fallback: &str) -> (String, bool) {
99 for name in priority {
100 if ffmpeg_output.contains(name) {
101 let is_hw = !name.starts_with("lib");
102 return (name.to_string(), is_hw);
103 }
104 }
105 (fallback.to_string(), false)
106}