#[macro_use] extern crate failure; #[macro_use] extern crate vapoursynth; use vapoursynth::core::CoreRef; use vapoursynth::map::Map; use vapoursynth::video_info::VideoInfo; use failure::Error; use vapoursynth::node::Node; use vapoursynth::plugins::{Filter, FilterArgument, FrameContext, Metadata}; use vapoursynth::api::API; use vapoursynth::frame::{FrameRef, FrameRefMut}; const PLUGIN_NAME: &str = "adaptivegrain"; const PLUGIN_IDENTIFIER: &str = "moe.kageru.adaptivegrain"; struct AdaptiveGrain<'core> { source: Node<'core> } impl<'core> Filter<'core> for AdaptiveGrain<'core> { fn video_info(&self, _api: API, _core: CoreRef<'core>) -> Vec> { vec![self.source.info()] } fn get_frame_initial( &self, _api: API, _core: CoreRef<'core>, context: FrameContext, n: usize, ) -> Result>, Error> { self.source.request_frame_filter(context, n); Ok(None) } fn get_frame( &self, _api: API, core: CoreRef<'core>, context: FrameContext, n: usize, ) -> Result, Error> { let frame = self.source .get_frame_filter(context, n) .ok_or_else(|| format_err!("Could not retrieve source frame. This shouldn’t happen."))?; let average = match frame.props().get::("PlaneStatsAverage") { Ok(average) => (average * 256.0) as u8, Err(_) => panic!(PLUGIN_NAME.to_owned() + ": You need to run std.PlaneStats on the clip before calling this function.") }; let mut frame = FrameRefMut::copy_of(core, &frame); for plane in 0..frame.format().plane_count() { for row in 0..frame.height(plane) { for pixel in frame.plane_row_mut::(plane, row) { *pixel = average; } } } Ok(frame.into()) } } make_filter_function! { AdaptiveGrainFunction, "AdaptiveGrain" fn create_adaptivegrain<'core>( _api: API, _core: CoreRef<'core>, clip: Node<'core>, ) -> Result + 'core>>, Error> { Ok(Some(Box::new(AdaptiveGrain { source: clip }))) } } export_vapoursynth_plugin! { Metadata { identifier: PLUGIN_IDENTIFIER, namespace: "adg", name: "Adaptive grain", read_only: false, }, [ AdaptiveGrainFunction::new() ] } #[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } }