Skip to content

Commit

Permalink
refact
Browse files Browse the repository at this point in the history
  • Loading branch information
torokati44 committed Jun 27, 2024
1 parent 7fcb366 commit e9c744b
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 109 deletions.
2 changes: 1 addition & 1 deletion video/external/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ bzip2 = { version = "0.4.4", features = ["static"], optional = true }
# Needed for WebCodecs:
web-sys = { version = "0.3.69", features = [
"VideoDecoder", "VideoDecoderConfig", "VideoDecoderInit", "EncodedVideoChunk", "EncodedVideoChunkInit",
"EncodedVideoChunkType", "DomException", "CodecState",
"EncodedVideoChunkType", "DomException", "CodecState", "VideoFrame",

"VideoFrameCopyToOptions", "VideoPixelFormat", "DomRectReadOnly"
], optional = true }
Expand Down
112 changes: 19 additions & 93 deletions video/external/src/backend.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::decoder::VideoDecoder;
#[cfg(not(target_arch = "wasm32"))]
use bzip2::read::BzDecoder;
#[cfg(not(target_arch = "wasm32"))]
use md5::{Digest, Md5};

use ruffle_render::backend::RenderBackend;
use ruffle_render::bitmap::{BitmapHandle, BitmapInfo, PixelRegion};
use ruffle_video::backend::VideoBackend;
Expand All @@ -11,10 +8,6 @@ use ruffle_video::frame::{EncodedFrame, FrameDependency};
use ruffle_video::VideoStreamHandle;
use ruffle_video_software::backend::SoftwareVideoBackend;
use slotmap::SlotMap;
#[cfg(not(target_arch = "wasm32"))]
use std::fs::File;
#[cfg(not(target_arch = "wasm32"))]
use std::io::copy;
use std::path::PathBuf;
use swf::{VideoCodec, VideoDeblocking};

Expand Down Expand Up @@ -44,80 +37,27 @@ impl Default for ExternalVideoBackend {
}

impl ExternalVideoBackend {
#[cfg(not(target_arch = "wasm32"))]
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
match (std::env::consts::OS, std::env::consts::ARCH) {
("linux", "x86") => Ok((
"libopenh264-2.4.1-linux32.7.so",
"dd0743066117d63e1b2abc56a86506e5",
)),
("linux", "x86_64") => Ok((
"libopenh264-2.4.1-linux64.7.so",
"19c561386a9564f8510fcb7586b9d402",
)),
("linux", "arm") => Ok((
"libopenh264-2.4.1-linux-arm.7.so",
"2274a1bbd13f32b7afe22092e44fa2b5",
)),
("linux", "aarch64") => Ok((
"libopenh264-2.4.1-linux-arm64.7.so",
"2aa205f08077aa2d049032e0b56c5b84",
)),
("macos", "x86_64") => Ok((
"libopenh264-2.4.1-mac-x64.dylib",
"9fefa1e0279a49b8a4e9cf6fc148bc0c",
)),
("macos", "aarch64") => Ok((
"libopenh264-2.4.1-mac-arm64.dylib",
"41f59bb5696ffeadbfba3a8a95ec39b7",
)),
("windows", "x86") => Ok((
"openh264-2.4.1-win32.dll",
"a9360e6dd1e24320c3d65a0c65bf14a4",
)),
("windows", "x86_64") => Ok((
"openh264-2.4.1-win64.dll",
"c85406e6b73812ec3fb9da5f898c6a9e",
)),
(os, arch) => Err(format!("Unsupported OS/ARCH: {} {}", os, arch).into()),
}
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "openh264")]
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";

let (filename, md5sum) = Self::get_openh264_data()?;

let filepath = std::env::current_exe()?
.parent()
.ok_or("Could not determine Ruffle location.")?
.join(filename);

// If the binary doesn't exist in the expected location, download it.
if !filepath.is_file() {
let url = format!("{}{}{}", URL_BASE, filename, URL_SUFFIX);
let response = reqwest::blocking::get(url)?;
let bytes = response.bytes()?;
let mut bzip2_reader = BzDecoder::new(bytes.as_ref());
crate::decoder::openh264::H264Decoder::get_openh264()
}

let mut file = File::create(filepath.clone())?;
copy(&mut bzip2_reader, &mut file)?;
fn get_owned_stream(&mut self) -> Result<ProxyOrStream, Error> {
#[cfg(feature = "openh264")]
if let Some(openh264) = &self.openh264_lib_filepath {
tracing::info!("Using OpenH264 at {:?}", openh264);
let decoder = Box::new(crate::decoder::openh264::H264Decoder::new(openh264));
let stream = VideoStream::new(decoder);
return Ok(ProxyOrStream::Owned(stream));
}

// Regardless of whether the library was already there, or we just downloaded it, let's check the MD5 hash.
let mut md5 = Md5::new();
copy(&mut File::open(filepath.clone())?, &mut md5)?;
let result: [u8; 16] = md5.finalize().into();

if result[..] != hex::decode(md5sum)?[..] {
return Err(format!("MD5 checksum mismatch for {}", filename).into());
#[cfg(feature = "webcodecs")]
{
let decoder = Box::new(crate::decoder::webcodecs::H264Decoder::new());
let stream = VideoStream::new(decoder);
return Ok(ProxyOrStream::Owned(stream));
}

Ok(filepath)
#[allow(unreachable_code)]
Err(Error::DecoderError("No OpenH264".into()))
}

pub fn new(openh264_lib_filepath: Option<PathBuf>) -> Self {
Expand All @@ -140,21 +80,7 @@ impl VideoBackend for ExternalVideoBackend {
filter: VideoDeblocking,
) -> Result<VideoStreamHandle, Error> {
let proxy_or_stream = if codec == VideoCodec::H264 {
#[cfg(not(target_arch = "wasm32"))]
if let Some(openh264) = &self.openh264_lib_filepath {
tracing::info!("Using OpenH264 at {:?}", openh264);
let decoder = Box::new(crate::decoder::openh264::H264Decoder::new(openh264));
let stream = VideoStream::new(decoder);
ProxyOrStream::Owned(stream)
} else {
return Err(Error::DecoderError("No OpenH264".into()));
}
#[cfg(target_arch = "wasm32")]
{
let decoder = Box::new(crate::decoder::webcodecs::H264Decoder::new());
let stream = VideoStream::new(decoder);
ProxyOrStream::Owned(stream)
}
self.get_owned_stream()?
} else {
ProxyOrStream::Proxied(
self.software
Expand Down
6 changes: 3 additions & 3 deletions video/external/src/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// bindgen ../openh264/codec/api/wels/codec_api.h --no-prepend-enum-name \
// --dynamic-loading OpenH264 -o openh264_sys.rs
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "openh264")]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(dead_code)]
mod openh264_sys;

#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "openh264")]
pub mod openh264;

#[cfg(target_arch = "wasm32")]
#[cfg(feature = "webcodecs")]
pub mod webcodecs;

pub use ruffle_video_software::decoder::VideoDecoder;
86 changes: 84 additions & 2 deletions video/external/src/decoder/openh264.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use core::slice;
use std::ffi::{c_int, c_uchar};
use std::ptr;
use std::{
ffi::{c_int, c_uchar},
fs::File,
io::copy,
path::PathBuf,
ptr,
};

use crate::decoder::openh264_sys::{self, videoFormatI420, ISVCDecoder, OpenH264};
use crate::decoder::VideoDecoder;
Expand All @@ -9,6 +14,9 @@ use ruffle_render::bitmap::BitmapFormat;
use ruffle_video::error::Error;
use ruffle_video::frame::{DecodedFrame, EncodedFrame, FrameDependency};

use bzip2::read::BzDecoder;
use md5::{Digest, Md5};

/// H264 video decoder.
pub struct H264Decoder {
/// How many bytes are used to store the length of the NALU (1, 2, 3, or 4).
Expand All @@ -19,6 +27,80 @@ pub struct H264Decoder {
}

impl H264Decoder {
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
match (std::env::consts::OS, std::env::consts::ARCH) {
("linux", "x86") => Ok((
"libopenh264-2.4.1-linux32.7.so",
"dd0743066117d63e1b2abc56a86506e5",
)),
("linux", "x86_64") => Ok((
"libopenh264-2.4.1-linux64.7.so",
"19c561386a9564f8510fcb7586b9d402",
)),
("linux", "arm") => Ok((
"libopenh264-2.4.1-linux-arm.7.so",
"2274a1bbd13f32b7afe22092e44fa2b5",
)),
("linux", "aarch64") => Ok((
"libopenh264-2.4.1-linux-arm64.7.so",
"2aa205f08077aa2d049032e0b56c5b84",
)),
("macos", "x86_64") => Ok((
"libopenh264-2.4.1-mac-x64.dylib",
"9fefa1e0279a49b8a4e9cf6fc148bc0c",
)),
("macos", "aarch64") => Ok((
"libopenh264-2.4.1-mac-arm64.dylib",
"41f59bb5696ffeadbfba3a8a95ec39b7",
)),
("windows", "x86") => Ok((
"openh264-2.4.1-win32.dll",
"a9360e6dd1e24320c3d65a0c65bf14a4",
)),
("windows", "x86_64") => Ok((
"openh264-2.4.1-win64.dll",
"c85406e6b73812ec3fb9da5f898c6a9e",
)),
(os, arch) => Err(format!("Unsupported OS/ARCH: {} {}", os, arch).into()),
}
}

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";

let (filename, md5sum) = Self::get_openh264_data()?;

let filepath = std::env::current_exe()?
.parent()
.ok_or("Could not determine Ruffle location.")?
.join(filename);

// If the binary doesn't exist in the expected location, download it.
if !filepath.is_file() {
let url = format!("{}{}{}", URL_BASE, filename, URL_SUFFIX);
let response = reqwest::blocking::get(url)?;
let bytes = response.bytes()?;
let mut bzip2_reader = BzDecoder::new(bytes.as_ref());

let mut file = File::create(filepath.clone())?;
copy(&mut bzip2_reader, &mut file)?;
}

// Regardless of whether the library was already there, or we just downloaded it, let's check the MD5 hash.
let mut md5 = Md5::new();
copy(&mut File::open(filepath.clone())?, &mut md5)?;
let result: [u8; 16] = md5.finalize().into();

if result[..] != hex::decode(md5sum)?[..] {
return Err(format!("MD5 checksum mismatch for {}", filename).into());
}

Ok(filepath)
}

/// `extradata` should hold "AVCC (MP4) format" decoder configuration, including PPS and SPS.
/// Make sure it has any start code emulation prevention "three bytes" removed.
pub fn new(openh264_lib_filename: &std::path::Path) -> Self {
Expand Down
20 changes: 11 additions & 9 deletions video/external/src/decoder/webcodecs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ impl H264Decoder {
let lf = last_frame.clone();
// TODO: set up tracing log subscriber into these closures
let output = move |output: &VideoFrame| {
tracing::warn!("webcodecs output frame");
let visible_rect = output.visible_rect().unwrap();
//let options = VideoFrameCopyToOptions::new();

match output.format().unwrap() {
VideoPixelFormat::I420 => {
Expand Down Expand Up @@ -68,11 +66,7 @@ impl H264Decoder {
)));
}
_ => {
assert!(
false,
"unsupported pixel format: {:?}",
output.format().unwrap()
);
panic!("unsupported pixel format: {:?}", output.format().unwrap());
}
};
};
Expand Down Expand Up @@ -100,8 +94,16 @@ impl H264Decoder {
}
}

impl Default for H264Decoder {
fn default() -> Self {
Self::new()
}
}

impl Drop for H264Decoder {
fn drop(&mut self) {}
fn drop(&mut self) {
// TODO: release callback closures
}
}

impl VideoDecoder for H264Decoder {
Expand Down Expand Up @@ -218,7 +220,7 @@ impl VideoDecoder for H264Decoder {
EncodedVideoChunkType::Delta
};
let timestamp = (encoded_frame.frame_id as f64 - 1.0) * 1000000.0 * 0.5;
tracing::warn!("time offset: {}", encoded_frame.time_offset,);
tracing::warn!("timestamp: {}", timestamp);
let data = Uint8Array::from(
&encoded_frame.data
[offset..offset + encoded_len as usize + self.length_size as usize],
Expand Down
2 changes: 1 addition & 1 deletion web/packages/core/tools/build_wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ function copyStandIn(from: string, to: string) {
}
function detectWasmOpt() {
try {
execFileSync("wassm-opt", ["--version"]);
execFileSync("wasm-opt", ["--version"]);
return true;
} catch (_a) {
return false;
Expand Down

0 comments on commit e9c744b

Please sign in to comment.