diff --git a/.github/workflows/contrib_rerun_py.yml b/.github/workflows/contrib_rerun_py.yml index 323ac0974400..25cfc2978be7 100644 --- a/.github/workflows/contrib_rerun_py.yml +++ b/.github/workflows/contrib_rerun_py.yml @@ -61,11 +61,11 @@ jobs: # this stops `re_web_viewer_server/build.rs` from running RERUN_IS_PUBLISHING: true run: | - cargo build \ + pixi run cargo build \ --locked \ -p rerun-cli \ --no-default-features \ - --features native_viewer,web_viewer \ + --features release \ --release \ --target x86_64-unknown-linux-gnu diff --git a/.github/workflows/reusable_build_and_upload_rerun_cli.yml b/.github/workflows/reusable_build_and_upload_rerun_cli.yml index f3279346b271..2316e6686bc6 100644 --- a/.github/workflows/reusable_build_and_upload_rerun_cli.yml +++ b/.github/workflows/reusable_build_and_upload_rerun_cli.yml @@ -176,11 +176,11 @@ jobs: # this stops `re_web_viewer_server/build.rs` from running RERUN_IS_PUBLISHING: true run: | - cargo build \ + pixi run cargo build \ --locked \ -p rerun-cli \ --no-default-features \ - --features native_viewer,web_viewer \ + --features release \ --release \ --target ${{ needs.set-config.outputs.TARGET }} diff --git a/crates/store/re_video/Cargo.toml b/crates/store/re_video/Cargo.toml index f9eef572ba4e..02035987964c 100644 --- a/crates/store/re_video/Cargo.toml +++ b/crates/store/re_video/Cargo.toml @@ -30,9 +30,8 @@ av1 = ["dep:dav1d"] ## Enable faster native video decoding with assembly. ## You need to install [nasm](https://nasm.us/) to compile with this feature. -# TODO(#7671): this feature flag currently does nothing on Linux. nasm = [ - # The default feature set of our dav1d fork has asm enabled (except on Linux, see above) + # The default feature set of our dav1d fork has asm enabled "dav1d?/default", ] diff --git a/crates/store/re_video/src/decode/av1.rs b/crates/store/re_video/src/decode/av1.rs index 2409199753a9..0dc631ffe86a 100644 --- a/crates/store/re_video/src/decode/av1.rs +++ b/crates/store/re_video/src/decode/av1.rs @@ -37,14 +37,22 @@ impl SyncDav1dDecoder { pub fn new(debug_name: String) -> Result { re_tracing::profile_function!(); - // TODO(#7671): enable this warning again on Linux when the `nasm` feature actually does something - #[allow(clippy::overly_complex_bool_expr)] - if !cfg!(target_os = "linux") && !cfg!(feature = "nasm") { - re_log::warn_once!( - "NOTE: native AV1 video decoder is running extra slowly. \ - Speed it up by compiling Rerun with the `nasm` feature enabled. \ - You'll need to also install nasm: https://nasm.us/" - ); + if !cfg!(feature = "nasm") { + // The `nasm` feature makes AV1 decoding much faster. + // On Linux the difference is huge (~25x). + // On Windows, the difference was also pretty big (unsure how big). + // On an M3 Mac the difference is smalelr (2-3x), + // and ever without `nasm` emilk can play an 8k video at 2x speed. + + if cfg!(target_os = "macos") && cfg!(target_arch = "aarch64") { + re_log::warn_once!( + "The native AV1 video decoder is unnecessarily slow. \ + Speed it up by compiling Rerun with the `nasm` feature enabled." + ); + } else { + // Better to return an error than to be perceived as being slow + return Err(Error::Dav1dWithoutNasm); + } } // See https://videolan.videolan.me/dav1d/structDav1dSettings.html for settings docs diff --git a/crates/store/re_video/src/decode/mod.rs b/crates/store/re_video/src/decode/mod.rs index 5d46985e4aa7..071c892948fe 100644 --- a/crates/store/re_video/src/decode/mod.rs +++ b/crates/store/re_video/src/decode/mod.rs @@ -100,6 +100,11 @@ pub enum Error { #[cfg(not(target_arch = "wasm32"))] #[error("dav1d: {0}")] Dav1d(#[from] dav1d::Error), + + #[cfg(feature = "av1")] + #[cfg(not(target_arch = "wasm32"))] + #[error("To enabled native AV1 decoding, compile Rerun with the `nasm` feature enabled.")] + Dav1dWithoutNasm, } pub type Result = std::result::Result; diff --git a/crates/store/re_video/src/lib.rs b/crates/store/re_video/src/lib.rs index 30785cc7e997..b007518fb2f4 100644 --- a/crates/store/re_video/src/lib.rs +++ b/crates/store/re_video/src/lib.rs @@ -1,102 +1,27 @@ //! Video decoding library. +mod time; + pub mod decode; pub mod demux; -pub use decode::{Chunk, Frame, PixelFormat}; -pub use demux::{Config, Sample, VideoData, VideoLoadError}; pub use re_mp4::{TrackId, TrackKind}; -/// A value in time units. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Time(i64); - -impl Time { - pub const ZERO: Self = Self(0); - pub const MAX: Self = Self(i64::MAX); - - /// Create a new value in _time units_. - /// - /// ⚠️ Don't use this for regular timestamps in seconds/milliseconds/etc., - /// use the proper constructors for those instead! - /// This only exists for cases where you already have a value expressed in time units, - /// such as those received from the `WebCodecs` APIs. - #[inline] - pub fn new(v: i64) -> Self { - Self(v) - } - - #[inline] - pub fn from_secs(v: f64, timescale: Timescale) -> Self { - Self((v * timescale.0 as f64).round() as i64) - } - - #[inline] - pub fn from_millis(v: f64, timescale: Timescale) -> Self { - Self::from_secs(v / 1e3, timescale) - } - - #[inline] - pub fn from_micros(v: f64, timescale: Timescale) -> Self { - Self::from_secs(v / 1e6, timescale) - } - - #[inline] - pub fn from_nanos(v: i64, timescale: Timescale) -> Self { - Self::from_secs(v as f64 / 1e9, timescale) - } - - /// Convert to a duration - #[inline] - pub fn duration(self, timescale: Timescale) -> std::time::Duration { - std::time::Duration::from_nanos(self.into_nanos(timescale) as _) - } - - #[inline] - pub fn into_secs(self, timescale: Timescale) -> f64 { - self.0 as f64 / timescale.0 as f64 - } +pub use self::{ + decode::{Chunk, Frame, PixelFormat}, + demux::{Config, Sample, VideoData, VideoLoadError}, + time::{Time, Timescale}, +}; - #[inline] - pub fn into_millis(self, timescale: Timescale) -> f64 { - self.into_secs(timescale) * 1e3 +/// Which features was this crate compiled with? +pub fn features() -> Vec<&'static str> { + // TODO(emilk): is there a helper crate for this? + let mut features = vec![]; + if cfg!(feature = "av1") { + features.push("av1"); } - - #[inline] - pub fn into_micros(self, timescale: Timescale) -> f64 { - self.into_secs(timescale) * 1e6 - } - - #[inline] - pub fn into_nanos(self, timescale: Timescale) -> i64 { - (self.into_secs(timescale) * 1e9).round() as i64 - } -} - -impl std::ops::Add for Time { - type Output = Self; - - #[inline] - fn add(self, rhs: Self) -> Self::Output { - Self(self.0.saturating_add(rhs.0)) - } -} - -impl std::ops::Sub for Time { - type Output = Self; - - #[inline] - fn sub(self, rhs: Self) -> Self::Output { - Self(self.0.saturating_sub(rhs.0)) - } -} - -/// The number of time units per second. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Timescale(u64); - -impl Timescale { - pub(crate) fn new(v: u64) -> Self { - Self(v) + if cfg!(feature = "nasm") { + features.push("nasm"); } + features } diff --git a/crates/store/re_video/src/time.rs b/crates/store/re_video/src/time.rs new file mode 100644 index 000000000000..fc0c36619d4b --- /dev/null +++ b/crates/store/re_video/src/time.rs @@ -0,0 +1,93 @@ +/// The number of time units per second. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Timescale(u64); + +impl Timescale { + pub(crate) fn new(v: u64) -> Self { + Self(v) + } +} + +/// A value in time units. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Time(pub i64); + +impl Time { + pub const ZERO: Self = Self(0); + pub const MAX: Self = Self(i64::MAX); + + /// Create a new value in _time units_. + /// + /// ⚠️ Don't use this for regular timestamps in seconds/milliseconds/etc., + /// use the proper constructors for those instead! + /// This only exists for cases where you already have a value expressed in time units, + /// such as those received from the `WebCodecs` APIs. + #[inline] + pub fn new(v: i64) -> Self { + Self(v) + } + + #[inline] + pub fn from_secs(v: f64, timescale: Timescale) -> Self { + Self((v * timescale.0 as f64).round() as i64) + } + + #[inline] + pub fn from_millis(v: f64, timescale: Timescale) -> Self { + Self::from_secs(v / 1e3, timescale) + } + + #[inline] + pub fn from_micros(v: f64, timescale: Timescale) -> Self { + Self::from_secs(v / 1e6, timescale) + } + + #[inline] + pub fn from_nanos(v: i64, timescale: Timescale) -> Self { + Self::from_secs(v as f64 / 1e9, timescale) + } + + /// Convert to a duration + #[inline] + pub fn duration(self, timescale: Timescale) -> std::time::Duration { + std::time::Duration::from_nanos(self.into_nanos(timescale) as _) + } + + #[inline] + pub fn into_secs(self, timescale: Timescale) -> f64 { + self.0 as f64 / timescale.0 as f64 + } + + #[inline] + pub fn into_millis(self, timescale: Timescale) -> f64 { + self.into_secs(timescale) * 1e3 + } + + #[inline] + pub fn into_micros(self, timescale: Timescale) -> f64 { + self.into_secs(timescale) * 1e6 + } + + #[inline] + pub fn into_nanos(self, timescale: Timescale) -> i64 { + (self.into_secs(timescale) * 1e9).round() as i64 + } +} + +impl std::ops::Add for Time { + type Output = Self; + + #[inline] + fn add(self, rhs: Self) -> Self::Output { + Self(self.0.saturating_add(rhs.0)) + } +} + +impl std::ops::Sub for Time { + type Output = Self; + + #[inline] + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0.saturating_sub(rhs.0)) + } +} diff --git a/crates/top/rerun-cli/Cargo.toml b/crates/top/rerun-cli/Cargo.toml index 2cf4ac433a67..ce0c0f96bf98 100644 --- a/crates/top/rerun-cli/Cargo.toml +++ b/crates/top/rerun-cli/Cargo.toml @@ -37,13 +37,18 @@ path = "src/bin/rerun.rs" doc = false [features] -# The default is what the user gets when they call `cargo install rerun-cli --locked`, -# so wer have all the bells and wistles here +## The default is what the user gets when they call `cargo install rerun-cli --locked`, +## so we have all the bells and wistles here, except those that may require extra tools +## (like "nasm"). +## That is: `cargo install rerun-cli --locked` should work for _everyone_. default = ["native_viewer", "web_viewer"] +## The features we enable when we build the pre-built binaries during our releases. +## This may enable features that require extra build tools that not everyone heas. +release = ["default", "nasm"] + ## Enable faster native video decoding with assembly. ## You need to install [nasm](https://nasm.us/) to compile with this feature. -# TODO(#7671): this feature flag currently does nothing on linux. nasm = ["rerun/nasm"] ## Support spawning a native viewer. diff --git a/crates/top/rerun/Cargo.toml b/crates/top/rerun/Cargo.toml index fb7214aad752..cc3ae783161a 100644 --- a/crates/top/rerun/Cargo.toml +++ b/crates/top/rerun/Cargo.toml @@ -73,7 +73,6 @@ log = ["dep:env_logger", "dep:log"] ## Enable faster native video decoding with assembly. ## You need to install [nasm](https://nasm.us/) to compile with this feature. -# TODO(#7671): this feature flag currently does nothing on linux. nasm = ["re_video/nasm"] ## Support spawning a native viewer. diff --git a/crates/top/rerun/src/commands/entrypoint.rs b/crates/top/rerun/src/commands/entrypoint.rs index 71b47617c9fe..6fe9e16c5b05 100644 --- a/crates/top/rerun/src/commands/entrypoint.rs +++ b/crates/top/rerun/src/commands/entrypoint.rs @@ -553,6 +553,7 @@ where if args.version { println!("{build_info}"); + println!("Video features: {}", re_video::features().join(" ")); return Ok(0); } diff --git a/rerun_py/Cargo.toml b/rerun_py/Cargo.toml index 992d5b5f5977..192c5f229b1e 100644 --- a/rerun_py/Cargo.toml +++ b/rerun_py/Cargo.toml @@ -30,7 +30,6 @@ extension-module = ["pyo3/extension-module"] ## Enable faster native video decoding with assembly. ## You need to install [nasm](https://nasm.us/) to compile with this feature. -# TODO(#7671): this feature flag currently does nothing on linux. nasm = ["re_video/nasm"] ## Support serving a web viewer over HTTP with `serve()`.