diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..a3f804e53 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# re_rav1d changelog +Tracks differences since [rav1d 1.0.0](https://crates.io/crates/rav1d/1.0.0) + +## re_rav1d 0.1.3 +* Remove *.c files from the release again & move build.rs parts that are only relevant for the cli to the cli project [#4](https://github.com/rerun-io/re_rav1d/pull/4) +* Fix assembly on Windows [#5](https://github.com/rerun-io/re_rav1d/pull/5) + +## re_rav1d 0.1.2 +* Linux/x64: re-enable assembly routines and prevent illegal relocations [#3](https://github.com/rerun-io/re_rav1d/pull/3) + +## re_rav1d 0.1.1 +* Include `tools/compat/getopt.c` in the release + +## re_rav1d 0.1.0 +* Add `dav1d-rs` as a Rust API ([upstream PR](https://github.com/memorysafety/rav1d/pull/1364)) +* Fix crash on erroneous videos ([upstream PR](https://github.com/memorysafety/rav1d/pull/1362)) +* Disable `asm` feature on Linux diff --git a/Cargo.lock b/Cargo.lock index 396bbecb2..07ae1d3ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,18 +34,44 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "av-data" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "124ae24335161b3d2226594640a67903da0866e2591312591fc8ddad64c1b38c" +dependencies = [ + "byte-slice-cast", + "bytes", + "num-derive", + "num-rational", + "num-traits", + "thiserror", +] + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + [[package]] name = "cc" version = "1.1.5" @@ -98,6 +124,56 @@ dependencies = [ "jobserver", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -145,32 +221,13 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rav1d" -version = "1.0.0" -dependencies = [ - "assert_matches", - "atomig", - "bitflags", - "cc", - "cfg-if", - "libc", - "nasm-rs", - "parking_lot", - "paste", - "raw-cpuid", - "strum", - "to_method", - "zerocopy", -] - [[package]] name = "rav1d-cli" version = "1.0.0" dependencies = [ "cfg-if", "libc", - "rav1d", + "re_rav1d", "windows-sys", ] @@ -183,6 +240,27 @@ dependencies = [ "bitflags", ] +[[package]] +name = "re_rav1d" +version = "0.1.3" +dependencies = [ + "assert_matches", + "atomig", + "av-data", + "bitflags", + "cc", + "cfg-if", + "libc", + "nasm-rs", + "parking_lot", + "paste", + "raw-cpuid", + "static_assertions", + "strum", + "to_method", + "zerocopy", +] + [[package]] name = "redox_syscall" version = "0.5.3" @@ -210,6 +288,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strum" version = "0.26.3" @@ -254,6 +338,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "to_method" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index dc4f051b4..c145433f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,15 +3,15 @@ members = [".", "tools"] default-members = [".", "tools"] [package] -name = "rav1d" +name = "re_rav1d" authors = ["Rav1d Developers", "Prossimo"] -version = "1.0.0" +version = "0.1.3" edition = "2021" rust-version = "1.79" description = "Rust port of the dav1d AV1 decoder" license = "BSD-2-Clause" repository = "https://github.com/memorysafety/rav1d" -exclude = ["*.c", "*.h", "*.in", "meson*", "tests/", "doc/", "package/"] +exclude = ["*.c", "*.in", "meson*", "tests/", "doc/", "package/"] [lib] path = "lib.rs" @@ -20,12 +20,14 @@ crate-type = ["staticlib", "rlib"] [dependencies] assert_matches = "1.5.0" atomig = { version = "0.4.0", features = ["derive"] } +av-data = "0.4.2" bitflags = "2.4.0" cfg-if = "1.0.0" libc = "0.2" parking_lot = "0.12.2" paste = "1.0.14" raw-cpuid = "11.0.1" +static_assertions = "1" strum = { version = "0.26", features = ["derive"] } to_method = "1.1.0" zerocopy = { version = "0.7.32", features = ["derive"] } @@ -35,7 +37,13 @@ cc = "1.0.79" nasm-rs = { version = "0.3", features = ["parallel"] } [features] -default = ["asm", "asm_arm64_dotprod", "asm_arm64_i8mm", "bitdepth_8", "bitdepth_16"] +default = [ + "asm", + "asm_arm64_dotprod", + "asm_arm64_i8mm", + "bitdepth_8", + "bitdepth_16", +] asm = [] asm_arm64_dotprod = ["asm"] asm_arm64_i8mm = ["asm"] diff --git a/RELEASES.md b/RELEASES.md new file mode 100644 index 000000000..e4d252542 --- /dev/null +++ b/RELEASES.md @@ -0,0 +1,11 @@ +# `re_rav1d` Release Checklist + +* [ ] Update `CHANGELOG.md` +* [ ] Bump version numbers +* [ ] `git commit -m 'Release 0.x.0 - summary'` +* [ ] `cargo publish --quiet -p re_rav1d` +* [ ] `git tag -a 0.x.0 -m 'Release 0.x.0 - summary'` +* [ ] `git pull --tags && git tag -d latest ; git tag -a latest -m 'Latest release' && git push --tags origin latest --force && git push origin main ; git push --tags ; git push` +* [ ] Do a GitHub release: https://github.com/rerun-io/re_rav1d/releases/new +* [ ] Wait for documentation to build: https://docs.rs/releases/queue +* [ ] Post on Twitter diff --git a/build.rs b/build.rs index 99e84cef2..a2487d440 100644 --- a/build.rs +++ b/build.rs @@ -331,41 +331,4 @@ fn main() { { asm::main(); } - - // NOTE: we rely on libraries that are only distributed for Windows so - // targeting Windows/MSVC is not supported when cross compiling. - #[cfg(all(target_os = "windows", target_env = "msvc"))] - { - use cc::windows_registry; - use std::env; - - let os = env::var("CARGO_CFG_TARGET_OS").expect("missing CARGO_CFG_TARGET_OS"); - let target = env::var("TARGET").expect("missing TARGET"); - if os == "windows" { - // for sprintf, snprintf, etc. - println!("cargo:rustc-link-lib=static=oldnames"); - let tool = windows_registry::find_tool(&target, "cl.exe") - .expect("couldn't find cl.exe; are the Visual Studio C++ tools installed?"); - let lib_paths = &tool - .env() - .iter() - .find(|(key, _val)| key == "LIB") - .expect("LIB path not found") - .1; - for path in lib_paths.to_str().unwrap().split(';') { - if path != "" { - println!("cargo:rustc-link-search={path}"); - } - } - - let getopt = "getopt"; - cc::Build::new() - .files([&"tools/compat/getopt.c"]) - .include("include/compat") - .debug(cfg!(debug_assertions)) - .compile(&getopt); - // cc automatically outputs the following line - // println!("cargo:rustc-link-lib=static={getopt}"); - } - } } diff --git a/include/dav1d/headers.rs b/include/dav1d/headers.rs index 0bb34a7d5..74a8481ed 100644 --- a/include/dav1d/headers.rs +++ b/include/dav1d/headers.rs @@ -671,7 +671,7 @@ pub const DAV1D_MC_SMPTE240: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients:: pub const DAV1D_MC_SMPTE_YCGCO: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients::SMPTE_YCGCO.to_dav1d(); pub const DAV1D_MC_BT2020_NCL: Dav1dMatrixCoefficients = - Rav1dMatrixCoefficients::BT2020_CL.to_dav1d(); + Rav1dMatrixCoefficients::BT2020_NCL.to_dav1d(); pub const DAV1D_MC_BT2020_CL: Dav1dMatrixCoefficients = Rav1dMatrixCoefficients::BT2020_CL.to_dav1d(); pub const DAV1D_MC_SMPTE2085: Dav1dMatrixCoefficients = diff --git a/lib.rs b/lib.rs index 3bc3ec59c..7be11047a 100644 --- a/lib.rs +++ b/lib.rs @@ -93,3 +93,846 @@ pub mod src { } // mod src pub use src::error::Dav1dResult; + +// --------------------------------------------------------------------------------------- + +/// Public Rust API. +/// +/// This is more or less the same API as , +/// and is indeed a fork of that work. +pub mod dav1d { + // This whole module was originally copied from https://github.com/rust-av/dav1d-rs/ + // (specifically https://github.com/rust-av/dav1d-rs/blob/94b1deaa1e25bf29c77bb5cc8a08ddaf7663eede/src/lib.rs) + // with some modifications. + // `dav1d-rs` is under the MIT license, replicated here: + + // MIT License + // + // Copyright (c) 2018 Luca Barbato + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in all + // copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + // SOFTWARE. + + // The code below provides a safe API around the rav1d C FFI layer. + + use crate as rav1d; + + pub use av_data::pixel; + use std::ffi::c_void; + use std::fmt; + use std::mem; + use std::ptr::NonNull; + use std::sync::Arc; + + use rav1d::include::dav1d::data::*; + use rav1d::include::dav1d::dav1d::*; + use rav1d::include::dav1d::headers::*; + use rav1d::include::dav1d::picture::*; + use rav1d::src::error::{Rav1dError, Rav1dResult}; + use rav1d::src::lib::*; + use rav1d::src::send_sync_non_null::SendSyncNonNull; + use rav1d::Dav1dResult; + + fn option_nonnull(ptr: *mut T) -> Option> { + if ptr.is_null() { + None + } else { + Some(NonNull::new(ptr).unwrap()) + } + } + + fn option_send_sync_non_null(r#box: Box) -> Option> { + Some(SendSyncNonNull::from_box(r#box)) + } + + fn rav1d_result(ret: Dav1dResult) -> Rav1dResult { + Rav1dResult::try_from(ret).unwrap() + } + + /// Error enum return by various `dav1d` operations. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[non_exhaustive] + pub enum Error { + /// Try again. + /// + /// If this is returned by [`Decoder::send_data`] or [`Decoder::send_pending_data`] then there + /// are decoded frames pending that first have to be retrieved via [`Decoder::get_picture`] + /// before processing any further pending data. + /// + /// If this is returned by [`Decoder::get_picture`] then no decoded frames are pending + /// currently and more data needs to be sent to the decoder. + Again, + /// Invalid argument. + /// + /// One of the arguments passed to the function was invalid. + InvalidArgument, + /// Not enough memory. + /// + /// Not enough memory is currently available for performing this operation. + NotEnoughMemory, + /// Unsupported bitstream. + /// + /// The provided bitstream is not supported by `dav1d`. + UnsupportedBitstream, + /// Unknown error. + UnknownError(Rav1dError), + } + + impl From for Error { + fn from(err: Rav1dError) -> Self { + match err { + Rav1dError::EAGAIN => Error::Again, + Rav1dError::ENOMEM => Error::NotEnoughMemory, + Rav1dError::EINVAL => Error::InvalidArgument, + Rav1dError::ENOPROTOOPT => Error::UnsupportedBitstream, + _ => Error::UnknownError(err), + } + } + } + + impl Error { + pub const fn is_again(&self) -> bool { + matches!(self, Error::Again) + } + } + + impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + Error::Again => write!(fmt, "Try again"), + Error::InvalidArgument => write!(fmt, "Invalid argument"), + Error::NotEnoughMemory => write!(fmt, "Not enough memory available"), + Error::UnsupportedBitstream => write!(fmt, "Unsupported bitstream"), + Error::UnknownError(err) => write!(fmt, "Unknown error {err:?}"), + } + } + } + + impl std::error::Error for Error {} + + /// Settings for creating a new [`Decoder`] instance. + /// See documentation for native `Dav1dSettings` struct. + pub struct Settings { + dav1d_settings: Dav1dSettings, + } + + unsafe impl Send for Settings {} + unsafe impl Sync for Settings {} + + impl Default for Settings { + fn default() -> Self { + Self::new() + } + } + + impl Settings { + /// Creates a new [`Settings`] instance with default settings. + pub fn new() -> Self { + unsafe { + let mut dav1d_settings = mem::MaybeUninit::uninit(); + + dav1d_default_settings(NonNull::new(dav1d_settings.as_mut_ptr()).unwrap()); + + Self { + dav1d_settings: dav1d_settings.assume_init(), + } + } + } + + pub fn set_n_threads(&mut self, n_threads: u32) { + self.dav1d_settings.n_threads = n_threads as i32; + } + + pub fn get_n_threads(&self) -> u32 { + self.dav1d_settings.n_threads as u32 + } + + pub fn set_max_frame_delay(&mut self, max_frame_delay: u32) { + self.dav1d_settings.max_frame_delay = max_frame_delay as i32; + } + + pub fn get_max_frame_delay(&self) -> u32 { + self.dav1d_settings.max_frame_delay as u32 + } + + pub fn set_apply_grain(&mut self, apply_grain: bool) { + self.dav1d_settings.apply_grain = i32::from(apply_grain); + } + + pub fn get_apply_grain(&self) -> bool { + self.dav1d_settings.apply_grain != 0 + } + + pub fn set_operating_point(&mut self, operating_point: u32) { + self.dav1d_settings.operating_point = operating_point as i32; + } + + pub fn get_operating_point(&self) -> u32 { + self.dav1d_settings.operating_point as u32 + } + + pub fn set_all_layers(&mut self, all_layers: bool) { + self.dav1d_settings.all_layers = i32::from(all_layers); + } + + pub fn get_all_layers(&self) -> bool { + self.dav1d_settings.all_layers != 0 + } + + pub fn set_frame_size_limit(&mut self, frame_size_limit: u32) { + self.dav1d_settings.frame_size_limit = frame_size_limit; + } + + pub fn get_frame_size_limit(&self) -> u32 { + self.dav1d_settings.frame_size_limit + } + + pub fn set_strict_std_compliance(&mut self, strict_std_compliance: bool) { + self.dav1d_settings.strict_std_compliance = i32::from(strict_std_compliance); + } + + pub fn get_strict_std_compliance(&self) -> bool { + self.dav1d_settings.strict_std_compliance != 0 + } + + pub fn set_output_invisible_frames(&mut self, output_invisible_frames: bool) { + self.dav1d_settings.output_invisible_frames = i32::from(output_invisible_frames); + } + + pub fn get_output_invisible_frames(&self) -> bool { + self.dav1d_settings.output_invisible_frames != 0 + } + + pub fn set_inloop_filters(&mut self, inloop_filters: InloopFilterType) { + self.dav1d_settings.inloop_filters = inloop_filters.bits(); + } + + pub fn get_inloop_filters(&self) -> InloopFilterType { + InloopFilterType::from_bits_truncate(self.dav1d_settings.inloop_filters) + } + + pub fn set_decode_frame_type(&mut self, decode_frame_type: DecodeFrameType) { + self.dav1d_settings.decode_frame_type = decode_frame_type.into(); + } + + pub fn get_decode_frame_type(&self) -> DecodeFrameType { + DecodeFrameType::try_from(self.dav1d_settings.decode_frame_type) + .expect("Invalid Dav1dDecodeFrameType") + } + } + + bitflags::bitflags! { + #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] + pub struct InloopFilterType: u32 { + const DEBLOCK = DAV1D_INLOOPFILTER_DEBLOCK; + const CDEF = DAV1D_INLOOPFILTER_CDEF; + const RESTORATION = DAV1D_INLOOPFILTER_RESTORATION; + } + } + + #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] + pub enum DecodeFrameType { + #[default] + All, + Reference, + Intra, + Key, + } + + impl TryFrom for DecodeFrameType { + type Error = TryFromEnumError; + + fn try_from(value: u32) -> Result { + match value { + DAV1D_DECODEFRAMETYPE_ALL => Ok(DecodeFrameType::All), + DAV1D_DECODEFRAMETYPE_REFERENCE => Ok(DecodeFrameType::Reference), + DAV1D_DECODEFRAMETYPE_INTRA => Ok(DecodeFrameType::Intra), + DAV1D_DECODEFRAMETYPE_KEY => Ok(DecodeFrameType::Key), + _ => Err(TryFromEnumError(())), + } + } + } + + impl From for u32 { + fn from(v: DecodeFrameType) -> u32 { + match v { + DecodeFrameType::All => DAV1D_DECODEFRAMETYPE_ALL, + DecodeFrameType::Reference => DAV1D_DECODEFRAMETYPE_REFERENCE, + DecodeFrameType::Intra => DAV1D_DECODEFRAMETYPE_INTRA, + DecodeFrameType::Key => DAV1D_DECODEFRAMETYPE_KEY, + } + } + } + + /// The error type returned when a conversion from a C enum fails. + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub struct TryFromEnumError(()); + + impl std::fmt::Display for TryFromEnumError { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fmt.write_str("Invalid enum value") + } + } + + impl From for TryFromEnumError { + fn from(x: std::convert::Infallible) -> TryFromEnumError { + match x {} + } + } + + impl std::error::Error for TryFromEnumError {} + + /// A `dav1d` decoder instance. + pub struct Decoder { + dec: Dav1dContext, + pending_data: Option, + } + + unsafe extern "C" fn release_wrapped_data>( + _data: *const u8, + cookie: Option>, + ) { + let cookie = cookie.unwrap().as_ptr().as_ptr(); + let buf = unsafe { Box::from_raw(cookie as *mut T) }; + drop(buf); + } + + impl Decoder { + /// Creates a new [`Decoder`] instance with given [`Settings`]. + pub fn with_settings(settings: &Settings) -> Result { + unsafe { + let mut dec = mem::MaybeUninit::uninit(); + + let ret = dav1d_open( + Some(NonNull::new(dec.as_mut_ptr()).unwrap()), + Some(NonNull::new(&settings.dav1d_settings as *const _ as *mut _).unwrap()), + ); + + match rav1d_result(ret) { + Ok(_) => Ok(Decoder { + dec: dec.assume_init().unwrap(), + pending_data: None, + }), + Err(err) => Err(Error::from(err)), + } + } + } + + /// Creates a new [`Decoder`] instance with the default settings. + pub fn new() -> Result { + Self::with_settings(&Settings::default()) + } + + /// Flush the decoder. + /// + /// This flushes all delayed frames in the decoder and clears the internal decoder state. + /// + /// All currently pending frames are available afterwards via [`Decoder::get_picture`]. + pub fn flush(&mut self) { + unsafe { + dav1d_flush(self.dec); + if let Some(mut pending_data) = self.pending_data.take() { + dav1d_data_unref(Some(NonNull::new(&mut pending_data).unwrap())); + } + } + } + + /// Send new AV1 data to the decoder. + /// + /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames + /// available via [`Decoder::get_picture`]. + /// + /// # Panics + /// + /// If a previous call returned [`Error::Again`] then this must not be called again until + /// [`Decoder::send_pending_data`] has returned `Ok(())`. + pub fn send_data + Send + Sync + 'static>( + &mut self, + buf: T, + offset: Option, + timestamp: Option, + duration: Option, + ) -> Result<(), Error> { + assert!( + self.pending_data.is_none(), + "Have pending data that needs to be handled first" + ); + + let buf = Box::new(buf); + let slice = (*buf).as_ref(); + let len = slice.len(); + + unsafe { + let mut data: Dav1dData = mem::zeroed(); + let _ret = dav1d_data_wrap( + option_nonnull(&mut data), + option_nonnull(slice.as_ptr() as *mut _), + len, + Some(release_wrapped_data::), + option_send_sync_non_null(buf).map(|v| v.cast()), + ); + if let Some(offset) = offset { + data.m.offset = offset as libc::off_t; + } + if let Some(timestamp) = timestamp { + data.m.timestamp = timestamp; + } + if let Some(duration) = duration { + data.m.duration = duration; + } + + let ret = dav1d_send_data(Some(self.dec), option_nonnull(&mut data)); + if let Err(err) = rav1d_result(ret) { + let ret = Error::from(err); + + if ret.is_again() { + self.pending_data = Some(data); + } else { + dav1d_data_unref(option_nonnull(&mut data)); + } + + return Err(ret); + } + + if data.sz > 0 { + self.pending_data = Some(data); + return Err(Error::Again); + } + + Ok(()) + } + } + + /// Sends any pending data to the decoder. + /// + /// This has to be called after [`Decoder::send_data`] has returned `Err([Error::Again])` to + /// consume any futher pending data. + /// + /// After this returned `Ok(())` or `Err([Error::Again])` there might be decoded frames + /// available via [`Decoder::get_picture`]. + pub fn send_pending_data(&mut self) -> Result<(), Error> { + let mut data = match self.pending_data.take() { + None => { + return Ok(()); + } + Some(data) => data, + }; + + unsafe { + let ret = dav1d_send_data(Some(self.dec), option_nonnull(&mut data)); + if let Err(err) = rav1d_result(ret) { + let ret = Error::from(err); + + if ret.is_again() { + self.pending_data = Some(data); + } else { + dav1d_data_unref(option_nonnull(&mut data)); + } + + return Err(ret); + } + + if data.sz > 0 { + self.pending_data = Some(data); + return Err(Error::Again); + } + + Ok(()) + } + } + + /// Get the next decoded frame from the decoder. + /// + /// If this returns `Err([Error::Again])` then further data has to be sent to the decoder + /// before further decoded frames become available. + /// + /// To make most use of frame threading this function should only be called once per submitted + /// input frame and not until it returns `Err([Error::Again])`. Calling it in a loop should + /// only be done to drain all pending frames at the end. + pub fn get_picture(&mut self) -> Result { + unsafe { + let mut pic: Dav1dPicture = mem::zeroed(); + let ret = dav1d_get_picture(Some(self.dec), option_nonnull(&mut pic)); + + if let Err(err) = rav1d_result(ret) { + Err(Error::from(err)) + } else { + let inner = InnerPicture { pic }; + Ok(Picture { + inner: Arc::new(inner), + }) + } + } + } + + /// Get the decoder delay. + pub fn get_frame_delay(&self) -> u32 { + unsafe { + dav1d_get_frame_delay(option_nonnull(&self.dec as *const _ as *mut _)).0 as u32 + } + } + } + + impl Drop for Decoder { + fn drop(&mut self) { + unsafe { + if let Some(mut pending_data) = self.pending_data.take() { + dav1d_data_unref(option_nonnull(&mut pending_data)); + } + let mut dec = Some(self.dec); + dav1d_close(option_nonnull(&mut dec)); + }; + } + } + + unsafe impl Send for Decoder {} + unsafe impl Sync for Decoder {} + + struct InnerPicture { + pub pic: Dav1dPicture, + } + + /// A decoded frame. + #[derive(Clone)] + pub struct Picture { + inner: Arc, + } + + /// Pixel layout of a frame. + #[derive(Debug, Eq, PartialEq, Copy, Clone)] + pub enum PixelLayout { + /// Monochrome. + I400, + /// 4:2:0 planar. + I420, + /// 4:2:2 planar. + I422, + /// 4:4:4 planar. + I444, + } + + /// Frame component. + #[derive(Eq, PartialEq, Copy, Clone, Debug)] + pub enum PlanarImageComponent { + /// Y component. + Y, + /// U component. + U, + /// V component. + V, + } + + impl From for PlanarImageComponent { + fn from(index: usize) -> Self { + match index { + 0 => PlanarImageComponent::Y, + 1 => PlanarImageComponent::U, + 2 => PlanarImageComponent::V, + _ => panic!("Invalid YUV index: {}", index), + } + } + } + + impl From for usize { + fn from(component: PlanarImageComponent) -> Self { + match component { + PlanarImageComponent::Y => 0, + PlanarImageComponent::U => 1, + PlanarImageComponent::V => 2, + } + } + } + + /// A single plane of a decoded frame. + /// + /// This can be used like a `&[u8]`. + #[derive(Clone)] + pub struct Plane(Picture, PlanarImageComponent); + + impl AsRef<[u8]> for Plane { + fn as_ref(&self) -> &[u8] { + let (stride, height) = self.0.plane_data_geometry(self.1); + unsafe { + std::slice::from_raw_parts( + self.0.plane_data_ptr(self.1) as *const u8, + (stride * height) as usize, + ) + } + } + } + + impl std::ops::Deref for Plane { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } + } + + static_assertions::assert_impl_all!(Plane: Send, Sync); + + /// Number of bits per component. + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub struct BitsPerComponent(pub usize); + + impl Picture { + /// Stride in pixels of the `component` for the decoded frame. + pub fn stride(&self, component: PlanarImageComponent) -> u32 { + let s = match component { + PlanarImageComponent::Y => 0, + _ => 1, + }; + self.inner.pic.stride[s] as u32 + } + + /// Raw pointer to the data of the `component` for the decoded frame. + pub fn plane_data_ptr(&self, component: PlanarImageComponent) -> *mut c_void { + let index: usize = component.into(); + self.inner.pic.data[index].unwrap().as_ptr() + } + + /// Plane geometry of the `component` for the decoded frame. + /// + /// This returns the stride and height. + pub fn plane_data_geometry(&self, component: PlanarImageComponent) -> (u32, u32) { + let height = match component { + PlanarImageComponent::Y => self.height(), + _ => match self.pixel_layout() { + PixelLayout::I420 => (self.height() + 1) / 2, + PixelLayout::I400 | PixelLayout::I422 | PixelLayout::I444 => self.height(), + }, + }; + (self.stride(component), height) + } + + /// Plane data of the `component` for the decoded frame. + pub fn plane(&self, component: PlanarImageComponent) -> Plane { + Plane(self.clone(), component) + } + + /// Bit depth of the plane data. + /// + /// This returns 8 or 16 for the underlying integer type used for the plane data. + /// + /// Check [`Picture::bits_per_component`] for the number of bits that are used. + pub fn bit_depth(&self) -> usize { + self.inner.pic.p.bpc as usize + } + + /// Bits used per component of the plane data. + /// + /// Check [`Picture::bit_depth`] for the number of storage bits. + pub fn bits_per_component(&self) -> Option { + unsafe { + match (*self.inner.pic.seq_hdr.unwrap().as_ptr()).hbd { + 0 => Some(BitsPerComponent(8)), + 1 => Some(BitsPerComponent(10)), + 2 => Some(BitsPerComponent(12)), + _ => None, + } + } + } + + /// Width of the frame. + pub fn width(&self) -> u32 { + self.inner.pic.p.w as u32 + } + + /// Height of the frame. + pub fn height(&self) -> u32 { + self.inner.pic.p.h as u32 + } + + /// Pixel layout of the frame. + pub fn pixel_layout(&self) -> PixelLayout { + #[allow(non_upper_case_globals)] + match self.inner.pic.p.layout { + DAV1D_PIXEL_LAYOUT_I400 => PixelLayout::I400, + DAV1D_PIXEL_LAYOUT_I420 => PixelLayout::I420, + DAV1D_PIXEL_LAYOUT_I422 => PixelLayout::I422, + DAV1D_PIXEL_LAYOUT_I444 => PixelLayout::I444, + _ => unreachable!(), + } + } + + /// Timestamp of the frame. + /// + /// This is the same timestamp as the one provided to [`Decoder::send_data`]. + pub fn timestamp(&self) -> Option { + let ts = self.inner.pic.m.timestamp; + if ts == i64::MIN { + None + } else { + Some(ts) + } + } + + /// Duration of the frame. + /// + /// This is the same duration as the one provided to [`Decoder::send_data`] or `0` if none was + /// provided. + pub fn duration(&self) -> i64 { + self.inner.pic.m.duration + } + + /// Offset of the frame. + /// + /// This is the same offset as the one provided to [`Decoder::send_data`] or `-1` if none was + /// provided. + pub fn offset(&self) -> i64 { + self.inner.pic.m.offset as i64 + } + + /// Chromaticity coordinates of the source colour primaries. + pub fn color_primaries(&self) -> pixel::ColorPrimaries { + unsafe { + #[allow(non_upper_case_globals)] + match (*self.inner.pic.seq_hdr.unwrap().as_ptr()).pri { + DAV1D_COLOR_PRI_BT709 => pixel::ColorPrimaries::BT709, + DAV1D_COLOR_PRI_UNKNOWN => pixel::ColorPrimaries::Unspecified, + DAV1D_COLOR_PRI_BT470M => pixel::ColorPrimaries::BT470M, + DAV1D_COLOR_PRI_BT470BG => pixel::ColorPrimaries::BT470BG, + DAV1D_COLOR_PRI_BT601 => pixel::ColorPrimaries::BT470BG, + DAV1D_COLOR_PRI_SMPTE240 => pixel::ColorPrimaries::ST240M, + DAV1D_COLOR_PRI_FILM => pixel::ColorPrimaries::Film, + DAV1D_COLOR_PRI_BT2020 => pixel::ColorPrimaries::BT2020, + DAV1D_COLOR_PRI_XYZ => pixel::ColorPrimaries::ST428, + DAV1D_COLOR_PRI_SMPTE431 => pixel::ColorPrimaries::P3DCI, + DAV1D_COLOR_PRI_SMPTE432 => pixel::ColorPrimaries::P3Display, + DAV1D_COLOR_PRI_EBU3213 => pixel::ColorPrimaries::Tech3213, + 23..=DAV1D_COLOR_PRI_RESERVED => pixel::ColorPrimaries::Unspecified, + _ => unreachable!(), + } + } + } + + /// Transfer characteristics function. + pub fn transfer_characteristic(&self) -> pixel::TransferCharacteristic { + unsafe { + #[allow(non_upper_case_globals)] + match (*self.inner.pic.seq_hdr.unwrap().as_ptr()).trc { + DAV1D_TRC_BT709 => pixel::TransferCharacteristic::BT1886, + DAV1D_TRC_UNKNOWN => pixel::TransferCharacteristic::Unspecified, + DAV1D_TRC_BT470M => pixel::TransferCharacteristic::BT470M, + DAV1D_TRC_BT470BG => pixel::TransferCharacteristic::BT470BG, + DAV1D_TRC_BT601 => pixel::TransferCharacteristic::ST170M, + DAV1D_TRC_SMPTE240 => pixel::TransferCharacteristic::ST240M, + DAV1D_TRC_LINEAR => pixel::TransferCharacteristic::Linear, + DAV1D_TRC_LOG100 => pixel::TransferCharacteristic::Logarithmic100, + DAV1D_TRC_LOG100_SQRT10 => pixel::TransferCharacteristic::Logarithmic316, + DAV1D_TRC_IEC61966 => pixel::TransferCharacteristic::SRGB, + DAV1D_TRC_BT1361 => pixel::TransferCharacteristic::BT1886, + DAV1D_TRC_SRGB => pixel::TransferCharacteristic::SRGB, + DAV1D_TRC_BT2020_10BIT => pixel::TransferCharacteristic::BT2020Ten, + DAV1D_TRC_BT2020_12BIT => pixel::TransferCharacteristic::BT2020Twelve, + DAV1D_TRC_SMPTE2084 => pixel::TransferCharacteristic::PerceptualQuantizer, + DAV1D_TRC_SMPTE428 => pixel::TransferCharacteristic::ST428, + DAV1D_TRC_HLG => pixel::TransferCharacteristic::HybridLogGamma, + 19..=DAV1D_TRC_RESERVED => pixel::TransferCharacteristic::Unspecified, + _ => unreachable!(), + } + } + } + + /// Matrix coefficients used in deriving luma and chroma signals from the + /// green, blue and red or X, Y and Z primaries. + pub fn matrix_coefficients(&self) -> pixel::MatrixCoefficients { + unsafe { + #[allow(non_upper_case_globals)] + match (*self.inner.pic.seq_hdr.unwrap().as_ptr()).mtrx { + DAV1D_MC_IDENTITY => pixel::MatrixCoefficients::Identity, + DAV1D_MC_BT709 => pixel::MatrixCoefficients::BT709, + DAV1D_MC_UNKNOWN => pixel::MatrixCoefficients::Unspecified, + DAV1D_MC_FCC => pixel::MatrixCoefficients::BT470M, + DAV1D_MC_BT470BG => pixel::MatrixCoefficients::BT470BG, + DAV1D_MC_BT601 => pixel::MatrixCoefficients::BT470BG, + DAV1D_MC_SMPTE240 => pixel::MatrixCoefficients::ST240M, + DAV1D_MC_SMPTE_YCGCO => pixel::MatrixCoefficients::YCgCo, + DAV1D_MC_BT2020_NCL => pixel::MatrixCoefficients::BT2020NonConstantLuminance, + DAV1D_MC_BT2020_CL => pixel::MatrixCoefficients::BT2020ConstantLuminance, + DAV1D_MC_SMPTE2085 => pixel::MatrixCoefficients::ST2085, + DAV1D_MC_CHROMAT_NCL => { + pixel::MatrixCoefficients::ChromaticityDerivedNonConstantLuminance + } + DAV1D_MC_CHROMAT_CL => { + pixel::MatrixCoefficients::ChromaticityDerivedConstantLuminance + } + DAV1D_MC_ICTCP => pixel::MatrixCoefficients::ICtCp, + 15..=DAV1D_MC_RESERVED => pixel::MatrixCoefficients::Unspecified, + _ => unreachable!(), + } + } + } + + /// YUV color range. + pub fn color_range(&self) -> pixel::YUVRange { + unsafe { + match (*self.inner.pic.seq_hdr.unwrap().as_ptr()).color_range { + 0 => pixel::YUVRange::Limited, + _ => pixel::YUVRange::Full, + } + } + } + + /// Sample position for subsampled chroma. + pub fn chroma_location(&self) -> pixel::ChromaLocation { + // According to y4m mapping declared in dav1d's output/y4m2.c and applied from FFmpeg's yuv4mpegdec.c + unsafe { + match (*self.inner.pic.seq_hdr.unwrap().as_ptr()).chr { + DAV1D_CHR_UNKNOWN | DAV1D_CHR_COLOCATED => pixel::ChromaLocation::Center, + DAV1D_CHR_VERTICAL => pixel::ChromaLocation::Left, + _ => unreachable!(), + } + } + } + } + + static_assertions::assert_impl_all!(Picture: Send, Sync); + + unsafe impl Send for InnerPicture {} + unsafe impl Sync for InnerPicture {} + + impl Drop for InnerPicture { + fn drop(&mut self) { + unsafe { + dav1d_picture_unref(option_nonnull(&mut self.pic)); + } + } + } + + impl std::fmt::Debug for Picture { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Picture") + .field("width", &self.width()) + .field("height", &self.height()) + .field("bit_depth", &self.bit_depth()) + .field("pixel_layout", &self.pixel_layout()) + .field("timestamp", &self.timestamp()) + .field("duration", &self.duration()) + .field("offset", &self.offset()) + .field("color_primaries", &self.color_primaries()) + .field("transfer_characteristic", &self.transfer_characteristic()) + .field("matrix_coefficients", &self.matrix_coefficients()) + .field("color_range", &self.color_range()) + .field("chroma_location", &self.chroma_location()) + .finish() + } + } +} + +pub use dav1d::*; diff --git a/src/decode.rs b/src/decode.rs index 6695e9798..9a3de607b 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -4994,7 +4994,10 @@ pub fn rav1d_submit_frame(c: &Rav1dContext, state: &mut Rav1dState) -> Rav1dResu ) { fc.task_thread.error.store(1, Ordering::Relaxed); let _ = mem::take(&mut *fc.in_cdf.try_write().unwrap()); - if f.frame_hdr.as_ref().unwrap().refresh_context != 0 { + if f.frame_hdr + .as_ref() + .is_some_and(|frame_hdr| frame_hdr.refresh_context != 0) + { let _ = mem::take(&mut f.out_cdf); } for i in 0..7 { diff --git a/src/ext/x86/x86inc.asm b/src/ext/x86/x86inc.asm index fc490b6f4..e6e6d51c2 100644 --- a/src/ext/x86/x86inc.asm +++ b/src/ext/x86/x86inc.asm @@ -868,6 +868,25 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, extern %1 %endmacro +; Like `cextern`, but assumes the symbol is hidden data (i.e. `extern:data hidden`). +; Portable across all supported platforms. +; +; This can be life saving in position-independent contexts, where it is very easy to generate +; illegal relocations otherwise. +; +; See for more information. +%macro cextern_hidden_data 1 + %xdefine %1 mangle(private_prefix %+ _ %+ %1) + CAT_XDEFINE cglobaled_, %1, 2 + %if FORMAT_ELF + extern %1:data hidden + %elif FORMAT_MACHO && HAVE_PRIVATE_EXTERN + extern %1:private_extern + %else + extern %1 + %endif +%endmacro + ; Like cextern, but without the prefix. This should be used for symbols from external libraries. %macro cextern_naked 1 %ifdef PREFIX diff --git a/src/x86/filmgrain_common.asm b/src/x86/filmgrain_common.asm index 74f7044e6..f15bf3dc7 100644 --- a/src/x86/filmgrain_common.asm +++ b/src/x86/filmgrain_common.asm @@ -43,4 +43,4 @@ struc FGData .clip_to_restricted_range: resd 1 endstruc -cextern gaussian_sequence +cextern_hidden_data gaussian_sequence diff --git a/src/x86/ipred16_avx2.asm b/src/x86/ipred16_avx2.asm index 7b52abaa1..a11b7f777 100644 --- a/src/x86/ipred16_avx2.asm +++ b/src/x86/ipred16_avx2.asm @@ -129,8 +129,8 @@ JMP_TABLE ipred_cfl_left_16bpc, avx2, h4, h8, h16, h32 JMP_TABLE ipred_cfl_ac_444_16bpc, avx2, w4, w8, w16, w32 JMP_TABLE pal_pred_16bpc, avx2, w4, w8, w16, w32, w64 -cextern dr_intra_derivative -cextern filter_intra_taps +cextern_hidden_data dr_intra_derivative +cextern_hidden_data filter_intra_taps SECTION .text diff --git a/src/x86/ipred16_avx512.asm b/src/x86/ipred16_avx512.asm index 69802614c..18fc0dbe2 100644 --- a/src/x86/ipred16_avx512.asm +++ b/src/x86/ipred16_avx512.asm @@ -121,10 +121,10 @@ JMP_TABLE ipred_z2_16bpc, avx512icl, w4, w8, w16, w32, w64 JMP_TABLE ipred_z3_16bpc, avx512icl, w4, w8, w16, w32, w64 JMP_TABLE pal_pred_16bpc, avx512icl, w4, w8, w16, w32, w64 -cextern smooth_weights_1d_16bpc -cextern smooth_weights_2d_16bpc -cextern dr_intra_derivative -cextern filter_intra_taps +cextern_hidden_data smooth_weights_1d_16bpc +cextern_hidden_data smooth_weights_2d_16bpc +cextern_hidden_data dr_intra_derivative +cextern_hidden_data filter_intra_taps SECTION .text diff --git a/src/x86/ipred16_sse.asm b/src/x86/ipred16_sse.asm index 5a311b144..3416574c0 100644 --- a/src/x86/ipred16_sse.asm +++ b/src/x86/ipred16_sse.asm @@ -99,10 +99,10 @@ JMP_TABLE ipred_cfl_left_16bpc, ssse3, h4, h8, h16, h32 JMP_TABLE ipred_cfl_ac_444_16bpc, ssse3, w4, w8, w16, w32 JMP_TABLE pal_pred_16bpc, ssse3, w4, w8, w16, w32, w64 -cextern smooth_weights_1d_16bpc -cextern smooth_weights_2d_16bpc -cextern dr_intra_derivative -cextern filter_intra_taps +cextern_hidden_data smooth_weights_1d_16bpc +cextern_hidden_data smooth_weights_2d_16bpc +cextern_hidden_data dr_intra_derivative +cextern_hidden_data filter_intra_taps SECTION .text diff --git a/src/x86/ipred_avx2.asm b/src/x86/ipred_avx2.asm index 2956ffaf2..4a5483725 100644 --- a/src/x86/ipred_avx2.asm +++ b/src/x86/ipred_avx2.asm @@ -173,8 +173,8 @@ JMP_TABLE ipred_cfl_ac_422, avx2, w16_pad1, w16_pad2, w16_pad3 JMP_TABLE ipred_cfl_ac_444, avx2, w32_pad1, w32_pad2, w32_pad3, w4, w8, w16, w32 JMP_TABLE pal_pred, avx2, w4, w8, w16, w32, w64 -cextern dr_intra_derivative -cextern filter_intra_taps +cextern_hidden_data dr_intra_derivative +cextern_hidden_data filter_intra_taps SECTION .text diff --git a/src/x86/ipred_avx512.asm b/src/x86/ipred_avx512.asm index de953deba..cdd36c23d 100644 --- a/src/x86/ipred_avx512.asm +++ b/src/x86/ipred_avx512.asm @@ -213,8 +213,8 @@ JMP_TABLE ipred_dc_8bpc, avx512icl, h4, h8, h16, h32, h64, w4, w8, w16, s4-10*4, s8-10*4, s16-10*4, s32-10*4, s64-10*4 JMP_TABLE ipred_dc_left_8bpc, avx512icl, h4, h8, h16, h32, h64 -cextern dr_intra_derivative -cextern pb_0to63 +cextern_hidden_data dr_intra_derivative +cextern_hidden_data pb_0to63 SECTION .text diff --git a/src/x86/ipred_sse.asm b/src/x86/ipred_sse.asm index f6b0cad00..8a1bf08c8 100644 --- a/src/x86/ipred_sse.asm +++ b/src/x86/ipred_sse.asm @@ -141,8 +141,8 @@ JMP_TABLE ipred_cfl, ssse3, h4, h8, h16, h32, w4, w8, w16, w32, \ JMP_TABLE ipred_cfl_left, ssse3, h4, h8, h16, h32 JMP_TABLE ipred_filter, ssse3, w4, w8, w16, w32 -cextern dr_intra_derivative -cextern filter_intra_taps +cextern_hidden_data dr_intra_derivative +cextern_hidden_data filter_intra_taps SECTION .text diff --git a/src/x86/looprestoration16_avx2.asm b/src/x86/looprestoration16_avx2.asm index 4cf8b905c..7f1a45663 100644 --- a/src/x86/looprestoration16_avx2.asm +++ b/src/x86/looprestoration16_avx2.asm @@ -62,8 +62,8 @@ pd_0xf00801c7: dd 0xf00801c7 %define pw_256 sgr_lshuf5 -cextern pb_0to63 -cextern sgr_x_by_x_avx2 +cextern_hidden_data pb_0to63 +cextern_hidden_data sgr_x_by_x_avx2 SECTION .text diff --git a/src/x86/looprestoration16_avx512.asm b/src/x86/looprestoration16_avx512.asm index e560c54a4..2722d0e70 100644 --- a/src/x86/looprestoration16_avx512.asm +++ b/src/x86/looprestoration16_avx512.asm @@ -51,7 +51,7 @@ pd_m9: dd -9 pd_8: dd 8 pd_2147483648: dd 2147483648 -cextern sgr_x_by_x +cextern_hidden_data sgr_x_by_x SECTION .text diff --git a/src/x86/looprestoration16_sse.asm b/src/x86/looprestoration16_sse.asm index 872e50298..05aa9ab24 100644 --- a/src/x86/looprestoration16_sse.asm +++ b/src/x86/looprestoration16_sse.asm @@ -59,7 +59,7 @@ pd_0xfffffff0: times 4 dd 0xfffffff0 wiener_shifts: dw 4, 4, 2048, 2048, 1, 1, 8192, 8192 wiener_round: dd 1049600, 1048832 -cextern sgr_x_by_x +cextern_hidden_data sgr_x_by_x SECTION .text diff --git a/src/x86/looprestoration_avx512.asm b/src/x86/looprestoration_avx512.asm index 1e571774c..3a9294e7c 100644 --- a/src/x86/looprestoration_avx512.asm +++ b/src/x86/looprestoration_avx512.asm @@ -53,7 +53,7 @@ pd_m9: dd -9 pd_34816: dd 34816 pd_8421376: dd 8421376 -cextern sgr_x_by_x +cextern_hidden_data sgr_x_by_x SECTION .text diff --git a/src/x86/looprestoration_sse.asm b/src/x86/looprestoration_sse.asm index b5c73a51d..9538979b2 100644 --- a/src/x86/looprestoration_sse.asm +++ b/src/x86/looprestoration_sse.asm @@ -51,7 +51,7 @@ pd_0xffff: times 4 dd 0xffff pd_0xf00800a4: times 4 dd 0xf00800a4 pd_0xf00801c7: times 4 dd 0xf00801c7 -cextern sgr_x_by_x +cextern_hidden_data sgr_x_by_x SECTION .text diff --git a/src/x86/mc16_avx2.asm b/src/x86/mc16_avx2.asm index 6b4424946..9fae60152 100644 --- a/src/x86/mc16_avx2.asm +++ b/src/x86/mc16_avx2.asm @@ -194,11 +194,11 @@ SCALED_JMP_TABLE prep_8tap_scaled, avx2, 4, 8, 16, 32, 64, 128 %define table_offset(type, fn) type %+ fn %+ SUFFIX %+ _table - type %+ SUFFIX -cextern mc_subpel_filters +cextern_hidden_data mc_subpel_filters %define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8) -cextern mc_warp_filter -cextern resize_filter +cextern_hidden_data mc_warp_filter +cextern_hidden_data resize_filter SECTION .text diff --git a/src/x86/mc16_avx512.asm b/src/x86/mc16_avx512.asm index 27715c166..a6ddbc231 100644 --- a/src/x86/mc16_avx512.asm +++ b/src/x86/mc16_avx512.asm @@ -251,12 +251,12 @@ HV_JMP_TABLE prep, 8tap, avx512icl, 2, 4, 8, 16, 32, 64, 128 %define table_offset(type, fn) type %+ fn %+ SUFFIX %+ _table - type %+ SUFFIX -cextern mc_subpel_filters +cextern_hidden_data mc_subpel_filters %define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8) -cextern mc_warp_filter -cextern obmc_masks_avx2 -cextern resize_filter +cextern_hidden_data mc_warp_filter +cextern_hidden_data obmc_masks_avx2 +cextern_hidden_data resize_filter SECTION .text diff --git a/src/x86/mc16_sse.asm b/src/x86/mc16_sse.asm index b0c42597f..6c066d28d 100644 --- a/src/x86/mc16_sse.asm +++ b/src/x86/mc16_sse.asm @@ -158,11 +158,11 @@ BASE_JMP_TABLE prep, ssse3, 4, 8, 16, 32, 64, 128 SCALED_JMP_TABLE put_8tap_scaled, ssse3, 2, 4, 8, 16, 32, 64, 128 SCALED_JMP_TABLE prep_8tap_scaled, ssse3, 4, 8, 16, 32, 64, 128 -cextern mc_subpel_filters +cextern_hidden_data mc_subpel_filters %define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8) -cextern mc_warp_filter -cextern resize_filter +cextern_hidden_data mc_warp_filter +cextern_hidden_data resize_filter SECTION .text diff --git a/src/x86/mc_avx2.asm b/src/x86/mc_avx2.asm index df8bebb1c..98b435448 100644 --- a/src/x86/mc_avx2.asm +++ b/src/x86/mc_avx2.asm @@ -91,10 +91,10 @@ pd_0x3ff: dd 0x3ff pd_0x4000: dd 0x4000 pq_0x40000000: dq 0x40000000 -cextern mc_subpel_filters -cextern mc_warp_filter2 -cextern resize_filter -cextern z_filter_s +cextern_hidden_data mc_subpel_filters +cextern_hidden_data mc_warp_filter2 +cextern_hidden_data resize_filter +cextern_hidden_data z_filter_s %define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8) diff --git a/src/x86/mc_avx512.asm b/src/x86/mc_avx512.asm index 50e670ec2..d8b86dafc 100644 --- a/src/x86/mc_avx512.asm +++ b/src/x86/mc_avx512.asm @@ -200,10 +200,10 @@ pd_512: dd 512 %define pb_64 (wm_sign+8) %define pd_2 (pd_0to7+8) -cextern mc_subpel_filters +cextern_hidden_data mc_subpel_filters %define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8) -cextern mc_warp_filter -cextern resize_filter +cextern_hidden_data mc_warp_filter +cextern_hidden_data resize_filter %macro BASE_JMP_TABLE 3-* %xdefine %1_%2_table (%%table - %3) diff --git a/src/x86/mc_sse.asm b/src/x86/mc_sse.asm index a447a8016..558145a99 100644 --- a/src/x86/mc_sse.asm +++ b/src/x86/mc_sse.asm @@ -202,7 +202,7 @@ const mc_warp_filter2 ; dav1d_mc_warp_filter[] reordered for pmaddubsw usage pw_258: times 2 dw 258 -cextern mc_subpel_filters +cextern_hidden_data mc_subpel_filters %define subpel_filters (mangle(private_prefix %+ _mc_subpel_filters)-8) %macro BIDIR_JMP_TABLE 2-* @@ -9357,7 +9357,7 @@ cglobal emu_edge_8bpc, 10, 13, 2, bw, bh, iw, ih, x, \ %undef reg_blkm %undef reg_tmp -cextern resize_filter +cextern_hidden_data resize_filter %macro SCRATCH 3 %if ARCH_X86_32 diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 7b0189a80..002153f62 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -20,7 +20,7 @@ name = "seek_stress" [dependencies] cfg-if = "1.0.0" libc = "0.2" -rav1d = { path = "../", version = "1.0.0", default-features = false } +rav1d = { path = "../", version = "0.1.0", package = "re_rav1d", default-features = false } [features] default = ["asm", "asm_arm64_dotprod", "asm_arm64_i8mm", "bitdepth_8", "bitdepth_16"] diff --git a/tools/build.rs b/tools/build.rs new file mode 100644 index 000000000..84c55ffdb --- /dev/null +++ b/tools/build.rs @@ -0,0 +1,38 @@ +fn main() { + // NOTE: we rely on libraries that are only distributed for Windows so + // targeting Windows/MSVC is not supported when cross compiling. + #[cfg(all(target_os = "windows", target_env = "msvc"))] + { + use cc::windows_registry; + use std::env; + + let os = env::var("CARGO_CFG_TARGET_OS").expect("missing CARGO_CFG_TARGET_OS"); + let target = env::var("TARGET").expect("missing TARGET"); + if os == "windows" { + // for sprintf, snprintf, etc. + println!("cargo:rustc-link-lib=static=oldnames"); + let tool = windows_registry::find_tool(&target, "cl.exe") + .expect("couldn't find cl.exe; are the Visual Studio C++ tools installed?"); + let lib_paths = &tool + .env() + .iter() + .find(|(key, _val)| key == "LIB") + .expect("LIB path not found") + .1; + for path in lib_paths.to_str().unwrap().split(';') { + if path != "" { + println!("cargo:rustc-link-search={path}"); + } + } + + let getopt = "getopt"; + cc::Build::new() + .files([&"tools/compat/getopt.c"]) + .include("include/compat") + .debug(cfg!(debug_assertions)) + .compile(&getopt); + // cc automatically outputs the following line + // println!("cargo:rustc-link-lib=static={getopt}"); + } + } +}