Skip to content

Commit 202e645

Browse files
committed
Implement grain synthesis via photon noise tables
1 parent f3290aa commit 202e645

24 files changed

+1769
-46
lines changed

Cargo.toml

+7-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ binaries = [
3636
"fern",
3737
"console",
3838
"av-metrics",
39+
"nom",
3940
]
4041
default = ["binaries", "asm", "threading", "signal_support"]
4142
asm = ["nasm-rs", "cc", "regex"]
@@ -63,7 +64,11 @@ dump_lookahead_data = ["byteorder", "image"]
6364
arg_enum_proc_macro = "0.3"
6465
bitstream-io = "1"
6566
cfg-if = "1.0"
66-
clap = { version = "3.1", optional = true, default-features = false, features = ["color", "std", "wrap_help"] }
67+
clap = { version = "3.1", optional = true, default-features = false, features = [
68+
"color",
69+
"std",
70+
"wrap_help",
71+
] }
6772
clap_complete = { version = "3", optional = true }
6873
libc = "0.2"
6974
y4m = { version = "0.7", optional = true }
@@ -94,6 +99,7 @@ wasm-bindgen = { version = "0.2.63", optional = true }
9499
rust_hawktracer = "0.7.0"
95100
arrayref = "0.3.6"
96101
const_fn_assert = "0.1.2"
102+
nom = { version = "7.0.0", optional = true }
97103

98104
[dependencies.image]
99105
version = "0.23"

examples/simple_encoding.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn main() {
1919
..Default::default()
2020
};
2121

22-
let cfg = Config::new().with_encoder_config(enc);
22+
let cfg = Config::new().with_encoder_config(enc.clone());
2323

2424
let mut ctx: Context<u16> = cfg.new_context().unwrap();
2525

src/api/channel/by_gop.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<T: Pixel> SceneChange<T> {
5252
let seq = Arc::new(Sequence::new(enc));
5353

5454
let detector = SceneChangeDetector::new(
55-
*enc,
55+
enc.clone(),
5656
CpuFeatureLevel::default(),
5757
pyramid_size,
5858
seq,
@@ -353,8 +353,11 @@ impl Config {
353353
}
354354

355355
let channel = (
356-
FrameSender::new(frame_limit, send_frame, Arc::new(self.enc)),
357-
PacketReceiver { receiver: receive_packet, config: Arc::new(self.enc) },
356+
FrameSender::new(frame_limit, send_frame, Arc::new(self.enc.clone())),
357+
PacketReceiver {
358+
receiver: receive_packet,
359+
config: Arc::new(self.enc.clone()),
360+
},
358361
);
359362

360363
Ok(channel)

src/api/channel/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ impl Config {
292292
(None, None, i32::MAX as u64)
293293
};
294294

295-
let config = Arc::new(self.enc);
295+
let config = Arc::new(self.enc.clone());
296296

297297
let channel = (
298298
FrameSender::new(frame_limit, send_frame, config.clone()),

src/api/config/encoder.rs

+41-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2020-2021, The rav1e contributors. All rights reserved
1+
// Copyright (c) 2020-2022, The rav1e contributors. All rights reserved
22
//
33
// This source code is subject to the terms of the BSD 2 Clause License and
44
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
@@ -10,6 +10,8 @@
1010
use itertools::*;
1111

1212
use crate::api::color::*;
13+
#[cfg(feature = "unstable")]
14+
use crate::api::config::GrainTableParams;
1315
use crate::api::{Rational, SpeedSettings};
1416
use crate::encoder::Tune;
1517
use crate::serialize::{Deserialize, Serialize};
@@ -22,7 +24,7 @@ pub(crate) const MAX_RDO_LOOKAHEAD_FRAMES: usize = usize::max_value() - 1;
2224
pub(crate) const MAX_MAX_KEY_FRAME_INTERVAL: u64 = i32::max_value() as u64 / 3;
2325

2426
/// Encoder settings which impact the produced bitstream.
25-
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
27+
#[derive(Clone, Debug, Serialize, Deserialize)]
2628
pub struct EncoderConfig {
2729
// output size
2830
/// Width of the frames in pixels.
@@ -82,6 +84,9 @@ pub struct EncoderConfig {
8284
pub bitrate: i32,
8385
/// Metric to tune the quality for.
8486
pub tune: Tune,
87+
/// Parameters for grain synthesis.
88+
#[cfg(feature = "unstable")]
89+
pub film_grain_params: Option<Vec<GrainTableParams>>,
8590
/// Number of tiles horizontally. Must be a power of two.
8691
///
8792
/// Overridden by [`tiles`], if present.
@@ -155,6 +160,8 @@ impl EncoderConfig {
155160
quantizer: 100,
156161
bitrate: 0,
157162
tune: Tune::default(),
163+
#[cfg(feature = "unstable")]
164+
film_grain_params: None,
158165
tile_cols: 0,
159166
tile_rows: 0,
160167
tiles: 0,
@@ -215,6 +222,38 @@ impl EncoderConfig {
215222
// might be bigger than 8x8. So temporal RDO is always disabled in that case.
216223
!self.speed_settings.transform.tx_domain_distortion
217224
}
225+
226+
/// Describes whether the output is targeted as HDR
227+
pub fn is_hdr(&self) -> bool {
228+
self
229+
.color_description
230+
.map(|colors| {
231+
colors.transfer_characteristics == TransferCharacteristics::SMPTE2084
232+
})
233+
.unwrap_or(false)
234+
}
235+
236+
#[cfg(feature = "unstable")]
237+
pub(crate) fn get_film_grain_at(
238+
&self, timestamp: u64,
239+
) -> Option<&GrainTableParams> {
240+
self.film_grain_params.as_ref().and_then(|entries| {
241+
entries.iter().find(|entry| {
242+
timestamp >= entry.start_time && timestamp < entry.end_time
243+
})
244+
})
245+
}
246+
247+
#[cfg(feature = "unstable")]
248+
pub(crate) fn get_film_grain_mut_at(
249+
&mut self, timestamp: u64,
250+
) -> Option<&mut GrainTableParams> {
251+
self.film_grain_params.as_mut().and_then(|entries| {
252+
entries.iter_mut().find(|entry| {
253+
timestamp >= entry.start_time && timestamp < entry.end_time
254+
})
255+
})
256+
}
218257
}
219258

220259
impl fmt::Display for EncoderConfig {

src/api/config/grain_synth.rs

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2022-2022, 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+
use crate::serialize::{Deserialize, Serialize};
11+
use arrayvec::ArrayVec;
12+
13+
/// The max number of luma scaling points for grain synthesis
14+
pub const GS_NUM_Y_POINTS: usize = 14;
15+
/// The max number of scaling points per chroma plane for grain synthesis
16+
pub const GS_NUM_UV_POINTS: usize = 10;
17+
/// The max number of luma coefficients for grain synthesis
18+
pub const GS_NUM_Y_COEFFS: usize = 24;
19+
/// The max number of coefficients per chroma plane for grain synthesis
20+
pub const GS_NUM_UV_COEFFS: usize = 25;
21+
22+
/// A randomly generated u16 to be used as a starting random seed
23+
/// for grain synthesis.
24+
pub const DEFAULT_GS_SEED: u16 = 10956;
25+
26+
/// Specifies parameters for enabling decoder-side grain synthesis for
27+
/// a segment of video from `start_time` to `end_time`.
28+
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
29+
pub struct GrainTableParams {
30+
/// The beginning timestamp of this segment, in 10,000,000ths of a second.
31+
pub start_time: u64,
32+
/// The ending timestamp of this segment, not inclusive, in 10,000,000ths of a second.
33+
pub end_time: u64,
34+
35+
/// Values for the cutoffs and scale factors for luma scaling points
36+
pub scaling_points_y: ArrayVec<[u8; 2], GS_NUM_Y_POINTS>,
37+
/// Values for the cutoffs and scale factors for Cb scaling points
38+
pub scaling_points_cb: ArrayVec<[u8; 2], GS_NUM_UV_POINTS>,
39+
/// Values for the cutoffs and scale factors for Cr scaling points
40+
pub scaling_points_cr: ArrayVec<[u8; 2], GS_NUM_UV_POINTS>,
41+
42+
/// Determines the range and quantization step of the standard deviation
43+
/// of film grain.
44+
///
45+
/// Accepts values between `8..=11`.
46+
pub scaling_shift: u8,
47+
48+
/// A factor specifying how many AR coefficients are provided,
49+
/// based on the forumla `coeffs_len = (2 * ar_coeff_lag * (ar_coeff_lag + 1))`.
50+
///
51+
/// Accepts values between `0..=3`.
52+
pub ar_coeff_lag: u8,
53+
/// Values for the AR coefficients for luma scaling points
54+
pub ar_coeffs_y: ArrayVec<i8, GS_NUM_Y_COEFFS>,
55+
/// Values for the AR coefficients for Cb scaling points
56+
pub ar_coeffs_cb: ArrayVec<i8, GS_NUM_UV_COEFFS>,
57+
/// Values for the AR coefficients for Cr scaling points
58+
pub ar_coeffs_cr: ArrayVec<i8, GS_NUM_UV_COEFFS>,
59+
/// Shift value: Specifies the range of acceptable AR coefficients
60+
/// 6: [-2, 2)
61+
/// 7: [-1, 1)
62+
/// 8: [-0.5, 0.5)
63+
/// 9: [-0.25, 0.25)
64+
pub ar_coeff_shift: u8,
65+
/// Multiplier to the grain strength of the Cb plane
66+
pub cb_mult: u8,
67+
/// Multiplier to the grain strength of the Cb plane inherited from the luma plane
68+
pub cb_luma_mult: u8,
69+
/// A base value for the Cb plane grain
70+
pub cb_offset: u16,
71+
/// Multiplier to the grain strength of the Cr plane
72+
pub cr_mult: u8,
73+
/// Multiplier to the grain strength of the Cr plane inherited from the luma plane
74+
pub cr_luma_mult: u8,
75+
/// A base value for the Cr plane grain
76+
pub cr_offset: u16,
77+
78+
/// Whether film grain blocks should overlap or not
79+
pub overlap_flag: bool,
80+
/// Scale chroma grain from luma instead of providing chroma scaling points
81+
pub chroma_scaling_from_luma: bool,
82+
/// Specifies how much the Gaussian random numbers should be scaled down during the grain synthesis
83+
/// process.
84+
pub grain_scale_shift: u8,
85+
/// Random seed used for generating grain
86+
pub random_seed: u16,
87+
}

src/api/config/mod.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2020-2021, The rav1e contributors. All rights reserved
1+
// Copyright (c) 2020-2022, The rav1e contributors. All rights reserved
22
//
33
// This source code is subject to the terms of the BSD 2 Clause License and
44
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
@@ -18,6 +18,11 @@ use crate::util::Pixel;
1818
mod encoder;
1919
pub use encoder::*;
2020

21+
#[cfg(feature = "unstable")]
22+
mod grain_synth;
23+
#[cfg(feature = "unstable")]
24+
pub use grain_synth::*;
25+
2126
mod rate;
2227
pub use rate::Error as RateControlError;
2328
pub use rate::{RateControlConfig, RateControlSummary};
@@ -145,7 +150,7 @@ impl Config {
145150
///
146151
/// `EncoderConfig` contains the settings impacting the
147152
/// codec features used in the produced bitstream.
148-
pub const fn with_encoder_config(mut self, enc: EncoderConfig) -> Self {
153+
pub fn with_encoder_config(mut self, enc: EncoderConfig) -> Self {
149154
self.enc = enc;
150155
self
151156
}
@@ -212,7 +217,7 @@ impl Config {
212217

213218
self.validate()?;
214219

215-
let mut config = self.enc;
220+
let mut config = self.enc.clone();
216221
config.set_key_frame_interval(
217222
config.min_key_frame_interval,
218223
config.max_key_frame_interval,
@@ -276,7 +281,7 @@ impl Config {
276281
/// [`Context`]: struct.Context.html
277282
pub fn new_context<T: Pixel>(&self) -> Result<Context<T>, InvalidConfig> {
278283
let inner = self.new_inner()?;
279-
let config = *inner.config;
284+
let config = (*inner.config).clone();
280285
let pool = self.new_thread_pool();
281286

282287
Ok(Context { is_flushing: false, inner, pool, config })

src/api/internal.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2018-2021, The rav1e contributors. All rights reserved
1+
// Copyright (c) 2018-2022, The rav1e contributors. All rights reserved
22
//
33
// This source code is subject to the terms of the BSD 2 Clause License and
44
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
@@ -286,12 +286,12 @@ impl<T: Pixel> ContextInner<T> {
286286
gop_output_frameno_start: BTreeMap::new(),
287287
gop_input_frameno_start: BTreeMap::new(),
288288
keyframe_detector: SceneChangeDetector::new(
289-
*enc,
289+
enc.clone(),
290290
CpuFeatureLevel::default(),
291291
lookahead_distance,
292292
seq.clone(),
293293
),
294-
config: Arc::new(*enc),
294+
config: Arc::new(enc.clone()),
295295
seq,
296296
rc_state: RCState::new(
297297
enc.width as i32,

src/api/test.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2018-2021, The rav1e contributors. All rights reserved
1+
// Copyright (c) 2018-2022, The rav1e contributors. All rights reserved
22
//
33
// This source code is subject to the terms of the BSD 2 Clause License and
44
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
@@ -2077,6 +2077,8 @@ fn log_q_exp_overflow() {
20772077
min_quantizer: 64,
20782078
bitrate: 1,
20792079
tune: Tune::Psychovisual,
2080+
#[cfg(feature = "unstable")]
2081+
film_grain_params: None,
20802082
tile_cols: 0,
20812083
tile_rows: 0,
20822084
tiles: 0,
@@ -2152,6 +2154,8 @@ fn guess_frame_subtypes_assert() {
21522154
min_quantizer: 0,
21532155
bitrate: 16384,
21542156
tune: Tune::Psychovisual,
2157+
#[cfg(feature = "unstable")]
2158+
film_grain_params: None,
21552159
tile_cols: 0,
21562160
tile_rows: 0,
21572161
tiles: 0,

0 commit comments

Comments
 (0)