Skip to content

Commit eb5b8f8

Browse files
committed
Enable photon noise arg in stable
Add pre-processing denoising Align denoising arrays Autovectorization pass
1 parent 8c260d2 commit eb5b8f8

File tree

13 files changed

+674
-10
lines changed

13 files changed

+674
-10
lines changed

Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ binaries = [
3636
"fern",
3737
"console",
3838
"av-metrics",
39-
"nom",
4039
]
4140
default = ["binaries", "asm", "threading", "signal_support"]
4241
asm = ["nasm-rs", "cc", "regex"]
@@ -100,11 +99,18 @@ wasm-bindgen = { version = "0.2.63", optional = true }
10099
rust_hawktracer = "0.7.0"
101100
arrayref = "0.3.6"
102101
const_fn_assert = "0.1.2"
103-
nom = { version = "7.0.0", optional = true }
102+
# `unreachable!` macro which panics in debug mode
103+
# and optimizes away in release mode
104104
new_debug_unreachable = "1.0.4"
105105
once_cell = "1.13.0"
106106
av1-grain = { version = "0.2.0", features = ["serialize"] }
107107
serde-big-array = { version = "0.4.1", optional = true }
108+
# Used for parsing film grain table files
109+
nom = "7.0.0"
110+
# Used as a data holder during denoising
111+
ndarray = "0.15.4"
112+
# Used for running FFTs during denoising
113+
ndrustfft = "0.3.0"
108114

109115
[dependencies.image]
110116
version = "0.24.3"

clippy.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
too-many-arguments-threshold = 16
22
cognitive-complexity-threshold = 40
33
trivial-copy-size-limit = 16 # 128-bits = 2 64-bit registers
4+
doc-valid-idents = ["DFTTest"]
45
msrv = "1.59"

src/api/config/encoder.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ pub struct EncoderConfig {
8585
pub tune: Tune,
8686
/// Parameters for grain synthesis.
8787
pub film_grain_params: Option<Vec<GrainTableSegment>>,
88+
/// Strength of denoising, 0 = disabled
89+
pub denoise_strength: u8,
8890
/// Number of tiles horizontally. Must be a power of two.
8991
///
9092
/// Overridden by [`tiles`], if present.
@@ -159,6 +161,7 @@ impl EncoderConfig {
159161
bitrate: 0,
160162
tune: Tune::default(),
161163
film_grain_params: None,
164+
denoise_strength: 0,
162165
tile_cols: 0,
163166
tile_rows: 0,
164167
tiles: 0,

src/api/internal.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::api::{
1515
};
1616
use crate::color::ChromaSampling::Cs400;
1717
use crate::cpu_features::CpuFeatureLevel;
18+
use crate::denoise::{DftDenoiser, TB_MIDPOINT};
1819
use crate::dist::get_satd;
1920
use crate::encoder::*;
2021
use crate::frame::*;
@@ -220,7 +221,7 @@ impl<T: Pixel> FrameData<T> {
220221
}
221222
}
222223

223-
type FrameQueue<T> = BTreeMap<u64, Option<Arc<Frame<T>>>>;
224+
pub(crate) type FrameQueue<T> = BTreeMap<u64, Option<Arc<Frame<T>>>>;
224225
type FrameDataQueue<T> = BTreeMap<u64, Option<FrameData<T>>>;
225226

226227
// the fields pub(super) are accessed only by the tests
@@ -248,6 +249,7 @@ pub(crate) struct ContextInner<T: Pixel> {
248249
/// Maps `output_frameno` to `gop_input_frameno_start`.
249250
pub(crate) gop_input_frameno_start: BTreeMap<u64, u64>,
250251
keyframe_detector: SceneChangeDetector<T>,
252+
denoiser: Option<DftDenoiser<T>>,
251253
pub(crate) config: Arc<EncoderConfig>,
252254
seq: Arc<Sequence>,
253255
pub(crate) rc_state: RCState,
@@ -295,6 +297,17 @@ impl<T: Pixel> ContextInner<T> {
295297
lookahead_distance,
296298
seq.clone(),
297299
),
300+
denoiser: if enc.denoise_strength > 0 {
301+
Some(DftDenoiser::new(
302+
enc.denoise_strength as f32 / 10.0,
303+
enc.width,
304+
enc.height,
305+
enc.bit_depth as u8,
306+
enc.chroma_sampling,
307+
))
308+
} else {
309+
None
310+
},
298311
config: Arc::new(enc.clone()),
299312
seq,
300313
rc_state: RCState::new(
@@ -359,6 +372,25 @@ impl<T: Pixel> ContextInner<T> {
359372
self.t35_q.insert(input_frameno, params.t35_metadata);
360373
}
361374

375+
// If denoising is enabled, run it now because we want the entire
376+
// encoding process, including lookahead, to see the denoised frame.
377+
if let Some(ref mut denoiser) = self.denoiser {
378+
loop {
379+
let denoiser_frame = denoiser.cur_frameno;
380+
if (!is_flushing
381+
&& input_frameno >= denoiser_frame + TB_MIDPOINT as u64)
382+
|| (is_flushing && Some(denoiser_frame) < self.limit)
383+
{
384+
self.frame_q.insert(
385+
denoiser_frame,
386+
Some(Arc::new(denoiser.filter_frame(&self.frame_q).unwrap())),
387+
);
388+
} else {
389+
break;
390+
}
391+
}
392+
}
393+
362394
if !self.needs_more_frame_q_lookahead(self.next_lookahead_frame) {
363395
let lookahead_frames = self
364396
.frame_q

src/api/test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,6 +2131,7 @@ fn log_q_exp_overflow() {
21312131
tile_cols: 0,
21322132
tile_rows: 0,
21332133
tiles: 0,
2134+
denoise_strength: 0,
21342135
speed_settings: SpeedSettings {
21352136
multiref: false,
21362137
fast_deblock: true,
@@ -2207,6 +2208,7 @@ fn guess_frame_subtypes_assert() {
22072208
tile_cols: 0,
22082209
tile_rows: 0,
22092210
tiles: 0,
2211+
denoise_strength: 0,
22102212
speed_settings: SpeedSettings {
22112213
multiref: false,
22122214
fast_deblock: true,

src/bin/common.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ pub struct CliOptions {
176176
pub still_picture: bool,
177177
/// Uses grain synthesis to add photon noise to the resulting encode.
178178
/// Takes a strength value 0-64.
179-
#[cfg(feature = "unstable")]
180179
#[clap(
181180
long,
182181
conflicts_with = "film-grain-table",
@@ -185,6 +184,17 @@ pub struct CliOptions {
185184
help_heading = "ENCODE SETTINGS"
186185
)]
187186
pub photon_noise: u8,
187+
/// Enable spatio-temporal denoising, intended to be used with grain synthesis.
188+
/// Takes a strength value 0-50.
189+
///
190+
/// Default strength is 1/2 of photon noise strength,
191+
/// or 4 if a photon noise table is specified.
192+
#[clap(
193+
long,
194+
value_parser = clap::value_parser!(u8).range(0..=50),
195+
help_heading = "ENCODE SETTINGS"
196+
)]
197+
pub denoise: Option<u8>,
188198
/// Uses a film grain table file to apply grain synthesis to the encode.
189199
/// Uses the same table file format as aomenc and svt-av1.
190200
#[clap(
@@ -334,7 +344,6 @@ pub struct ParsedCliOptions {
334344
pub save_config: Option<PathBuf>,
335345
#[cfg(feature = "unstable")]
336346
pub slots: usize,
337-
#[cfg(feature = "unstable")]
338347
pub generate_grain_strength: u8,
339348
}
340349

@@ -482,7 +491,6 @@ pub fn parse_cli() -> Result<ParsedCliOptions, CliError> {
482491
save_config: save_config_path,
483492
#[cfg(feature = "unstable")]
484493
slots,
485-
#[cfg(feature = "unstable")]
486494
generate_grain_strength: matches.photon_noise,
487495
})
488496
}
@@ -676,7 +684,19 @@ fn parse_config(matches: &CliOptions) -> Result<EncoderConfig, CliError> {
676684
.expect("Failed to parse film grain table");
677685
if !table.is_empty() {
678686
cfg.film_grain_params = Some(table);
687+
cfg.denoise_strength = 4;
688+
}
689+
} else if matches.photon_noise > 0 {
690+
cfg.denoise_strength = matches.photon_noise / 2;
691+
// We have to know the video resolution before we can generate a table,
692+
// so we must handle that elsewhere.
693+
}
694+
// A user set denoise strength overrides the defaults above
695+
if let Some(denoise_str) = matches.denoise {
696+
if denoise_str > 50 {
697+
panic!("Denoising strength must be between 0-50");
679698
}
699+
cfg.denoise_strength = denoise_str;
680700
}
681701

682702
if let Some(frame_rate) = matches.frame_rate {

src/bin/rav1e-ch.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,6 @@ fn run() -> Result<(), error::CliError> {
473473
cli.enc.time_base = video_info.time_base;
474474
}
475475

476-
#[cfg(feature = "unstable")]
477476
if cli.generate_grain_strength > 0 && cli.enc.film_grain_params.is_none() {
478477
cli.enc.film_grain_params = Some(vec![generate_photon_noise_params(
479478
0,

src/bin/rav1e.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,6 @@ fn run() -> Result<(), error::CliError> {
456456
cli.enc.time_base = video_info.time_base;
457457
}
458458

459-
#[cfg(feature = "unstable")]
460459
if cli.generate_grain_strength > 0 && cli.enc.film_grain_params.is_none() {
461460
cli.enc.film_grain_params = Some(vec![generate_photon_noise_params(
462461
0,

0 commit comments

Comments
 (0)