1 // Copyright (c) 2017-2021, The rav1e contributors. All rights reserved 2 // 3 // This source code is subject to the terms of the BSD 2 Clause License and 4 // the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 5 // was not distributed with this source code in the LICENSE file, you can 6 // obtain it at www.aomedia.org/license/software. If the Alliance for Open 7 // Media Patent License 1.0 was not distributed with this source code in the 8 // PATENTS file, you can obtain it at www.aomedia.org/license/patent. 9 10 //! rav1e is an [AV1] video encoder. It is designed to eventually cover all use 11 //! cases, though in its current form it is most suitable for cases where 12 //! libaom (the reference encoder) is too slow. 13 //! 14 //! ## Features 15 //! 16 //! * Intra and inter frames 17 //! * 64x64 superblocks 18 //! * 4x4 to 64x64 RDO-selected square and 2:1/1:2 rectangular blocks 19 //! * DC, H, V, Paeth, smooth, and a subset of directional prediction modes 20 //! * DCT, (FLIP-)ADST and identity transforms (up to 64x64, 16x16 and 32x32 21 //! respectively) 22 //! * 8-, 10- and 12-bit depth color 23 //! * 4:2:0 (full support), 4:2:2 and 4:4:4 (limited) chroma sampling 24 //! * Variable speed settings 25 //! * Near real-time encoding at high speed levels 26 //! 27 //! ## Usage 28 //! 29 //! Encoding is done through the [`Context`] struct. Examples on 30 //! [`Context::receive_packet`] show how to create a [`Context`], send frames 31 //! into it and receive packets of encoded data. 32 //! 33 //! [AV1]: https://aomediacodec.github.io/av1-spec/av1-spec.pdf 34 //! [`Context`]: struct.Context.html 35 //! [`Context::receive_packet`]: struct.Context.html#method.receive_packet 36 37 #![deny(bare_trait_objects)] 38 #![allow(clippy::cast_lossless)] 39 #![allow(clippy::cast_ptr_alignment)] 40 #![allow(clippy::cognitive_complexity)] 41 #![allow(clippy::needless_range_loop)] 42 #![allow(clippy::too_many_arguments)] 43 #![allow(clippy::verbose_bit_mask)] 44 #![allow(clippy::unreadable_literal)] 45 #![allow(clippy::many_single_char_names)] 46 #![allow(clippy::wrong_self_convention)] 47 #![allow(clippy::missing_safety_doc)] 48 #![allow(clippy::comparison_chain)] 49 #![allow(clippy::upper_case_acronyms)] 50 #![allow(clippy::enum_variant_names)] 51 #![warn(clippy::expl_impl_clone_on_copy)] 52 #![warn(clippy::linkedlist)] 53 #![warn(clippy::map_flatten)] 54 #![warn(clippy::mem_forget)] 55 #![warn(clippy::mut_mut)] 56 #![warn(clippy::mutex_integer)] 57 #![warn(clippy::needless_borrow)] 58 #![warn(clippy::needless_continue)] 59 #![warn(clippy::path_buf_push_overwrite)] 60 #![warn(clippy::range_plus_one)] 61 62 // Override assert! and assert_eq! in tests 63 #[cfg(test)] 64 #[macro_use] 65 extern crate pretty_assertions; 66 67 #[macro_use] 68 extern crate log; 69 70 mod serialize { 71 cfg_if::cfg_if! { 72 if #[cfg(feature="serialize")] { 73 pub use serde::*; 74 } else { 75 pub use noop_proc_macro::{Deserialize, Serialize}; 76 } 77 } 78 } 79 80 mod wasm_bindgen { 81 cfg_if::cfg_if! { 82 if #[cfg(feature="wasm")] { 83 pub use wasm_bindgen::prelude::*; 84 } else { 85 pub use noop_proc_macro::wasm_bindgen; 86 } 87 } 88 } 89 90 mod rayon { 91 cfg_if::cfg_if! { 92 if #[cfg(all(target_arch="wasm32", not(target_feature = "atomics")))] { 93 pub struct ThreadPoolBuilder (); 94 impl ThreadPoolBuilder { 95 pub fn new() -> ThreadPoolBuilder { 96 ThreadPoolBuilder() 97 } 98 pub fn build(self) -> Result<ThreadPool, ()> { 99 Ok(ThreadPool()) 100 } 101 pub fn num_threads(self, _num_threads: usize) -> ThreadPoolBuilder { 102 ThreadPoolBuilder() 103 } 104 } 105 #[derive(Debug)] 106 pub struct ThreadPool (); 107 impl ThreadPool { 108 pub fn install<OP, R>(&self, op: OP) -> R where 109 OP: FnOnce() -> R + Send, 110 R: Send, { 111 op() 112 } 113 } 114 115 pub mod iter { 116 pub trait IntoParallelIterator { 117 type Iter: Iterator<Item = Self::Item>; 118 type Item: Send; 119 120 fn into_par_iter(self) -> Self::Iter; 121 } 122 123 impl<I: IntoIterator> IntoParallelIterator for I where 124 I::Item : Send { 125 type Item = I::Item; 126 type Iter = I::IntoIter; 127 128 fn into_par_iter(self) -> I::IntoIter { 129 self.into_iter() 130 } 131 } 132 133 pub trait IntoParallelRefMutIterator<'data> { 134 type Iter: IntoParallelIterator<Item = Self::Item>; 135 type Item: Send + 'data; 136 137 fn par_iter_mut(&'data mut self) -> Self::Iter; 138 } 139 140 impl<'data, I: 'data + ?Sized> IntoParallelRefMutIterator<'data> for I 141 where 142 &'data mut I: IntoParallelIterator, 143 { 144 type Iter = <&'data mut I as IntoParallelIterator>::Iter; 145 type Item = <&'data mut I as IntoParallelIterator>::Item; 146 147 fn par_iter_mut(&'data mut self) -> Self::Iter { 148 self.into_par_iter() 149 } 150 } 151 152 pub trait ParallelIterator: Iterator { 153 fn flat_map_iter<U, F>(self, f: F) -> std::iter::FlatMap<Self, U, F> 154 where 155 Self: Sized, 156 U: IntoIterator, 157 F: FnMut(<Self as Iterator>::Item) -> U, 158 { 159 self.flat_map(f) 160 } 161 } 162 163 impl<I: Iterator> ParallelIterator for I {} 164 } 165 166 pub mod slice { 167 pub trait ParallelSlice<T: Sync> { 168 fn par_chunks_exact( 169 &self, chunk_size: usize, 170 ) -> std::slice::ChunksExact<'_, T>; 171 } 172 173 impl<T: Sync> ParallelSlice<T> for [T] { 174 #[inline] 175 fn par_chunks_exact( 176 &self, chunk_size: usize, 177 ) -> std::slice::ChunksExact<'_, T> { 178 self.chunks_exact(chunk_size) 179 } 180 } 181 } 182 183 pub mod prelude { 184 pub use super::iter::*; 185 pub use super::slice::*; 186 } 187 188 pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) 189 where 190 A: FnOnce() -> RA + Send, 191 B: FnOnce() -> RB + Send, 192 RA: Send, 193 RB: Send { 194 (oper_a(), oper_b()) 195 } 196 197 use std::marker::PhantomData; 198 199 pub struct Scope<'scope>{ 200 marker: PhantomData<Box<dyn FnOnce(&Scope<'scope>) + Send + Sync + 'scope>>, 201 } 202 203 impl<'scope> Scope<'scope> { 204 pub fn spawn<BODY>(&self, body: BODY) 205 where BODY: FnOnce(&Scope<'scope>) + Send + 'scope 206 { 207 body(self) 208 } 209 } 210 211 pub fn scope<'scope, OP, R>(op: OP) -> R 212 where OP: for<'s> FnOnce(&'s Scope<'scope>) -> R + 'scope + Send, R: Send, 213 { 214 op(&Scope { marker: PhantomData}) 215 } 216 } else { 217 pub use rayon::*; 218 } 219 } 220 } 221 222 #[cfg(any(cargo_c, feature = "capi"))] 223 pub mod capi; 224 225 #[macro_use] 226 mod transform; 227 #[macro_use] 228 mod cpu_features; 229 230 mod activity; 231 pub(crate) mod asm; 232 mod dist; 233 mod ec; 234 mod partition; 235 mod predict; 236 mod quantize; 237 mod rdo; 238 mod rdo_tables; 239 #[macro_use] 240 mod util; 241 mod cdef; 242 mod context; 243 mod deblock; 244 mod encoder; 245 mod entropymode; 246 mod lrf; 247 mod mc; 248 mod me; 249 mod rate; 250 mod recon_intra; 251 mod sad_row; 252 mod scan_order; 253 #[cfg(feature = "scenechange")] 254 pub mod scenechange; 255 #[cfg(not(feature = "scenechange"))] 256 mod scenechange; 257 mod segmentation; 258 mod stats; 259 mod tiling; 260 mod token_cdfs; 261 262 mod api; 263 mod frame; 264 mod header; 265 266 use crate::encoder::*; 267 268 pub use crate::api::{ 269 Config, Context, EncoderConfig, EncoderStatus, InvalidConfig, Packet, 270 }; 271 pub use crate::frame::Frame; 272 pub use crate::util::{CastFromPrimitive, Pixel, PixelType}; 273 274 /// Commonly used types and traits. 275 pub mod prelude { 276 pub use crate::api::*; 277 pub use crate::encoder::{Sequence, Tune}; 278 pub use crate::frame::{ 279 Frame, FrameParameters, FrameTypeOverride, Plane, PlaneConfig, 280 }; 281 pub use crate::partition::BlockSize; 282 pub use crate::predict::PredictionMode; 283 pub use crate::transform::TxType; 284 pub use crate::util::{CastFromPrimitive, Pixel, PixelType}; 285 } 286 287 /// Basic data structures 288 pub mod data { 289 pub use crate::api::{ 290 ChromaticityPoint, EncoderStatus, FrameType, Packet, Rational, 291 }; 292 pub use crate::frame::{Frame, FrameParameters}; 293 pub use crate::stats::EncoderStats; 294 pub use crate::util::{CastFromPrimitive, Pixel, PixelType}; 295 } 296 297 pub use crate::api::color; 298 299 /// Encoder configuration and settings 300 pub mod config { 301 pub use crate::api::{ 302 Config, EncoderConfig, InvalidConfig, PredictionModesSetting, 303 RateControlConfig, RateControlError, RateControlSummary, SpeedSettings, 304 }; 305 pub use crate::cpu_features::CpuFeatureLevel; 306 } 307 308 /// Version information 309 /// 310 /// The information is recovered from `Cargo.toml` and `git describe`, when available. 311 /// 312 /// ``` 313 /// use rav1e::version; 314 /// use semver::Version; 315 /// 316 /// let major = version::major(); 317 /// let minor = version::minor(); 318 /// let patch = version::patch(); 319 /// 320 /// let short = version::short(); 321 /// 322 /// let v1 = Version::new(major, minor, patch); 323 /// let v2 = Version::parse(&short).unwrap(); 324 /// 325 /// assert_eq!(v1.major, v2.major); 326 /// ``` 327 pub mod version { 328 /// Major version component 329 /// 330 /// It is increased every time a release presents a incompatible API change. major() -> u64331 pub fn major() -> u64 { 332 env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap() 333 } 334 /// Minor version component 335 /// 336 /// It is increased every time a release presents new functionalities are added 337 /// in a backwards-compatible manner. minor() -> u64338 pub fn minor() -> u64 { 339 env!("CARGO_PKG_VERSION_MINOR").parse().unwrap() 340 } 341 /// Patch version component 342 /// 343 /// It is increased every time a release provides only backwards-compatible bugfixes. patch() -> u64344 pub fn patch() -> u64 { 345 env!("CARGO_PKG_VERSION_PATCH").parse().unwrap() 346 } 347 348 /// Version information as presented in `[package]` `version`. 349 /// 350 /// e.g. `0.1.0`` 351 /// 352 /// Can be parsed by [semver](https://crates.io/crates/semver). short() -> String353 pub fn short() -> String { 354 env!("CARGO_PKG_VERSION").to_string() 355 } 356 357 /// Version information as presented in `[package] version` followed by the 358 /// short commit hash if present. 359 /// 360 /// e.g. `0.1.0 - g743d464` 361 /// long() -> String362 pub fn long() -> String { 363 let s = short(); 364 let hash = hash(); 365 366 if hash.is_empty() { 367 s 368 } else { 369 format!("{} - {}", s, hash) 370 } 371 } 372 373 /// Commit hash (short) 374 /// 375 /// Short hash of the git commit used by this build 376 /// 377 /// e.g. `g743d464` 378 /// hash() -> String379 pub fn hash() -> String { 380 env!("VERGEN_SHA_SHORT").to_string() 381 } 382 383 /// Version information with the information 384 /// provided by `git describe --tags`. 385 /// 386 /// e.g. `0.1.0 (v0.1.0-1-g743d464)` 387 /// full() -> String388 pub fn full() -> String { 389 let semver = "v0.5.1"; 390 format!("{} ({})", short(), semver) 391 } 392 } 393 #[cfg(all( 394 any(test, fuzzing), 395 any(feature = "decode_test", feature = "decode_test_dav1d") 396 ))] 397 mod test_encode_decode; 398 399 #[cfg(feature = "bench")] 400 pub mod bench { 401 pub mod api { 402 pub use crate::api::*; 403 } 404 pub mod cdef { 405 pub use crate::cdef::*; 406 } 407 pub mod context { 408 pub use crate::context::*; 409 } 410 pub mod dist { 411 pub use crate::dist::*; 412 } 413 pub mod ec { 414 pub use crate::ec::*; 415 } 416 pub mod encoder { 417 pub use crate::encoder::*; 418 } 419 pub mod mc { 420 pub use crate::mc::*; 421 } 422 pub mod partition { 423 pub use crate::partition::*; 424 } 425 pub mod frame { 426 pub use crate::frame::*; 427 } 428 pub mod predict { 429 pub use crate::predict::*; 430 } 431 pub mod rdo { 432 pub use crate::rdo::*; 433 } 434 pub mod tiling { 435 pub use crate::tiling::*; 436 } 437 pub mod transform { 438 pub use crate::transform::*; 439 } 440 pub mod util { 441 pub use crate::util::*; 442 } 443 pub mod cpu_features { 444 pub use crate::cpu_features::*; 445 } 446 } 447 448 #[cfg(fuzzing)] 449 pub mod fuzzing; 450