use anyhow::Result;
use crate::api::API;
use crate::core::CoreRef;
use crate::frame::FrameRef;
use crate::function::Function;
use crate::map::{self, Map, Value, ValueIter};
use crate::node::Node;
use crate::video_info::VideoInfo;
mod frame_context;
pub use self::frame_context::FrameContext;
pub mod ffi;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Metadata {
pub identifier: &'static str,
pub namespace: &'static str,
pub name: &'static str,
pub read_only: bool,
}
pub trait FilterFunction: Send + Sync {
fn name(&self) -> &str;
fn args(&self) -> &str;
fn create<'core>(
&self,
api: API,
core: CoreRef<'core>,
args: &Map<'core>,
) -> Result<Option<Box<dyn Filter<'core> + 'core>>>;
}
pub trait Filter<'core>: Send + Sync {
fn video_info(&self, api: API, core: CoreRef<'core>) -> Vec<VideoInfo<'core>>;
fn get_frame_initial(
&self,
api: API,
core: CoreRef<'core>,
context: FrameContext,
n: usize,
) -> Result<Option<FrameRef<'core>>>;
fn get_frame(
&self,
api: API,
core: CoreRef<'core>,
context: FrameContext,
n: usize,
) -> Result<FrameRef<'core>>;
}
pub trait FilterArgument<'map, 'elem: 'map>: Value<'map, 'elem> + private::Sealed {
fn type_name() -> &'static str;
}
pub trait FilterParameter<'map, 'elem: 'map>: private::Sealed {
type Argument: FilterArgument<'map, 'elem>;
fn is_array() -> bool;
fn is_optional() -> bool;
fn get_from_map(map: &'map Map<'elem>, key: &str) -> Self;
}
impl<'map, 'elem: 'map> FilterArgument<'map, 'elem> for i64 {
#[inline]
fn type_name() -> &'static str {
"int"
}
}
impl<'map, 'elem: 'map> FilterArgument<'map, 'elem> for f64 {
#[inline]
fn type_name() -> &'static str {
"float"
}
}
impl<'map, 'elem: 'map> FilterArgument<'map, 'elem> for &'map [u8] {
#[inline]
fn type_name() -> &'static str {
"data"
}
}
impl<'map, 'elem: 'map> FilterArgument<'map, 'elem> for Node<'elem> {
#[inline]
fn type_name() -> &'static str {
"vnode"
}
}
impl<'map, 'elem: 'map> FilterArgument<'map, 'elem> for FrameRef<'elem> {
#[inline]
fn type_name() -> &'static str {
"vframe"
}
}
impl<'map, 'elem: 'map> FilterArgument<'map, 'elem> for Function<'elem> {
#[inline]
fn type_name() -> &'static str {
"func"
}
}
impl<'map, 'elem: 'map, T> FilterParameter<'map, 'elem> for T
where
T: FilterArgument<'map, 'elem>,
{
type Argument = Self;
#[inline]
fn is_array() -> bool {
false
}
#[inline]
fn is_optional() -> bool {
false
}
#[inline]
fn get_from_map(map: &'map Map<'elem>, key: &str) -> Self {
Self::get_from_map(map, key).unwrap()
}
}
impl<'map, 'elem: 'map, T> FilterParameter<'map, 'elem> for Option<T>
where
T: FilterArgument<'map, 'elem>,
{
type Argument = T;
#[inline]
fn is_array() -> bool {
false
}
#[inline]
fn is_optional() -> bool {
true
}
#[inline]
fn get_from_map(map: &'map Map<'elem>, key: &str) -> Self {
match <Self::Argument as Value>::get_from_map(map, key) {
Ok(x) => Some(x),
Err(map::Error::KeyNotFound) => None,
_ => unreachable!(),
}
}
}
impl<'map, 'elem: 'map, T> FilterParameter<'map, 'elem> for ValueIter<'map, 'elem, T>
where
T: FilterArgument<'map, 'elem>,
{
type Argument = T;
#[inline]
fn is_array() -> bool {
true
}
#[inline]
fn is_optional() -> bool {
false
}
#[inline]
fn get_from_map(map: &'map Map<'elem>, key: &str) -> Self {
<Self::Argument>::get_iter_from_map(map, key).unwrap()
}
}
impl<'map, 'elem: 'map, T> FilterParameter<'map, 'elem> for Option<ValueIter<'map, 'elem, T>>
where
T: FilterArgument<'map, 'elem>,
{
type Argument = T;
#[inline]
fn is_array() -> bool {
true
}
#[inline]
fn is_optional() -> bool {
true
}
#[inline]
fn get_from_map(map: &'map Map<'elem>, key: &str) -> Self {
match <Self::Argument as Value>::get_iter_from_map(map, key) {
Ok(x) => Some(x),
Err(map::Error::KeyNotFound) => None,
_ => unreachable!(),
}
}
}
mod private {
use super::{FilterArgument, FrameRef, Function, Node, ValueIter};
pub trait Sealed {}
impl Sealed for i64 {}
impl Sealed for f64 {}
impl Sealed for &[u8] {}
impl<'elem> Sealed for Node<'elem> {}
impl<'elem> Sealed for FrameRef<'elem> {}
impl<'elem> Sealed for Function<'elem> {}
impl<'map, 'elem: 'map, T> Sealed for Option<T> where T: FilterArgument<'map, 'elem> {}
impl<'map, 'elem: 'map, T> Sealed for ValueIter<'map, 'elem, T> where T: FilterArgument<'map, 'elem> {}
impl<'map, 'elem: 'map, T> Sealed for Option<ValueIter<'map, 'elem, T>> where
T: FilterArgument<'map, 'elem>
{
}
}
#[macro_export]
macro_rules! make_filter_function {
(
$struct_name:ident, $function_name:tt
$(#[$attr:meta])*
fn $create_fn_name:ident<$lifetime:tt>(
$api_arg_name:ident : $api_arg_type:ty,
$core_arg_name:ident : $core_arg_type:ty,
$($arg_name:ident : $arg_type:ty),* $(,)*
) -> $return_type:ty {
$($body:tt)*
}
) => (
struct $struct_name {
args: String,
}
impl $struct_name {
fn new<'core>() -> Self {
let mut args = String::new();
$(
// Don't use format!() for better constant propagation.
args += stringify!($arg_name); // TODO: allow using a different name.
args += ":";
args
+= <<$arg_type as $crate::plugins::FilterParameter>::Argument>::type_name();
if <$arg_type as $crate::plugins::FilterParameter>::is_array() {
args += "[]";
}
if <$arg_type as $crate::plugins::FilterParameter>::is_optional() {
args += ":opt";
}
args += ";";
)*
Self { args }
}
}
impl $crate::plugins::FilterFunction for $struct_name {
#[inline]
fn name(&self) -> &str {
$function_name
}
#[inline]
fn args(&self) -> &str {
&self.args
}
#[inline]
fn create<'core>(
&self,
api: $crate::prelude::API,
core: $crate::core::CoreRef<'core>,
args: &$crate::prelude::Map<'core>,
) -> $crate::anyhow::Result<Option<Box<dyn $crate::plugins::Filter<'core> + 'core>>> {
$create_fn_name(
api,
core,
$(
<$arg_type as $crate::plugins::FilterParameter>::get_from_map(
args,
stringify!($arg_name),
)
),*
)
}
}
$(#[$attr])*
fn $create_fn_name<$lifetime>(
$api_arg_name : $api_arg_type,
$core_arg_name : $core_arg_type,
$($arg_name : $arg_type),*
) -> $return_type {
$($body)*
}
)
}