adaptivegrain/src/mask.rs

199 lines
6.5 KiB
Rust
Raw Normal View History

2019-06-01 08:55:47 +02:00
use super::PLUGIN_NAME;
2019-06-02 15:31:27 +02:00
use failure::Error;
use std::ptr;
2019-06-01 08:55:47 +02:00
use vapoursynth::core::CoreRef;
2019-06-02 15:31:27 +02:00
use vapoursynth::format::ColorFamily;
2019-06-01 08:55:47 +02:00
use vapoursynth::plugins::{Filter, FrameContext};
2019-06-02 22:44:52 +02:00
use vapoursynth::prelude::*;
2019-06-02 15:31:27 +02:00
use vapoursynth::video_info::{Property, VideoInfo};
2019-06-01 08:55:47 +02:00
pub struct Mask<'core> {
pub source: Node<'core>,
pub luma_scaling: f32,
}
lazy_static! {
static ref FLOAT_RANGE: Vec<f32> = {
2019-06-02 22:44:52 +02:00
[0f32; 256]
2019-06-02 15:31:27 +02:00
.iter()
.enumerate()
2020-02-19 20:17:16 +01:00
.map(|(i, _f)| (i as f32) / 256.0)
.collect()
2019-06-01 08:55:47 +02:00
};
}
#[inline]
fn get_mask_value(x: f32, y: f32, luma_scaling: f32) -> f32 {
2019-06-02 15:31:27 +02:00
f32::powf(
1.0 - (x * (1.124 + x * (-9.466 + x * (36.624 + x * (-45.47 + x * 18.188))))),
(y * y) * luma_scaling,
)
2019-06-01 08:55:47 +02:00
}
macro_rules! from_property {
($prop: expr) => {
match $prop {
Property::Constant(p) => p,
Property::Variable => unreachable!(),
}
};
2019-06-01 08:55:47 +02:00
}
2020-02-19 20:17:16 +01:00
macro_rules! int_filter {
($type:ty, $fname:ident) => {
fn $fname(
frame: &mut FrameRefMut,
src_frame: FrameRef,
depth: u8,
average: f32,
luma_scaling: f32,
) {
let max = ((1 << depth) - 1) as f32;
let lut: Vec<$type> = FLOAT_RANGE
.iter()
.map(|x| (get_mask_value(*x, average, luma_scaling) * max) as $type)
.collect();
for row in 0..frame.height(0) {
for (pixel, src_pixel) in frame
.plane_row_mut::<$type>(0, row)
.iter_mut()
.zip(src_frame.plane_row::<$type>(0, row))
{
let i = (src_pixel.clone() >> (depth - 8)) as usize;
unsafe {
ptr::write(pixel, lut[i].clone());
}
}
}
2019-06-02 22:44:52 +02:00
}
2020-02-19 20:17:16 +01:00
};
2019-06-02 22:44:52 +02:00
}
fn filter_for_float(frame: &mut FrameRefMut, src_frame: FrameRef, average: f32, luma_scaling: f32) {
let lut: Vec<f32> = FLOAT_RANGE
.iter()
.map(|x| get_mask_value(*x, average, luma_scaling))
.collect();
for row in 0..frame.height(0) {
for (pixel, src_pixel) in frame
.plane_row_mut::<f32>(0, row)
.iter_mut()
.zip(src_frame.plane_row::<f32>(0, row).iter())
{
unsafe {
ptr::write(pixel, lut[(src_pixel * 255.99f32) as usize]);
}
2019-06-02 22:44:52 +02:00
}
}
}
2019-06-01 08:55:47 +02:00
impl<'core> Filter<'core> for Mask<'core> {
fn video_info(&self, _api: API, _core: CoreRef<'core>) -> Vec<VideoInfo<'core>> {
let info = self.source.info();
let format = match info.format {
2019-06-02 15:31:27 +02:00
Property::Variable => unreachable!(),
Property::Constant(format) => format,
2019-06-01 08:55:47 +02:00
};
vec![VideoInfo {
2019-06-02 15:31:27 +02:00
format: Property::Constant(
_core
.register_format(
ColorFamily::Gray,
format.sample_type(),
format.bits_per_sample(),
0,
0,
)
.unwrap(),
),
2019-06-01 08:55:47 +02:00
flags: info.flags,
framerate: info.framerate,
num_frames: info.num_frames,
resolution: info.resolution,
}]
}
fn get_frame_initial(
&self,
_api: API,
_core: CoreRef<'core>,
context: FrameContext,
n: usize,
) -> Result<Option<FrameRef<'core>>, Error> {
self.source.request_frame_filter(context, n);
Ok(None)
}
fn get_frame(
&self,
_api: API,
core: CoreRef<'core>,
context: FrameContext,
n: usize,
) -> Result<FrameRef<'core>, Error> {
let new_format = from_property!(self.video_info(_api, core)[0].format);
2019-06-01 08:55:47 +02:00
let mut frame = unsafe {
FrameRefMut::new_uninitialized(
2019-06-02 15:31:27 +02:00
core,
None,
new_format,
from_property!(self.source.info().resolution),
2019-06-02 15:31:27 +02:00
)
2019-06-01 08:55:47 +02:00
};
2019-06-02 15:31:27 +02:00
let src_frame = self.source.get_frame_filter(context, n).ok_or_else(|| {
format_err!("Could not retrieve source frame. This shouldn’t happen.")
})?;
2019-06-01 08:55:47 +02:00
let average = match src_frame.props().get::<f64>("PlaneStatsAverage") {
Ok(average) => average as f32,
2019-06-02 22:44:52 +02:00
Err(_) => bail!(format!(
2019-06-02 15:31:27 +02:00
"{}: you need to run std.PlaneStats on the clip before calling this function.",
PLUGIN_NAME
)),
2019-06-01 08:55:47 +02:00
};
match from_property!(self.source.info().format).sample_type() {
2019-06-02 22:44:52 +02:00
SampleType::Integer => {
let depth = from_property!(self.source.info().format).bits_per_sample();
2019-06-02 22:44:52 +02:00
match depth {
2020-02-19 20:17:16 +01:00
0..=8 => {
int_filter!(u8, filter_8bit);
filter_8bit(&mut frame, src_frame, depth, average, self.luma_scaling)
}
9..=16 => {
int_filter!(u16, filter_16bit);
filter_16bit(&mut frame, src_frame, depth, average, self.luma_scaling)
}
17..=32 => {
int_filter!(u32, filter_32bit);
filter_32bit(&mut frame, src_frame, depth, average, self.luma_scaling)
}
2019-06-02 22:44:52 +02:00
_ => bail!(format!(
"{}: input depth {} not supported",
PLUGIN_NAME, depth
)),
}
}
SampleType::Float => {
if let Err(e) = verify_input_range(&src_frame.props()) {
bail!(e);
}
2019-06-02 22:44:52 +02:00
filter_for_float(&mut frame, src_frame, average, self.luma_scaling);
2019-06-01 08:55:47 +02:00
}
}
Ok(frame.into())
}
}
fn verify_input_range<'a>(props: &vapoursynth::map::MapRef<'a, 'a>) -> Result<(), String> {
let max = props.get::<f64>("PlaneStatsMax").unwrap_or(1.0);
let min = props.get::<f64>("PlaneStatsMin").unwrap_or(0.0);
if min < 0.0 || max > 1.0 {
return Err(format!(
"{}: found invalid input. Some pixels are outside of the valid range.
You probably used a filter that operates on limited range without clipping properly, e.g. edgefixer, before converting to float.
This can be fixed by clipping all pixels to (0, 1) with Expr or converting to an integer format.", PLUGIN_NAME
));
}
Ok(())
}