Skip to content

Commit

Permalink
Integrate AV-Metrics for calculation of metrics
Browse files Browse the repository at this point in the history
For showing metrics in CLI use --metrics for showing all metrics and use --psnr for showing PNSR.

This commit introduces:
- Frame Metrics function to calculate
PSNR, PSNR-HVS, SSIM, MS-SSIM, CIEDE2000.
- Quality Metrics Structure to store all the calculated values
- Adding METRICS as an argument
- Updates --psnr calculation based on av-metrics
- Calculated metrics in a neat way
- Introduce metrics_cli as an additional parameter for
process_frame as parse_cli is an expensive function to be made in
encode_loop, to make it more efficient we have moved metrics_cli
enum as an argument to process_frame and making the calculation
in do_encode function.
  • Loading branch information
vibhoothi authored Mar 29, 2020
1 parent bde0cfc commit 81b25d8
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 150 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ binaries = [
"fern",
"console",
"better-panic",
"av-metrics",
]
default = ["binaries", "asm", "signal_support"]
asm = ["nasm-rs", "cc"]
Expand Down Expand Up @@ -69,6 +70,7 @@ aom-sys = { version = "0.1.3", optional = true }
scan_fmt = { version = "0.2.3", optional = true, default-features = false }
ivf = { version = "0.1", path = "ivf/", optional = true }
v_frame = { version = "0.1", path = "v_frame/" }
av-metrics = { version = "0.4", optional = true }
rayon = "1.0"
toml = { version = "0.5", optional = true }
arrayvec = "0.5"
Expand Down Expand Up @@ -104,6 +106,9 @@ version = "0.1.7"
optional = true
features = ["parallel"]

[replace]
"v_frame:0.1.0" = { path = "v_frame/" }

[target.'cfg(unix)'.dependencies]
signal-hook = { version = "0.1.9", optional = true }

Expand Down
5 changes: 0 additions & 5 deletions src/api/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,6 @@ pub struct EncoderConfig {
pub tiles: usize,
/// Number of frames to read ahead for the RDO lookahead computation.
pub rdo_lookahead_frames: usize,
/// If enabled, computes the PSNR values and stores them in [`Packet`].
///
/// [`Packet`]: struct.Packet.html#structfield.psnr
pub show_psnr: bool,

/// Settings which affect the enconding speed vs. quality trade-off.
pub speed_settings: SpeedSettings,
Expand Down Expand Up @@ -171,7 +167,6 @@ impl EncoderConfig {
tiles: 0,
rdo_lookahead_frames: 40,
speed_settings: SpeedSettings::from_preset(speed),
show_psnr: false,
}
}

Expand Down
38 changes: 2 additions & 36 deletions src/api/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use crate::dist::get_satd;
use crate::encoder::*;
use crate::frame::*;
use crate::hawktracer::*;
use crate::metrics::calculate_frame_psnr;
use crate::partition::*;
use crate::rate::RCState;
use crate::rate::FRAME_NSUBTYPES;
Expand Down Expand Up @@ -351,18 +350,6 @@ impl<T: Pixel> ContextInner<T> {
Ok(())
}

fn get_frame(&self, input_frameno: u64) -> Arc<Frame<T>> {
// Clones only the arc, so low cost overhead
self
.frame_q
.get(&input_frameno)
.as_ref()
.unwrap()
.as_ref()
.unwrap()
.clone()
}

/// Indicates whether more frames need to be read into the frame queue
/// in order for frame queue lookahead to be full.
fn needs_more_frame_q_lookahead(&self, input_frameno: u64) -> bool {
Expand Down Expand Up @@ -1101,15 +1088,13 @@ impl<T: Pixel> ContextInner<T> {

let input_frameno = frame_data.fi.input_frameno;
let frame_type = frame_data.fi.frame_type;
let bit_depth = frame_data.fi.sequence.bit_depth;
let qp = frame_data.fi.base_q_idx;
let enc_stats = frame_data.fs.enc_stats.clone();
self.finalize_packet(
rec,
source,
input_frameno,
frame_type,
bit_depth,
qp,
enc_stats,
)
Expand Down Expand Up @@ -1222,14 +1207,12 @@ impl<T: Pixel> ContextInner<T> {
if fi.show_frame {
let input_frameno = fi.input_frameno;
let frame_type = fi.frame_type;
let bit_depth = fi.sequence.bit_depth;
let qp = fi.base_q_idx;
self.finalize_packet(
rec,
source,
input_frameno,
frame_type,
bit_depth,
qp,
enc_stats,
)
Expand Down Expand Up @@ -1283,7 +1266,7 @@ impl<T: Pixel> ContextInner<T> {

fn finalize_packet(
&mut self, rec: Option<Arc<Frame<T>>>, source: Option<Arc<Frame<T>>>,
input_frameno: u64, frame_type: FrameType, bit_depth: usize, qp: u8,
input_frameno: u64, frame_type: FrameType, qp: u8,
enc_stats: EncoderStats,
) -> Result<Packet<T>, EncoderStatus> {
let data = self.packet_data.clone();
Expand All @@ -1292,25 +1275,8 @@ impl<T: Pixel> ContextInner<T> {
return Err(EncoderStatus::Failure);
}

let mut psnr = None;
if self.config.show_psnr {
if let Some(ref rec) = rec {
let original_frame = self.get_frame(input_frameno);
psnr = Some(calculate_frame_psnr(&*original_frame, rec, bit_depth));
}
}

self.frames_processed += 1;
Ok(Packet {
data,
rec,
source,
input_frameno,
frame_type,
psnr,
qp,
enc_stats,
})
Ok(Packet { data, rec, source, input_frameno, frame_type, qp, enc_stats })
}

fn garbage_collect(&mut self, cur_input_frameno: u64) {
Expand Down
2 changes: 0 additions & 2 deletions src/api/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1710,7 +1710,6 @@ fn log_q_exp_overflow() {
non_square_partition: false,
..Default::default()
},
show_psnr: false,
},
threads: 1,
};
Expand Down Expand Up @@ -1778,7 +1777,6 @@ fn guess_frame_subtypes_assert() {
non_square_partition: false,
..Default::default()
},
show_psnr: false,
},
threads: 1,
};
Expand Down
2 changes: 0 additions & 2 deletions src/api/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,6 @@ pub struct Packet<T: Pixel> {
pub input_frameno: u64,
/// Type of the shown frame.
pub frame_type: FrameType,
/// PSNR for Y, U, and V planes for the shown frame.
pub psnr: Option<(f64, f64, f64)>,
/// QP selected for the frame.
pub qp: u8,
/// Block-level encoding stats for the frame
Expand Down
19 changes: 18 additions & 1 deletion src/bin/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use crate::error::*;
use crate::muxer::{create_muxer, Muxer};
use crate::stats::MetricsEnabled;
use crate::{ColorPrimaries, MatrixCoefficients, TransferCharacteristics};
use clap::{App, AppSettings, Arg, ArgMatches, Shell, SubCommand};
use rav1e::prelude::*;
Expand Down Expand Up @@ -42,6 +43,7 @@ pub struct CliOptions {
pub verbose: Verbose,
pub benchmark: bool,
pub threads: usize,
pub metrics_enabled: MetricsEnabled,
pub pass1file_name: Option<String>,
pub pass2file_name: Option<String>,
pub save_config: Option<String>,
Expand Down Expand Up @@ -74,6 +76,8 @@ fn build_speed_long_help() -> String {
}

#[allow(unused_mut)]
/// Only call this once at the start of the app,
/// otherwise bad things will happen.
pub fn parse_cli() -> Result<CliOptions, CliError> {
let ver_short = version::short();
let ver_long = version::full();
Expand Down Expand Up @@ -340,6 +344,11 @@ pub fn parse_cli() -> Result<CliOptions, CliError> {
.help("Calculate and display PSNR metrics")
.long("psnr")
)
.arg(
Arg::with_name("METRICS")
.help("Calulate and display several metrics including PSNR, SSIM, CIEDE2000 etc")
.long("metrics")
)
.arg(
Arg::with_name("RECONSTRUCTION")
.help("Outputs a Y4M file containing the output from the decoder")
Expand Down Expand Up @@ -448,6 +457,14 @@ pub fn parse_cli() -> Result<CliOptions, CliError> {
Verbose::Normal
};

let metrics_enabled = if matches.is_present("METRICS") {
MetricsEnabled::All
} else if matches.is_present("PSNR") {
MetricsEnabled::Psnr
} else {
MetricsEnabled::None
};

Ok(CliOptions {
io,
enc,
Expand All @@ -456,6 +473,7 @@ pub fn parse_cli() -> Result<CliOptions, CliError> {
// if a parameter has a default value.
color_range_specified: matches.occurrences_of("PIXEL_RANGE") > 0,
override_time_base: matches.is_present("FRAME_RATE"),
metrics_enabled,
skip: matches.value_of("SKIP").unwrap().parse().unwrap(),
benchmark: matches.is_present("BENCHMARK"),
verbose,
Expand Down Expand Up @@ -615,7 +633,6 @@ fn parse_config(matches: &ArgMatches<'_>) -> Result<EncoderConfig, CliError> {
.map(|reservior_frame_delay| reservior_frame_delay.parse().unwrap());
cfg.rdo_lookahead_frames =
matches.value_of("RDO_LOOKAHEAD_FRAMES").unwrap_or("40").parse().unwrap();
cfg.show_psnr = matches.is_present("PSNR");
cfg.tune = matches.value_of("TUNE").unwrap().parse().unwrap();

if cfg.tune == Tune::Psychovisual {
Expand Down
14 changes: 12 additions & 2 deletions src/bin/rav1e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ fn process_frame<T: Pixel, D: Decoder>(
pass1file: Option<&mut File>, pass2file: Option<&mut File>,
buffer: &mut [u8], buf_pos: &mut usize,
mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>,
metrics_cli: MetricsEnabled,
) -> Result<Option<Vec<FrameSummary>>, CliError> {
let y4m_details = source.input.get_video_details();
let mut frame_summaries = Vec::new();
Expand Down Expand Up @@ -155,7 +156,12 @@ fn process_frame<T: Pixel, D: Decoder>(
{
write_y4m_frame(y4m_enc_uw, rec, y4m_details);
}
frame_summaries.push(pkt.into());
frame_summaries.push(build_frame_summary(
pkt,
y4m_details.bit_depth,
y4m_details.chroma_sampling,
metrics_cli,
));
}
Err(EncoderStatus::NeedMoreData) => {
source.read_frame(ctx, y4m_details);
Expand Down Expand Up @@ -197,6 +203,7 @@ fn do_encode<T: Pixel, D: Decoder>(
output: &mut dyn Muxer, source: &mut Source<D>,
pass1file_name: Option<&String>, pass2file_name: Option<&String>,
mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>,
metrics_enabled: MetricsEnabled,
) -> Result<(), CliError> {
let mut ctx: Context<T> =
cfg.new_context().map_err(|e| e.context("Invalid encoder settings"))?;
Expand Down Expand Up @@ -224,6 +231,7 @@ fn do_encode<T: Pixel, D: Decoder>(
&mut buffer,
&mut buf_pos,
y4m_enc.as_mut(),
metrics_enabled,
)? {
if verbose != Verbose::Quiet {
for frame in frame_info {
Expand Down Expand Up @@ -419,7 +427,7 @@ fn run() -> Result<(), error::CliError> {
let progress = ProgressInfo::new(
Rational { num: video_info.time_base.den, den: video_info.time_base.num },
if cli.limit == 0 { None } else { Some(cli.limit) },
cfg.enc.show_psnr,
cli.metrics_enabled,
);

for _ in 0..cli.skip {
Expand Down Expand Up @@ -467,6 +475,7 @@ fn run() -> Result<(), error::CliError> {
cli.pass1file_name.as_ref(),
cli.pass2file_name.as_ref(),
y4m_enc,
cli.metrics_enabled,
)?
} else {
do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
Expand All @@ -478,6 +487,7 @@ fn run() -> Result<(), error::CliError> {
cli.pass1file_name.as_ref(),
cli.pass2file_name.as_ref(),
y4m_enc,
cli.metrics_enabled,
)?
}
if cli.benchmark {
Expand Down
Loading

0 comments on commit 81b25d8

Please sign in to comment.