#![forbid(unsafe_code)] use gstreamer as gst; /// Pick the client-side H.264 decoder in a predictable preference order. /// /// Inputs: none, though operators may override the choice with /// `LESAVKA_H264_DECODER=`. /// Outputs: the chosen decoder element name, or `decodebin` as a last-resort /// fallback when no explicit decoder is present. /// Why: `decodebin` is flexible, but a stable preference order makes decode /// behavior easier to reason about and compare in diagnostics. #[must_use] pub fn pick_h264_decoder() -> String { if let Ok(raw) = std::env::var("LESAVKA_H264_DECODER") { let name = raw.trim(); if name.eq_ignore_ascii_case("decodebin") { return "decodebin".to_string(); } if !name.is_empty() && buildable_decoder(name) { return name.to_string(); } } for name in [ "avdec_h264", "openh264dec", "nvh264dec", "nvh264sldec", "vah264dec", "vaapih264dec", "v4l2h264dec", "v4l2slh264dec", ] { if buildable_decoder(name) { return name.to_string(); } } "decodebin".to_string() } fn buildable_decoder(name: &str) -> bool { #[cfg(coverage)] if std::env::var("TEST_FAIL_GST_INIT").is_ok() { return false; } if gst::init().is_err() { return false; } #[cfg(coverage)] if std::env::var("TEST_DISABLE_H264_DECODER_FACTORY").is_ok() { return false; } gst::ElementFactory::find(name).is_some() && gst::ElementFactory::make(name).build().is_ok() }