use super::capabilities::{HwAccelCapabilities, HwAccelDevice, HwKind};
use std::process::Command;
pub(crate) fn probe_macos() -> HwAccelCapabilities {
match try_probe_macos() {
Ok(caps) => caps,
Err(e) => {
tracing::debug!("macOS HW accel probe failed (benign): {e}");
HwAccelCapabilities::none()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ChipFamily {
AppleM1M2,
AppleM3M4,
IntelMac,
Unknown,
}
fn sysctl_n(key: &str) -> Result<String, String> {
let out = Command::new("sysctl")
.arg("-n")
.arg(key)
.output()
.map_err(|e| format!("sysctl spawn failed: {e}"))?;
if !out.status.success() {
return Err(format!("sysctl -n {key} exited with status {}", out.status));
}
Ok(String::from_utf8_lossy(&out.stdout).trim().to_string())
}
fn detect_chip_family() -> ChipFamily {
let is_arm64 = sysctl_n("hw.optional.arm64")
.ok()
.map(|v| v == "1")
.unwrap_or(false);
if is_arm64 {
let brand = sysctl_n("machdep.cpu.brand_string").unwrap_or_default();
let upper = brand.to_uppercase();
if upper.contains("M3") || upper.contains("M4") {
return ChipFamily::AppleM3M4;
}
if upper.contains("M1") || upper.contains("M2") {
return ChipFamily::AppleM1M2;
}
return ChipFamily::AppleM1M2;
}
let brand = sysctl_n("machdep.cpu.brand_string").unwrap_or_default();
if brand.to_uppercase().contains("INTEL") {
return ChipFamily::IntelMac;
}
ChipFamily::Unknown
}
fn try_probe_macos() -> Result<HwAccelCapabilities, String> {
let chip = detect_chip_family();
if chip == ChipFamily::Unknown {
return Ok(HwAccelCapabilities::none());
}
let (codecs, supports_hdr) = match chip {
ChipFamily::AppleM1M2 => (
vec!["h264".to_string(), "hevc".to_string()],
true,
),
ChipFamily::AppleM3M4 => (
vec!["h264".to_string(), "hevc".to_string(), "av1".to_string()],
true,
),
ChipFamily::IntelMac => (
vec!["h264".to_string(), "hevc".to_string()],
false,
),
ChipFamily::Unknown => unreachable!("handled above"),
};
let device = HwAccelDevice {
kind: HwKind::VideoToolbox,
driver: None,
render_node: None,
supported_codecs: codecs,
max_width: 8192,
max_height: 4320,
supports_hdr,
};
Ok(HwAccelCapabilities {
devices: vec![device],
})
}