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