use clipbin_core::VideoCodec; /// Official OBS hardware encoders for each codec, most preferred first. /// /// Texture-based encoders come first because they take frames straight from /// the GPU; their counterparts copy each frame through system memory. Software /// encoders are deliberately absent: a codec without a working hardware /// encoder is unavailable, never silently software-encoded. pub fn hardware_candidates(codec: VideoCodec) -> &'static [&'static str] { #[cfg(windows)] return match codec { VideoCodec::H264 => &[ "obs_nvenc_h264_tex", "h264_texture_amf", "obs_qsv11_v2", "obs_nvenc_h264_soft", "obs_qsv11_soft_v2", "h264_fallback_amf", ], VideoCodec::Hevc => &[ "obs_nvenc_hevc_tex", "h265_texture_amf", "obs_qsv11_hevc", "obs_nvenc_hevc_soft", "obs_qsv11_hevc_soft", "h265_fallback_amf", ], VideoCodec::Av1 => &[ "obs_nvenc_av1_tex", "av1_texture_amf", "obs_qsv11_av1", "obs_nvenc_av1_soft", "obs_qsv11_av1_soft", "av1_fallback_amf", ], }; #[cfg(not(windows))] return match codec { VideoCodec::H264 => &[ "obs_nvenc_h264_tex", "ffmpeg_vaapi_tex", "obs_nvenc_h264_soft", "ffmpeg_vaapi", ], VideoCodec::Hevc => &[ "obs_nvenc_hevc_tex", "hevc_ffmpeg_vaapi_tex", "obs_nvenc_hevc_soft", "hevc_ffmpeg_vaapi", ], VideoCodec::Av1 => &[ "obs_nvenc_av1_tex", "av1_ffmpeg_vaapi_tex", "obs_nvenc_av1_soft", "av1_ffmpeg_vaapi", ], }; } /// Registered encoders for `codec`, in preference order. /// /// Registration only means the plugin loaded. Whether the device can actually /// encode is proven by starting an output; see `Recorder`. pub fn registered_candidates<'a>( codec: VideoCodec, registered: &[impl AsRef], ) -> Vec<&'a str> { hardware_candidates(codec) .iter() .copied() .filter(|id| registered.iter().any(|r| r.as_ref() == *id)) .collect() } pub const ALL_CODECS: [VideoCodec; 3] = [VideoCodec::H264, VideoCodec::Hevc, VideoCodec::Av1]; #[cfg(test)] mod tests { use super::*; #[test] fn candidates_keep_preference_order_and_skip_unregistered() { let first = hardware_candidates(VideoCodec::Hevc)[0]; let third = hardware_candidates(VideoCodec::Hevc)[2]; let registered = [third, "obs_x264", first]; assert_eq!( registered_candidates(VideoCodec::Hevc, ®istered), [first, third] ); } #[test] fn software_encoders_are_never_candidates() { for codec in ALL_CODECS { for id in hardware_candidates(codec) { assert!( ![ "obs_x264", "ffmpeg_svt_av1", "ffmpeg_aom_av1", "ffmpeg_openh264" ] .contains(id) ); } } } }