video: Prefer loading system OpenH264 library to downloading it

Some systems do have OpenH264 installed and in order to get
rid of the delay caused by downloading the library
(and needlessly downloading it in the first place),
an attempt is made first to load OpenH264 as a system library.
When loading fails (or version is mismatched), only then Ruffle
downloads OpenH264 and uses that version of the library.
This commit is contained in:
Kamil Jarosz 2024-09-06 23:24:16 +02:00 committed by TÖRÖK Attila
parent f7ec20fd92
commit 22fda90f92
3 changed files with 42 additions and 20 deletions

View File

@ -224,16 +224,16 @@ impl ActivePlayer {
#[cfg(feature = "external_video")] #[cfg(feature = "external_video")]
{ {
use ruffle_video_external::backend::ExternalVideoBackend; use ruffle_video_external::backend::ExternalVideoBackend;
let path = tokio::task::block_in_place(ExternalVideoBackend::get_openh264); let openh264 = tokio::task::block_in_place(ExternalVideoBackend::load_openh264);
let openh264_path = match path { let openh264 = match openh264 {
Ok(path) => Some(path), Ok(codec) => Some(codec),
Err(e) => { Err(e) => {
tracing::error!("Couldn't get OpenH264: {}", e); tracing::error!("Failed to load OpenH264: {}", e);
None None
} }
}; };
builder = builder.with_video(ExternalVideoBackend::new(openh264_path)); builder = builder.with_video(ExternalVideoBackend::new(openh264));
} }
} else { } else {
#[cfg(feature = "software_video")] #[cfg(feature = "software_video")]

View File

@ -178,11 +178,11 @@ impl PlayerOptions {
#[cfg(feature = "ruffle_video_external")] #[cfg(feature = "ruffle_video_external")]
{ {
use ruffle_video_external::backend::ExternalVideoBackend; use ruffle_video_external::backend::ExternalVideoBackend;
let openh264_path = ExternalVideoBackend::get_openh264() let openh264 = ExternalVideoBackend::load_openh264()
.map_err(|e| anyhow!("Couldn't get OpenH264: {}", e))?; .map_err(|e| anyhow!("Couldn't load OpenH264: {}", e))?;
player_builder = player_builder =
player_builder.with_video(ExternalVideoBackend::new(Some(openh264_path))); player_builder.with_video(ExternalVideoBackend::new(Some(openh264)));
} }
#[cfg(all( #[cfg(all(

View File

@ -26,6 +26,7 @@ enum ProxyOrStream {
} }
struct OpenH264Data { struct OpenH264Data {
local_filenames: Vec<&'static str>,
download_filename: &'static str, download_filename: &'static str,
download_sha256: &'static str, download_sha256: &'static str,
} }
@ -49,6 +50,12 @@ impl ExternalVideoBackend {
const OS: &str = std::env::consts::OS; const OS: &str = std::env::consts::OS;
const ARCH: &str = std::env::consts::ARCH; 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 // Source: https://github.com/cisco/openh264/releases/tag/v2.4.1
let (download_filename, download_sha256) = match (OS, ARCH) { let (download_filename, download_sha256) = match (OS, ARCH) {
("linux", "x86") => ( ("linux", "x86") => (
@ -87,17 +94,19 @@ impl ExternalVideoBackend {
}; };
Ok(OpenH264Data { Ok(OpenH264Data {
local_filenames,
download_filename, download_filename,
download_sha256, download_sha256,
}) })
} }
pub fn get_openh264() -> Result<PathBuf, Box<dyn std::error::Error>> { fn download_openh264(
openh264_data: &OpenH264Data,
) -> Result<PathBuf, Box<dyn std::error::Error>> {
// See the license at: https://www.openh264.org/BINARY_LICENSE.txt // See the license at: https://www.openh264.org/BINARY_LICENSE.txt
const URL_BASE: &str = "http://ciscobinary.openh264.org/"; const URL_BASE: &str = "http://ciscobinary.openh264.org/";
const URL_SUFFIX: &str = ".bz2"; const URL_SUFFIX: &str = ".bz2";
let openh264_data = Self::get_openh264_data()?;
let (filename, sha256sum) = ( let (filename, sha256sum) = (
openh264_data.download_filename, openh264_data.download_filename,
openh264_data.download_sha256, openh264_data.download_sha256,
@ -140,19 +149,32 @@ impl ExternalVideoBackend {
Ok(filepath) Ok(filepath)
} }
pub fn new(openh264_lib_filepath: Option<PathBuf>) -> Self { pub fn load_openh264() -> Result<OpenH264Codec, Box<dyn std::error::Error>> {
let h264_codec = if let Some(openh264_lib_filepath) = openh264_lib_filepath { let openh264_data = Self::get_openh264_data()?;
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
};
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<OpenH264Codec>) -> Self {
Self { Self {
streams: SlotMap::with_key(), streams: SlotMap::with_key(),
openh264_codec: h264_codec, openh264_codec,
software: SoftwareVideoBackend::new(), software: SoftwareVideoBackend::new(),
} }
} }