video/external: Make OpenH264 support optional by adding the `openh264` feature

And enable it in desktop and tests.
This commit is contained in:
TÖRÖK Attila 2024-09-12 19:02:40 +02:00
parent 0e1d500654
commit 8ad1c1069c
7 changed files with 46 additions and 24 deletions

View File

@ -23,7 +23,7 @@ ruffle_core = { path = "../core", features = ["audio", "clap", "mp3", "nellymose
ruffle_render = { path = "../render", features = ["clap"] } ruffle_render = { path = "../render", features = ["clap"] }
ruffle_render_wgpu = { path = "../render/wgpu", features = ["clap"] } ruffle_render_wgpu = { path = "../render/wgpu", features = ["clap"] }
ruffle_video_software = { path = "../video/software", optional = true } ruffle_video_software = { path = "../video/software", optional = true }
ruffle_video_external = { path = "../video/external", optional = true } ruffle_video_external = { path = "../video/external", features = ["openh264"], optional = true }
ruffle_frontend_utils = { path = "../frontend-utils", features = ["cpal"] } ruffle_frontend_utils = { path = "../frontend-utils", features = ["cpal"] }
tracing = { workspace = true } tracing = { workspace = true }
tracing-subscriber = { workspace = true } tracing-subscriber = { workspace = true }

View File

@ -234,15 +234,14 @@ impl ActivePlayer {
let openh264 = tokio::task::block_in_place(|| { let openh264 = tokio::task::block_in_place(|| {
OpenH264Codec::load(&opt.cache_directory.join("video")) OpenH264Codec::load(&opt.cache_directory.join("video"))
}); });
let openh264 = match openh264 { let backend = match openh264 {
Ok(codec) => Some(codec), Ok(codec) => ExternalVideoBackend::new_with_openh264(codec),
Err(e) => { Err(e) => {
tracing::error!("Failed to load OpenH264: {}", e); tracing::error!("Failed to load OpenH264: {}", e);
None ExternalVideoBackend::new()
} }
}; };
builder = builder.with_video(backend);
builder = builder.with_video(ExternalVideoBackend::new(openh264));
} }
} else { } else {
#[cfg(feature = "software_video")] #[cfg(feature = "software_video")]

View File

@ -16,7 +16,7 @@ ruffle_render = { path = "../../render", features = ["serde"] }
ruffle_input_format = { path = "../input-format" } ruffle_input_format = { path = "../input-format" }
ruffle_socket_format = { path = "../socket-format" } ruffle_socket_format = { path = "../socket-format" }
ruffle_video_software = { path = "../../video/software", optional = true } ruffle_video_software = { path = "../../video/software", optional = true }
ruffle_video_external = { path = "../../video/external", optional = true } ruffle_video_external = { path = "../../video/external", features = ["openh264"], optional = true }
image = { workspace = true, features = ["png"] } image = { workspace = true, features = ["png"] }
regex = "1.10.6" regex = "1.10.6"
url = { workspace = true } url = { workspace = true }

View File

@ -187,7 +187,7 @@ impl PlayerOptions {
.map_err(|e| anyhow!("Couldn't load OpenH264: {}", e))?; .map_err(|e| anyhow!("Couldn't load OpenH264: {}", e))?;
player_builder = player_builder =
player_builder.with_video(ExternalVideoBackend::new(Some(openh264))); player_builder.with_video(ExternalVideoBackend::new_with_openh264(openh264));
} }
#[cfg(all( #[cfg(all(

View File

@ -17,9 +17,12 @@ ruffle_video_software = { path = "../software" }
thiserror = { workspace = true } thiserror = { workspace = true }
# Needed for OpenH264: # Needed for OpenH264:
libloading = "0.8.5" libloading = { version = "0.8.5", optional = true }
reqwest = { version = "0.12.7", default-features = false, features = ["blocking"] } reqwest = { version = "0.12.7", default-features = false, features = ["blocking"], optional = true }
hex = "0.4.3" hex = { version = "0.4.3", optional = true }
bzip2 = { version = "0.4.4", features = ["static"] } bzip2 = { version = "0.4.4", features = ["static"], optional = true }
tempfile = "3.12.0" tempfile = { version = "3.12.0", optional = true }
sha2 = "0.10.8" sha2 = { version = "0.10.8", optional = true }
[features]
openh264 = ["libloading", "reqwest", "hex", "bzip2", "tempfile", "sha2"]

View File

@ -1,3 +1,4 @@
#[cfg(feature = "openh264")]
use crate::decoder::openh264::OpenH264Codec; use crate::decoder::openh264::OpenH264Codec;
use crate::decoder::VideoDecoder; use crate::decoder::VideoDecoder;
@ -26,21 +27,42 @@ enum ProxyOrStream {
/// except for H.264, for which it uses an external decoder. /// except for H.264, for which it uses an external decoder.
pub struct ExternalVideoBackend { pub struct ExternalVideoBackend {
streams: SlotMap<VideoStreamHandle, ProxyOrStream>, streams: SlotMap<VideoStreamHandle, ProxyOrStream>,
#[cfg(feature = "openh264")]
openh264_codec: Option<OpenH264Codec>, openh264_codec: Option<OpenH264Codec>,
software: SoftwareVideoBackend, software: SoftwareVideoBackend,
} }
impl Default for ExternalVideoBackend { impl Default for ExternalVideoBackend {
fn default() -> Self { fn default() -> Self {
Self::new(None) Self::new()
} }
} }
impl ExternalVideoBackend { impl ExternalVideoBackend {
pub fn new(openh264_codec: Option<OpenH264Codec>) -> Self { fn make_decoder(&mut self) -> Result<Box<dyn VideoDecoder>, Error> {
#[cfg(feature = "openh264")]
if let Some(h264_codec) = self.openh264_codec.as_ref() {
let decoder = Box::new(crate::decoder::openh264::H264Decoder::new(h264_codec));
return Ok(decoder);
}
Err(Error::DecoderError("No OpenH264".into()))
}
pub fn new() -> Self {
Self { Self {
streams: SlotMap::with_key(), streams: SlotMap::with_key(),
openh264_codec, #[cfg(feature = "openh264")]
openh264_codec: None,
software: SoftwareVideoBackend::new(),
}
}
#[cfg(feature = "openh264")]
pub fn new_with_openh264(openh264_codec: OpenH264Codec) -> Self {
Self {
streams: SlotMap::with_key(),
openh264_codec: Some(openh264_codec),
software: SoftwareVideoBackend::new(), software: SoftwareVideoBackend::new(),
} }
} }
@ -57,13 +79,9 @@ impl VideoBackend for ExternalVideoBackend {
filter: VideoDeblocking, filter: VideoDeblocking,
) -> Result<VideoStreamHandle, Error> { ) -> Result<VideoStreamHandle, Error> {
let proxy_or_stream = if codec == VideoCodec::H264 { let proxy_or_stream = if codec == VideoCodec::H264 {
if let Some(h264_codec) = self.openh264_codec.as_ref() { let decoder = self.make_decoder()?;
let decoder = Box::new(crate::decoder::openh264::H264Decoder::new(h264_codec)); let stream = VideoStream::new(decoder);
let stream = VideoStream::new(decoder); ProxyOrStream::Owned(stream)
ProxyOrStream::Owned(stream)
} else {
return Err(Error::DecoderError("No OpenH264".into()));
}
} else { } else {
ProxyOrStream::Proxied( ProxyOrStream::Proxied(
self.software self.software

View File

@ -1,11 +1,13 @@
// bindgen ../openh264/codec/api/wels/codec_api.h --no-prepend-enum-name \ // bindgen ../openh264/codec/api/wels/codec_api.h --no-prepend-enum-name \
// --dynamic-loading OpenH264 -o openh264_sys.rs // --dynamic-loading OpenH264 -o openh264_sys.rs
#[cfg(feature = "openh264")]
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[allow(dead_code)] #[allow(dead_code)]
mod openh264_sys; mod openh264_sys;
#[cfg(feature = "openh264")]
pub mod openh264; pub mod openh264;
pub use ruffle_video_software::decoder::VideoDecoder; pub use ruffle_video_software::decoder::VideoDecoder;