diff --git a/desktop/src/player.rs b/desktop/src/player.rs index dd32d6daf..79f3210bc 100644 --- a/desktop/src/player.rs +++ b/desktop/src/player.rs @@ -224,16 +224,16 @@ impl ActivePlayer { #[cfg(feature = "external_video")] { use ruffle_video_external::backend::ExternalVideoBackend; - let path = tokio::task::block_in_place(ExternalVideoBackend::get_openh264); - let openh264_path = match path { - Ok(path) => Some(path), + let openh264 = tokio::task::block_in_place(ExternalVideoBackend::load_openh264); + let openh264 = match openh264 { + Ok(codec) => Some(codec), Err(e) => { - tracing::error!("Couldn't get OpenH264: {}", e); + tracing::error!("Failed to load OpenH264: {}", e); None } }; - builder = builder.with_video(ExternalVideoBackend::new(openh264_path)); + builder = builder.with_video(ExternalVideoBackend::new(openh264)); } } else { #[cfg(feature = "software_video")] diff --git a/tests/framework/src/options.rs b/tests/framework/src/options.rs index 068abaf38..b837c9f66 100644 --- a/tests/framework/src/options.rs +++ b/tests/framework/src/options.rs @@ -178,11 +178,11 @@ impl PlayerOptions { #[cfg(feature = "ruffle_video_external")] { use ruffle_video_external::backend::ExternalVideoBackend; - let openh264_path = ExternalVideoBackend::get_openh264() - .map_err(|e| anyhow!("Couldn't get OpenH264: {}", e))?; + let openh264 = ExternalVideoBackend::load_openh264() + .map_err(|e| anyhow!("Couldn't load OpenH264: {}", e))?; player_builder = - player_builder.with_video(ExternalVideoBackend::new(Some(openh264_path))); + player_builder.with_video(ExternalVideoBackend::new(Some(openh264))); } #[cfg(all( diff --git a/video/external/src/backend.rs b/video/external/src/backend.rs index d441d42eb..d684294be 100644 --- a/video/external/src/backend.rs +++ b/video/external/src/backend.rs @@ -26,6 +26,7 @@ enum ProxyOrStream { } struct OpenH264Data { + local_filenames: Vec<&'static str>, download_filename: &'static str, download_sha256: &'static str, } @@ -49,6 +50,12 @@ impl ExternalVideoBackend { const OS: &str = std::env::consts::OS; const ARCH: &str = std::env::consts::ARCH; + let local_filenames = match OS { + "linux" => vec!["libopenh264.so.7", "libopenh264.so.2.4.1", "libopenh264.so"], + // TODO: investigate other OSes + _ => vec![], + }; + // Source: https://github.com/cisco/openh264/releases/tag/v2.4.1 let (download_filename, download_sha256) = match (OS, ARCH) { ("linux", "x86") => ( @@ -87,17 +94,19 @@ impl ExternalVideoBackend { }; Ok(OpenH264Data { + local_filenames, download_filename, download_sha256, }) } - pub fn get_openh264() -> Result> { + fn download_openh264( + openh264_data: &OpenH264Data, + ) -> Result> { // See the license at: https://www.openh264.org/BINARY_LICENSE.txt const URL_BASE: &str = "http://ciscobinary.openh264.org/"; const URL_SUFFIX: &str = ".bz2"; - let openh264_data = Self::get_openh264_data()?; let (filename, sha256sum) = ( openh264_data.download_filename, openh264_data.download_sha256, @@ -140,19 +149,32 @@ impl ExternalVideoBackend { Ok(filepath) } - pub fn new(openh264_lib_filepath: Option) -> Self { - let h264_codec = if let Some(openh264_lib_filepath) = openh264_lib_filepath { - tracing::info!("Using OpenH264 at {:?}", openh264_lib_filepath); - OpenH264Codec::new(&openh264_lib_filepath) - .inspect_err(|err| tracing::error!("Error loading OpenH264: {:?}", err)) - .ok() - } else { - None - }; + pub fn load_openh264() -> Result> { + let openh264_data = Self::get_openh264_data()?; + for filename in &openh264_data.local_filenames { + match OpenH264Codec::new(filename) { + Ok(codec) => return Ok(codec), + Err(err) => { + tracing::warn!( + "Failed to load system OpenH264 library {}: {}", + filename, + err + ); + } + } + } + + tracing::info!("Downloading OpenH264 library"); + let filename = Self::download_openh264(&openh264_data)?; + tracing::info!("Using OpenH264 at {:?}", filename); + Ok(OpenH264Codec::new(&filename)?) + } + + pub fn new(openh264_codec: Option) -> Self { Self { streams: SlotMap::with_key(), - openh264_codec: h264_codec, + openh264_codec, software: SoftwareVideoBackend::new(), } }