Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add H.264 decoding by utilizing OpenH264 from Cisco #14654

Merged
merged 8 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ members = [

"video",
"video/software",
"video/external",

"tests",
"tests/input-format",
Expand Down
43 changes: 39 additions & 4 deletions core/src/streams.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,11 +973,43 @@ impl<'gc> NetStream<'gc> {
(_, _, FlvVideoPacket::CommandFrame(_command)) => {
tracing::warn!("Stub: FLV command frame processing")
}
(_, _, FlvVideoPacket::AvcSequenceHeader(_data)) => {
tracing::warn!("Stub: FLV AVC/H.264 Sequence Header processing")
(Some(video_handle), _, FlvVideoPacket::AvcSequenceHeader(data)) => {
match context
.video
.configure_video_stream_decoder(video_handle, data)
{
Ok(_) => {}
Err(e) => {
tracing::error!("Configuring video decoder {} failed: {}", frame_id, e);
}
}
}
(_, _, FlvVideoPacket::AvcNalu { .. }) => {
tracing::warn!("Stub: FLV AVC/H.264 NALU processing")
(
Some(video_handle),
Some(codec),
FlvVideoPacket::AvcNalu {
composition_time_offset: _,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to assume this means Flash didn't actually use the composition time offset in FLV H.264 streams either... AFAIK that sounds plausible to me (FLV is already variable framerate) but I wanted to just double-check.

Copy link
Member Author

@torokati44 torokati44 Mar 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to assume this means Flash didn't actually use the composition time offset in FLV H.264 streams either...

Oh, don't assume that! This may be exactly what I asked about on Discord. I just haven't connected the dots...
Also at the beginning, I didn't care about anything else than what's strictly necessary for "get picture on screen", and just never got back to this after.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#15747 should help investigating this.

data,
},
) => {
let encoded_frame = EncodedFrame {
codec,
data,
frame_id,
};

match context.video.decode_video_stream_frame(
video_handle,
encoded_frame,
context.renderer,
) {
Ok(bitmap_info) => {
write.last_decoded_bitmap = Some(bitmap_info);
}
Err(e) => {
tracing::error!("Decoding video frame {} failed: {}", frame_id, e);
}
}
}
(_, _, FlvVideoPacket::AvcEndOfSequence) => {
tracing::warn!("Stub: FLV AVC/H.264 End of Sequence processing")
Expand All @@ -988,6 +1020,9 @@ impl<'gc> NetStream<'gc> {
video_data.codec_id as u8
)
}
(None, _, _) => {
tracing::error!("No video handle")
}
}

match &mut write.stream_type {
Expand Down
4 changes: 3 additions & 1 deletion desktop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -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
Expand Down
59 changes: 59 additions & 0 deletions desktop/assets/OpenH264-license.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
-------------------------------------------------------
About The Cisco-Provided Binary of OpenH264 Video Codec
-------------------------------------------------------

Cisco provides this program under the terms of the BSD license.

Additionally, this binary is licensed under Cisco’s AVC/H.264 Patent Portfolio License from MPEG LA, at no cost to you, provided that the requirements and conditions shown below in the AVC/H.264 Patent Portfolio sections are met.

As with all AVC/H.264 codecs, you may also obtain your own patent license from MPEG LA or from the individual patent owners, or proceed at your own risk. Your rights from Cisco under the BSD license are not affected by this choice.

For more information on the OpenH264 binary licensing, please see the OpenH264 FAQ found at http://www.openh264.org/faq.html#binary

A corresponding source code to this binary program is available under the same BSD terms, which can be found at http://www.openh264.org

-----------
BSD License
-----------

Copyright © 2014 Cisco Systems, Inc.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-----------------------------------------
AVC/H.264 Patent Portfolio License Notice
-----------------------------------------

The binary form of this Software is distributed by Cisco under the AVC/H.264 Patent Portfolio License from MPEG LA, and is subject to the following requirements, which may or may not be applicable to your use of this software:

THIS PRODUCT IS LICENSED UNDER THE AVC PATENT PORTFOLIO LICENSE FOR THE PERSONAL USE OF A CONSUMER OR OTHER USES IN WHICH IT DOES NOT RECEIVE REMUNERATION TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE AVC STANDARD (“AVC VIDEO”) AND/OR (ii) DECODE AVC VIDEO THAT WAS ENCODED BY A CONSUMER ENGAGED IN A PERSONAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER LICENSED TO PROVIDE AVC VIDEO. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE HTTP://WWW.MPEGLA.COM

Accordingly, please be advised that content providers and broadcasters using AVC/H.264 in their service may be required to obtain a separate use license from MPEG LA, referred to as "(b) sublicenses" in the SUMMARY OF AVC/H.264 LICENSE TERMS from MPEG LA found at http://www.openh264.org/mpegla

---------------------------------------------
AVC/H.264 Patent Portfolio License Conditions
---------------------------------------------

In addition, the Cisco-provided binary of this Software is licensed under Cisco's license from MPEG LA only if the following conditions are met:

1. The Cisco-provided binary is separately downloaded to an end user’s device, and not integrated into or combined with third party software prior to being downloaded to the end user’s device;

2. The end user must have the ability to control (e.g., to enable, disable, or re-enable) the use of the Cisco-provided binary;

3. Third party software, in the location where end users can control the use of the Cisco-provided binary, must display the following text:

"OpenH264 Video Codec provided by Cisco Systems, Inc."

4. Any third-party software that makes use of the Cisco-provided binary must reproduce all of the above text, as well as this last condition, in the EULA and/or in another location where licensing information is to be presented to the end user.



v1.0
4 changes: 4 additions & 0 deletions desktop/assets/texts/en-US/preferences_dialog.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 53 additions & 1 deletion desktop/src/gui/dialogs/preferences_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,

Expand Down Expand Up @@ -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,

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -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"));

Expand Down Expand Up @@ -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);
}
Expand Down
24 changes: 21 additions & 3 deletions desktop/src/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading