diff --git a/Cargo.lock b/Cargo.lock index 95b1cb5dd..28a5b6b98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2069,6 +2069,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "h263-rs-deblock" +version = "0.1.0" +source = "git+https://github.com/ruffle-rs/h263-rs?rev=128cdbd85455d19783c88927bb535e8a26fe5220#128cdbd85455d19783c88927bb535e8a26fe5220" +dependencies = [ + "itertools", + "wide", +] + [[package]] name = "h263-rs-yuv" version = "0.1.0" @@ -2363,6 +2372,15 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.8" @@ -4030,6 +4048,7 @@ dependencies = [ "flate2", "generational-arena", "h263-rs", + "h263-rs-deblock", "log", "nihav_codec_support", "nihav_core", diff --git a/video/software/Cargo.toml b/video/software/Cargo.toml index ecf948361..581808ac4 100644 --- a/video/software/Cargo.toml +++ b/video/software/Cargo.toml @@ -17,12 +17,13 @@ flate2 = "1.0.26" log = "0.4" h263-rs = { git = "https://github.com/ruffle-rs/h263-rs", rev = "128cdbd85455d19783c88927bb535e8a26fe5220", optional = true } +h263-rs-deblock = { git = "https://github.com/ruffle-rs/h263-rs", rev = "128cdbd85455d19783c88927bb535e8a26fe5220", optional = true } nihav_core = { git = "https://github.com/ruffle-rs/nihav-vp6", rev = "9416fcc9fc8aab8f4681aa9093b42922214abbd3", optional = true } nihav_codec_support = { git = "https://github.com/ruffle-rs/nihav-vp6", rev = "9416fcc9fc8aab8f4681aa9093b42922214abbd3", optional = true } nihav_duck = { git = "https://github.com/ruffle-rs/nihav-vp6", rev = "9416fcc9fc8aab8f4681aa9093b42922214abbd3", optional = true } [features] default = ["h263", "vp6", "screenvideo"] -h263 = ["h263-rs"] +h263 = ["h263-rs", "h263-rs-deblock"] vp6 = ["nihav_core", "nihav_codec_support", "nihav_duck"] screenvideo = [] diff --git a/video/software/src/backend.rs b/video/software/src/backend.rs index 4d4dc5629..3f59bcdf3 100644 --- a/video/software/src/backend.rs +++ b/video/software/src/backend.rs @@ -35,11 +35,11 @@ impl VideoBackend for SoftwareVideoBackend { _num_frames: u32, size: (u16, u16), codec: VideoCodec, - _filter: VideoDeblocking, + filter: VideoDeblocking, ) -> Result { let decoder: Box = match codec { #[cfg(feature = "h263")] - VideoCodec::H263 => Box::new(crate::decoder::h263::H263Decoder::new()), + VideoCodec::H263 => Box::new(crate::decoder::h263::H263Decoder::new(filter)), #[cfg(feature = "vp6")] VideoCodec::Vp6 => Box::new(crate::decoder::vp6::Vp6Decoder::new(false, size)), #[cfg(feature = "vp6")] diff --git a/video/software/src/decoder/h263.rs b/video/software/src/decoder/h263.rs index 2abd35027..eade4bce9 100644 --- a/video/software/src/decoder/h263.rs +++ b/video/software/src/decoder/h263.rs @@ -1,9 +1,11 @@ use crate::decoder::VideoDecoder; use h263_rs::parser::H263Reader; -use h263_rs::{DecoderOption, H263State, PictureTypeCode}; +use h263_rs::{DecoderOption, H263State, PictureOption, PictureTypeCode}; +use h263_rs_deblock::deblock::{deblock, QUANT_TO_STRENGTH}; use ruffle_render::bitmap::BitmapFormat; use ruffle_video::error::Error; use ruffle_video::frame::{DecodedFrame, EncodedFrame, FrameDependency}; +use swf::VideoDeblocking; #[derive(thiserror::Error, Debug)] pub enum H263Error { @@ -27,11 +29,14 @@ impl From for Error { } /// H263 video decoder. -pub struct H263Decoder(H263State); +pub struct H263Decoder(H263State, VideoDeblocking); impl H263Decoder { - pub fn new() -> Self { - Self(H263State::new(DecoderOption::SORENSON_SPARK_BITSTREAM)) + pub fn new(deblock: VideoDeblocking) -> Self { + Self( + H263State::new(DecoderOption::SORENSON_SPARK_BITSTREAM), + deblock, + ) } } @@ -70,21 +75,49 @@ impl VideoDecoder for H263Decoder { .ok_or(H263Error::MissingWidthHeight)?; let (y, b, r) = picture.as_yuv(); - let mut data = y.to_vec(); - data.extend(b); - data.extend(r); + let hdr = picture.as_header(); - Ok(DecodedFrame::new( - width as u32, - height as u32, - BitmapFormat::Yuv420p, - data, - )) + if self.1 == VideoDeblocking::Level1 + || (self.1 == VideoDeblocking::UseVideoPacketValue + && hdr.options.contains(PictureOption::USE_DEBLOCKER)) + { + let chroma_width = picture.chroma_samples_per_row(); + let quantizer = hdr.quantizer as usize; + let strength = QUANT_TO_STRENGTH[quantizer]; + + let y = deblock(y, width as usize, strength); + let b = deblock(b, chroma_width, strength); + let r = deblock(r, chroma_width, strength); + + let mut data = Vec::with_capacity(y.len() + b.len() + r.len()); + data.extend_from_slice(&y); + data.extend_from_slice(&b); + data.extend_from_slice(&r); + + Ok(DecodedFrame::new( + width as u32, + height as u32, + BitmapFormat::Yuv420p, + data, + )) + } else { + let mut data = Vec::with_capacity(y.len() + b.len() + r.len()); + data.extend_from_slice(y); + data.extend_from_slice(b); + data.extend_from_slice(r); + + Ok(DecodedFrame::new( + width as u32, + height as u32, + BitmapFormat::Yuv420p, + data, + )) + } } } impl Default for H263Decoder { fn default() -> Self { - Self::new() + Self::new(VideoDeblocking::UseVideoPacketValue) } }