Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
torokati44 committed Feb 29, 2024
1 parent 7273581 commit a49f46d
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 123 deletions.
3 changes: 1 addition & 2 deletions Cargo.lock

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

20 changes: 9 additions & 11 deletions video/external/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,14 @@ ruffle_video = { path = ".." }
swf = { path = "../../swf" }
generational-arena = "0.2.9"
thiserror = "1.0"
flate2 = "1.0.28"
log = "0.4"
tracing = "0.1"
ruffle_video_software = { path = "../software" }

libloading = { version = "0.8.1", optional = true }
md-5 = { version = "0.10.6", optional = true }
isahc = { version = "1.7.2", optional = true }
hex = { version = "0.4.3", optional = true }
bzip2-rs = { version = "0.1.2", features = ["rustc_1_37"], optional = true }

[features]
default = ["openh264"]
openh264 = ["libloading", "md-5", "isahc", "hex", "bzip2-rs"]
# Needed for OpenH264:
libloading = "0.8.1"
md-5 = "0.10.6"
isahc = "1.7.2"
hex = "0.4.3"
# TODO: Switch to "rustc_1_63" once a new release is cut.
# See: https://github.com/paolobarbolini/bzip2-rs/issues/14
bzip2-rs = { version = "0.1.2", features = ["rustc_1_51"] }
184 changes: 83 additions & 101 deletions video/external/src/backend.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::io::{Read, Write};
use std::io::Write;
use std::path::PathBuf;

use crate::decoder::VideoDecoder;
use bzip2_rs::DecoderReader;
use generational_arena::Arena;
use isahc::ReadResponseExt;
use md5::{Digest, Md5};
use ruffle_render::backend::RenderBackend;
use ruffle_render::bitmap::{BitmapHandle, BitmapInfo, PixelRegion};
Expand All @@ -11,136 +12,117 @@ use ruffle_video::error::Error;
use ruffle_video::frame::{EncodedFrame, FrameDependency};
use ruffle_video::VideoStreamHandle;
use ruffle_video_software::backend::SoftwareVideoBackend;
use std::fs::File;
use swf::{VideoCodec, VideoDeblocking};

// TODO: Explain that "inner" and "outer" handles should never be
// conflated, despite being the same type.
// Or try adding two typedefs...?
enum ProxyOrStream {
/// These streams are passed through to the wrapped software
/// backend, accessed using the stored ("inner") handle,
/// which is completely internal to this backend.
Proxied(VideoStreamHandle),

/// These streams are handled by this backend directly.
Owned(VideoStream),
}

/// A video backend that falls back to the software backend for most codecs,
/// except for H.264, for which it uses an external decoder.
pub struct ExternalVideoBackend {
streams: Arena<ProxyOrStream>,
openh264_lib_filepath: Option<std::path::PathBuf>,
openh264_lib_filepath: Option<PathBuf>,
software: SoftwareVideoBackend,
}

/// Source: https://www.openh264.org/BINARY_LICENSE.txt
const BINARY_LICENSE: &[u8] = include_bytes!("BINARY_LICENSE.txt");

impl ExternalVideoBackend {
pub fn new() -> Result<Self, Error> {

// TODO: Proper error handling. Internal fallback to disabling H264?

std::fs::File::create("OpenH264-license.txt")
.unwrap()
.write_all(BINARY_LICENSE)
.unwrap();

fn get_openh264() -> Result<PathBuf, Box<dyn std::error::Error>> {
const URL_BASE: &str = "http://ciscobinary.openh264.org/";
const URL_SUFFIX: &str = ".bz2";

let filename;
let md5sum;

// Source: https://github.com/cisco/openh264/releases/tag/v2.4.1
match (std::env::consts::OS, std::env::consts::ARCH) {
("linux", "x86") => {
filename = "libopenh264-2.4.1-linux32.7.so";
md5sum = "dd0743066117d63e1b2abc56a86506e5";
}
("linux", "x86_64") => {
filename = "libopenh264-2.4.1-linux64.7.so";
md5sum = "19c561386a9564f8510fcb7586b9d402";
}
("linux", "arm") => {
filename = "libopenh264-2.4.1-linux-arm.7.so";
md5sum = "2274a1bbd13f32b7afe22092e44fa2b5";
}
("linux", "aarch64") => {
filename = "libopenh264-2.4.1-linux-arm64.7.so";
md5sum = "2aa205f08077aa2d049032e0b56c5b84";
}
("macos", "x86_64") => {
filename = "libopenh264-2.4.1-mac-x64.dylib";
md5sum = "9fefa1e0279a49b8a4e9cf6fc148bc0c";
}
("macos", "aarch64") => {
filename = "libopenh264-2.4.1-mac-arm64.dylib";
md5sum = "41f59bb5696ffeadbfba3a8a95ec39b7";
}
("windows", "x86") => {
filename = "openh264-2.4.1-win32.dll";
md5sum = "a9360e6dd1e24320c3d65a0c65bf14a4";
}
("windows", "x86_64") => {
filename = "openh264-2.4.1-win64.dll";
md5sum = "c85406e6b73812ec3fb9da5f898c6a9e";
}
let (filename, md5sum) = match (std::env::consts::OS, std::env::consts::ARCH) {
("linux", "x86") => (
"libopenh264-2.4.1-linux32.7.so",
"dd0743066117d63e1b2abc56a86506e5",
),
("linux", "x86_64") => (
"libopenh264-2.4.1-linux64.7.so",
"19c561386a9564f8510fcb7586b9d402",
),
("linux", "arm") => (
"libopenh264-2.4.1-linux-arm.7.so",
"2274a1bbd13f32b7afe22092e44fa2b5",
),
("linux", "aarch64") => (
"libopenh264-2.4.1-linux-arm64.7.so",
"2aa205f08077aa2d049032e0b56c5b84",
),
("macos", "x86_64") => (
"libopenh264-2.4.1-mac-x64.dylib",
"9fefa1e0279a49b8a4e9cf6fc148bc0c",
),
("macos", "aarch64") => (
"libopenh264-2.4.1-mac-arm64.dylib",
"41f59bb5696ffeadbfba3a8a95ec39b7",
),
("windows", "x86") => (
"openh264-2.4.1-win32.dll",
"a9360e6dd1e24320c3d65a0c65bf14a4",
),
("windows", "x86_64") => (
"openh264-2.4.1-win64.dll",
"c85406e6b73812ec3fb9da5f898c6a9e",
),
(os, arch) => {
panic!("Unsupported OS/ARCH: {} {}", os, arch);
return Err(format!("Unsupported OS/ARCH: {} {}", os, arch).into());
}
}
};

let filepath = std::env::current_dir().unwrap().join(filename);
let filepath = std::env::current_dir()?.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 mut resp = isahc::get(&url).unwrap();

let body = resp.bytes().unwrap();
File::create("OpenH264-license.txt")?.write_all(BINARY_LICENSE)?;

let mut decoder = bzip2_rs::decoder::Decoder::new();
let url = format!("{}{}{}", URL_BASE, filename, URL_SUFFIX);
let mut response = isahc::get(&url)?;
let mut bzip2_reader = DecoderReader::new(response.body_mut());

let mut output = vec![];
let mut file = File::create(filepath.clone())?;
std::io::copy(&mut bzip2_reader, &mut file)?;
}

let mut buf = [0; 1024];
loop {
match decoder.read(&mut buf).unwrap() {
bzip2_rs::decoder::ReadState::NeedsWrite(_space) => {
decoder.write(&body).unwrap();
}
bzip2_rs::decoder::ReadState::Read(n) => {
// `n` uncompressed bytes have been read into `buf`
output.extend_from_slice(&buf[..n]);
}
bzip2_rs::decoder::ReadState::Eof => {
// we reached the end of the file
break;
}
}
}
// Regardless of whether the library was already there, or we just downloaded it, let's check the MD5 hash.
let mut md5 = Md5::new();
std::io::copy(&mut File::open(filepath.clone())?, &mut md5)?;
let result: [u8; 16] = md5.finalize().into();

std::fs::write(filepath.clone(), &output).unwrap();
if result[..] != hex::decode(md5sum)?[..] {
return Err(format!("MD5 checksum mismatch for {}", filename).into());
}

let mut buf = vec![];
std::fs::File::open(filepath.clone())
.unwrap()
.read_to_end(&mut buf)
.unwrap();
let mut hasher = Md5::new();
hasher.update(buf);

// acquire hash digest in the form of GenericArray,
// which in this case is equivalent to [u8; 16]
let result = hasher.finalize();
assert_eq!(result[..], hex::decode(md5sum).unwrap()[..]);
Ok(filepath)
}

pub fn new() -> Result<Self, Error> {
Ok(Self {
streams: Arena::new(),
openh264_lib_filepath: Some(filepath),
openh264_lib_filepath: match Self::get_openh264() {
Ok(path) => Some(path),
Err(e) => {
tracing::error!("Couldn't get OpenH264: {}", e);
None
}
},
software: SoftwareVideoBackend::new(),
})
}
}

// NOTE: The stream handles coming in through this API must not be
// conflated with the ones stored in `streams` as `Proxied`.
impl VideoBackend for ExternalVideoBackend {
#[allow(unreachable_code, unused_variables)]
fn register_video_stream(
Expand All @@ -150,24 +132,24 @@ impl VideoBackend for ExternalVideoBackend {
codec: VideoCodec,
filter: VideoDeblocking,
) -> Result<VideoStreamHandle, Error> {
println!("Registering video stream");

let proxy_or_stream = if codec == VideoCodec::H264 {
let decoder = Box::new(crate::decoder::openh264::H264Decoder::new(
self.openh264_lib_filepath.clone().unwrap().clone().as_ref(),
));
let stream = VideoStream::new(decoder);
ProxyOrStream::Owned(stream)
let openh264 = &self.openh264_lib_filepath;
if let Some(openh264) = openh264 {
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()));
}
} else {
ProxyOrStream::Proxied(
self.software
.register_video_stream(num_frames, size, codec, filter)?,
)
};

let stream_handle = self.streams.insert(proxy_or_stream);

Ok(stream_handle)
Ok(self.streams.insert(proxy_or_stream))
}

fn configure_video_stream_decoder(
Expand Down
3 changes: 0 additions & 3 deletions video/external/src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ use ruffle_video::frame::{DecodedFrame, EncodedFrame, FrameDependency};

// bindgen ../openh264/codec/api/wels/codec_api.h --no-prepend-enum-name \
// --dynamic-loading OpenH264 -o openh264_sys.rs

#[cfg(feature = "openh264")]
#[allow(non_upper_case_globals)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(dead_code)]
mod openh264_sys;

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

/// Trait for video decoders.
Expand Down
11 changes: 5 additions & 6 deletions video/external/src/decoder/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
To update to a new OpenH264 release:

- Open the new release on https://github.com/cisco/openh264/releases
- Update the file names
- Update MD5 hashes
- Add/remove supported archs added/dropped
- Update the binary file names and MD5 hashes
- Add/remove supported architectures and platforms if added/dropped
- Update the base URL and license if changed
- Download the header
- Regenerate the bindings
- Download the OpenH264 sources (at least `codec_api.h`)
- Regenerate the bindings using the command in `decoder.rs`
- Follow the API changes if necessary
- Update the version sanity check
- Update the version number sanity check

0 comments on commit a49f46d

Please sign in to comment.