desktop: Add a preference to enable the OpenH264 decoder
This commit is contained in:
parent
381b77cda0
commit
76da9621c9
|
@ -4363,6 +4363,7 @@ dependencies = [
|
|||
"ruffle_frontend_utils",
|
||||
"ruffle_render",
|
||||
"ruffle_render_wgpu",
|
||||
"ruffle_video_external",
|
||||
"ruffle_video_software",
|
||||
"sys-locale",
|
||||
"tokio",
|
||||
|
|
|
@ -23,6 +23,7 @@ ruffle_core = { path = "../core", features = ["audio", "clap", "mp3", "nellymose
|
|||
ruffle_render = { path = "../render", features = ["clap"] }
|
||||
ruffle_render_wgpu = { path = "../render/wgpu", features = ["clap"] }
|
||||
ruffle_video_software = { path = "../video/software", optional = true }
|
||||
ruffle_video_external = { path = "../video/external", optional = true }
|
||||
ruffle_frontend_utils = { path = "../frontend-utils" }
|
||||
tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
|
@ -57,13 +58,14 @@ embed-resource = "2"
|
|||
vergen = { version = "8.3.1", features = ["build", "git", "gitcl", "cargo"] }
|
||||
|
||||
[features]
|
||||
default = ["software_video"]
|
||||
default = ["software_video", "external_video"]
|
||||
jpegxr = ["ruffle_core/jpegxr"]
|
||||
|
||||
# core features
|
||||
avm_debug = ["ruffle_core/avm_debug"]
|
||||
lzma = ["ruffle_core/lzma"]
|
||||
software_video = ["ruffle_video_software"]
|
||||
external_video = ["ruffle_video_external"]
|
||||
tracy = ["tracing-tracy", "ruffle_render_wgpu/profile-with-tracy"]
|
||||
|
||||
# wgpu features
|
||||
|
|
|
@ -14,6 +14,10 @@ language = Language
|
|||
audio-output-device = Audio Output Device
|
||||
audio-output-device-default = System Default
|
||||
|
||||
enable-openh264 = Enable OpenH264
|
||||
show-license = Show License
|
||||
openh264-license = OpenH264 License
|
||||
|
||||
log-filename-pattern = Log Filename
|
||||
log-filename-pattern-single-file = Single File (ruffle.log)
|
||||
log-filename-pattern-with-timestamp = With Timestamp
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::gui::{available_languages, optional_text, text};
|
|||
use crate::log::FilenamePattern;
|
||||
use crate::preferences::{storage::StorageBackend, GlobalPreferences};
|
||||
use cpal::traits::{DeviceTrait, HostTrait};
|
||||
use egui::{Align2, Button, ComboBox, DragValue, Grid, Ui, Widget, Window};
|
||||
use egui::{Align2, Button, Checkbox, ComboBox, DragValue, Grid, Ui, Widget, Window};
|
||||
use ruffle_render_wgpu::clap::{GraphicsBackend, PowerPreference};
|
||||
use std::borrow::Cow;
|
||||
use unic_langid::LanguageIdentifier;
|
||||
|
@ -26,6 +26,10 @@ pub struct PreferencesDialog {
|
|||
available_output_devices: Vec<String>,
|
||||
output_device_changed: bool,
|
||||
|
||||
enable_openh264: bool,
|
||||
enable_openh264_changed: bool,
|
||||
openh264_license_visible: bool,
|
||||
|
||||
recent_limit: usize,
|
||||
recent_limit_changed: bool,
|
||||
|
||||
|
@ -68,6 +72,10 @@ impl PreferencesDialog {
|
|||
available_output_devices,
|
||||
output_device_changed: false,
|
||||
|
||||
enable_openh264: preferences.openh264_enabled(),
|
||||
enable_openh264_changed: false,
|
||||
openh264_license_visible: false,
|
||||
|
||||
recent_limit: preferences.recent_limit(),
|
||||
recent_limit_changed: false,
|
||||
|
||||
|
@ -104,6 +112,8 @@ impl PreferencesDialog {
|
|||
|
||||
self.show_audio_preferences(locale, ui);
|
||||
|
||||
self.show_video_preferences(egui_ctx, locale, ui);
|
||||
|
||||
self.show_log_preferences(locale, ui);
|
||||
|
||||
self.show_storage_preferences(locale, &locked_text, ui);
|
||||
|
@ -136,6 +146,7 @@ impl PreferencesDialog {
|
|||
self.graphics_backend != self.preferences.graphics_backends()
|
||||
|| self.power_preference != self.preferences.graphics_power_preference()
|
||||
|| self.output_device != self.preferences.output_device_name()
|
||||
|| self.enable_openh264 != self.preferences.openh264_enabled()
|
||||
|| self.log_filename_pattern != self.preferences.log_filename_pattern()
|
||||
|| self.storage_backend != self.preferences.storage_backend()
|
||||
}
|
||||
|
@ -261,6 +272,44 @@ impl PreferencesDialog {
|
|||
ui.end_row();
|
||||
}
|
||||
|
||||
fn show_video_preferences(
|
||||
&mut self,
|
||||
egui_ctx: &egui::Context,
|
||||
locale: &LanguageIdentifier,
|
||||
ui: &mut Ui,
|
||||
) {
|
||||
#[cfg(feature = "external_video")]
|
||||
{
|
||||
ui.label(text(locale, "enable-openh264"));
|
||||
|
||||
let previous = self.enable_openh264;
|
||||
ui.add(Checkbox::without_text(&mut self.enable_openh264));
|
||||
ui.end_row();
|
||||
|
||||
ui.small("OpenH264 Video Codec provided by Cisco Systems, Inc.");
|
||||
if self.enable_openh264 != previous {
|
||||
self.enable_openh264_changed = true;
|
||||
}
|
||||
if ui.small_button(text(locale, "show-license")).clicked() {
|
||||
self.openh264_license_visible = true;
|
||||
};
|
||||
let available_size = egui_ctx.available_rect().size();
|
||||
egui::Window::new(text(locale, "openh264-license"))
|
||||
.collapsible(false)
|
||||
.resizable(false)
|
||||
.anchor(Align2::CENTER_CENTER, egui::Vec2::ZERO)
|
||||
.scroll(true)
|
||||
.open(&mut self.openh264_license_visible)
|
||||
.min_size(available_size * 0.8)
|
||||
.max_size(available_size * 0.9)
|
||||
.show(egui_ctx, |ui| {
|
||||
// Source: https://www.openh264.org/BINARY_LICENSE.txt
|
||||
ui.monospace(include_str!("../../../assets/OpenH264-license.txt"));
|
||||
});
|
||||
ui.end_row();
|
||||
}
|
||||
}
|
||||
|
||||
fn show_log_preferences(&mut self, locale: &LanguageIdentifier, ui: &mut Ui) {
|
||||
ui.label(text(locale, "log-filename-pattern"));
|
||||
|
||||
|
@ -359,6 +408,9 @@ impl PreferencesDialog {
|
|||
preferences.set_output_device(self.output_device.clone());
|
||||
// [NA] TODO: Inform the running player that the device changed
|
||||
}
|
||||
if self.enable_openh264_changed {
|
||||
preferences.set_enable_openh264(self.enable_openh264);
|
||||
}
|
||||
if self.log_filename_pattern_changed {
|
||||
preferences.set_log_filename_pattern(self.log_filename_pattern);
|
||||
}
|
||||
|
|
|
@ -220,9 +220,27 @@ impl ActivePlayer {
|
|||
RfdNavigatorInterface,
|
||||
);
|
||||
|
||||
if cfg!(feature = "software_video") {
|
||||
builder =
|
||||
builder.with_video(ruffle_video_software::backend::SoftwareVideoBackend::new());
|
||||
if cfg!(feature = "external_video") && preferences.openh264_enabled() {
|
||||
#[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),
|
||||
Err(e) => {
|
||||
tracing::error!("Couldn't get OpenH264: {}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
builder = builder.with_video(ExternalVideoBackend::new(openh264_path));
|
||||
}
|
||||
} else {
|
||||
#[cfg(feature = "software_video")]
|
||||
{
|
||||
builder =
|
||||
builder.with_video(ruffle_video_software::backend::SoftwareVideoBackend::new());
|
||||
}
|
||||
}
|
||||
|
||||
let renderer = WgpuRenderBackend::new(descriptors, movie_view)
|
||||
|
|
|
@ -145,6 +145,13 @@ impl GlobalPreferences {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn openh264_enabled(&self) -> bool {
|
||||
self.preferences
|
||||
.lock()
|
||||
.expect("Preferences is not reentrant")
|
||||
.enable_openh264
|
||||
}
|
||||
|
||||
pub fn log_filename_pattern(&self) -> FilenamePattern {
|
||||
self.preferences
|
||||
.lock()
|
||||
|
@ -229,6 +236,7 @@ pub struct SavedGlobalPreferences {
|
|||
pub output_device: Option<String>,
|
||||
pub mute: bool,
|
||||
pub volume: f32,
|
||||
pub enable_openh264: bool,
|
||||
pub recent_limit: usize,
|
||||
pub log: LogPreferences,
|
||||
pub storage: StoragePreferences,
|
||||
|
@ -247,6 +255,7 @@ impl Default for SavedGlobalPreferences {
|
|||
output_device: None,
|
||||
mute: false,
|
||||
volume: 1.0,
|
||||
enable_openh264: true,
|
||||
recent_limit: 10,
|
||||
log: Default::default(),
|
||||
storage: Default::default(),
|
||||
|
|
|
@ -51,6 +51,10 @@ pub fn read_preferences(input: &str) -> ParseDetails<SavedGlobalPreferences> {
|
|||
result.mute = value;
|
||||
};
|
||||
|
||||
if let Some(value) = document.get_bool(&mut cx, "enable_openh264") {
|
||||
result.enable_openh264 = value;
|
||||
};
|
||||
|
||||
if let Some(value) = document.get_integer(&mut cx, "recent_limit") {
|
||||
result.recent_limit = value as usize;
|
||||
}
|
||||
|
@ -327,6 +331,46 @@ mod tests {
|
|||
assert_eq!(Vec::<ParseWarning>::new(), result.warnings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enable_openh264() {
|
||||
let result = read_preferences("enable_openh264 = \"true\"");
|
||||
assert_eq!(
|
||||
&SavedGlobalPreferences {
|
||||
enable_openh264: true,
|
||||
..Default::default()
|
||||
},
|
||||
result.values()
|
||||
);
|
||||
assert_eq!(
|
||||
vec![ParseWarning::UnexpectedType {
|
||||
expected: "boolean",
|
||||
actual: "string",
|
||||
path: "enable_openh264".to_string()
|
||||
}],
|
||||
result.warnings
|
||||
);
|
||||
|
||||
let result = read_preferences("enable_openh264 = false");
|
||||
assert_eq!(
|
||||
&SavedGlobalPreferences {
|
||||
enable_openh264: false,
|
||||
..Default::default()
|
||||
},
|
||||
result.values()
|
||||
);
|
||||
assert_eq!(Vec::<ParseWarning>::new(), result.warnings);
|
||||
|
||||
let result = read_preferences("");
|
||||
assert_eq!(
|
||||
&SavedGlobalPreferences {
|
||||
enable_openh264: true,
|
||||
..Default::default()
|
||||
},
|
||||
result.values()
|
||||
);
|
||||
assert_eq!(Vec::<ParseWarning>::new(), result.warnings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log_filename() {
|
||||
let result = read_preferences("log = {filename_pattern = 5}");
|
||||
|
|
|
@ -59,6 +59,13 @@ impl<'a> PreferencesWriter<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn set_enable_openh264(&mut self, enable: bool) {
|
||||
self.0.edit(|values, toml_document| {
|
||||
toml_document["enable_openh264"] = value(enable);
|
||||
values.enable_openh264 = enable;
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_log_filename_pattern(&mut self, pattern: FilenamePattern) {
|
||||
self.0.edit(|values, toml_document| {
|
||||
toml_document["log"]["filename_pattern"] = value(pattern.as_str());
|
||||
|
@ -168,6 +175,20 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_enable_openh264() {
|
||||
test(
|
||||
"",
|
||||
|writer| writer.set_enable_openh264(false),
|
||||
"enable_openh264 = false\n",
|
||||
);
|
||||
test(
|
||||
"enable_openh264 = false",
|
||||
|writer| writer.set_enable_openh264(true),
|
||||
"enable_openh264 = true\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_log_filename_pattern() {
|
||||
test(
|
||||
|
|
|
@ -10,7 +10,7 @@ use ruffle_video::VideoStreamHandle;
|
|||
use ruffle_video_software::backend::SoftwareVideoBackend;
|
||||
use slotmap::SlotMap;
|
||||
use std::fs::File;
|
||||
use std::io::{copy, Write};
|
||||
use std::io::copy;
|
||||
use std::path::PathBuf;
|
||||
use swf::{VideoCodec, VideoDeblocking};
|
||||
|
||||
|
@ -38,9 +38,6 @@ impl Default for ExternalVideoBackend {
|
|||
}
|
||||
}
|
||||
|
||||
/// Source: https://www.openh264.org/BINARY_LICENSE.txt
|
||||
const BINARY_LICENSE: &[u8] = include_bytes!("BINARY_LICENSE.txt");
|
||||
|
||||
impl ExternalVideoBackend {
|
||||
fn get_openh264_data() -> Result<(&'static str, &'static str), Box<dyn std::error::Error>> {
|
||||
// Source: https://github.com/cisco/openh264/releases/tag/v2.4.1
|
||||
|
@ -82,6 +79,7 @@ impl ExternalVideoBackend {
|
|||
}
|
||||
|
||||
pub fn get_openh264() -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||
// See the license at: https://www.openh264.org/BINARY_LICENSE.txt
|
||||
const URL_BASE: &str = "http://ciscobinary.openh264.org/";
|
||||
const URL_SUFFIX: &str = ".bz2";
|
||||
|
||||
|
@ -94,8 +92,6 @@ impl ExternalVideoBackend {
|
|||
|
||||
// If the binary doesn't exist in the expected location, download it.
|
||||
if !filepath.is_file() {
|
||||
File::create("OpenH264-license.txt")?.write_all(BINARY_LICENSE)?;
|
||||
|
||||
let url = format!("{}{}{}", URL_BASE, filename, URL_SUFFIX);
|
||||
let response = reqwest::blocking::get(url)?;
|
||||
let bytes = response.bytes()?;
|
||||
|
|
Loading…
Reference in New Issue