2019-06-01 08:55:47 +02:00
use super ::PLUGIN_NAME ;
2019-06-02 15:31:27 +02:00
use failure ::Error ;
2019-06-04 19:35:39 +02:00
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! {
2019-06-02 10:12:38 +02:00
static ref FLOAT_RANGE : Vec < f32 > = {
2019-06-02 22:44:52 +02:00
[ 0 f32 ; 256 ]
2019-06-02 15:31:27 +02:00
. iter ( )
2019-06-01 15:07:49 +02:00
. 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 ]
2019-06-01 15:07:49 +02:00
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
}
2020-02-19 20:20:45 +01:00
macro_rules ! from_property {
2020-02-19 20:24:08 +01:00
( $prop : expr ) = > {
2020-02-19 20:20:45 +01:00
match $prop {
Property ::Constant ( p ) = > p ,
Property ::Variable = > unreachable! ( ) ,
}
2020-02-19 20:24:08 +01:00
} ;
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-04 19:35:39 +02:00
}
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 ( ) )
{
2019-06-04 19:35:39 +02:00
unsafe {
2020-02-19 20:24:08 +01:00
ptr ::write ( pixel , lut [ ( src_pixel * 255.99 f32 ) as usize ] ) ;
2019-06-04 19:35:39 +02:00
}
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 > {
2020-02-19 20:20:45 +01:00
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 ,
2020-02-19 20:20:45 +01:00
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
} ;
2020-02-19 20:20:45 +01:00
match from_property! ( self . source . info ( ) . format ) . sample_type ( ) {
2019-06-02 22:44:52 +02:00
SampleType ::Integer = > {
2020-02-19 20:20:45 +01:00
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 = > {
2020-03-25 11:07:21 +01:00
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 ( ) )
}
}
2020-03-25 11:07:21 +01:00
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 ( ( ) )
}