use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
use super::config;
use crate::common::{AnyResult, AviUtl2Info, Rational32};
#[derive(Debug, Clone)]
pub struct FilterPluginTable {
pub name: String,
pub label: Option<String>,
pub information: String,
pub filter_type: FilterType,
pub as_object: bool,
pub config_items: Vec<config::FilterConfigItem>,
}
#[derive(Debug, Clone)]
pub enum FilterType {
Video,
Audio,
Both,
}
impl FilterType {
pub(crate) fn to_bits(&self) -> i32 {
match self {
FilterType::Video => aviutl2_sys::filter2::FILTER_PLUGIN_TABLE::FLAG_VIDEO,
FilterType::Audio => aviutl2_sys::filter2::FILTER_PLUGIN_TABLE::FLAG_AUDIO,
FilterType::Both => {
aviutl2_sys::filter2::FILTER_PLUGIN_TABLE::FLAG_VIDEO
| aviutl2_sys::filter2::FILTER_PLUGIN_TABLE::FLAG_AUDIO
}
}
}
}
pub trait FilterPlugin: Send + Sync + Sized {
fn new(info: AviUtl2Info) -> AnyResult<Self>;
fn plugin_info(&self) -> FilterPluginTable;
fn proc_video(
&self,
_config: &[config::FilterConfigItem],
_video: &mut FilterProcVideo,
) -> AnyResult<()> {
anyhow::bail!("proc_video is not implemented");
}
fn proc_audio(
&self,
_config: &[config::FilterConfigItem],
_audio: &mut FilterProcAudio,
) -> AnyResult<()> {
anyhow::bail!("proc_audio is not implemented");
}
}
#[derive(Debug, Clone, Copy)]
pub struct SceneInfo {
pub width: u32,
pub height: u32,
pub frame_rate: Rational32,
pub sample_rate: u32,
}
#[derive(Debug, Clone, Copy)]
pub struct ObjectInfo {
pub id: i64,
pub frame: u32,
pub frame_total: u32,
pub time: f64,
pub time_total: f64,
}
#[derive(Debug, Clone, Copy)]
pub struct VideoObjectInfo {
pub width: u32,
pub height: u32,
}
#[derive(Debug, Clone, Copy)]
pub struct AudioObjectInfo {
pub sample_index: u64,
pub sample_total: u64,
pub sample_num: u32,
pub channel_num: u32,
}
#[derive(
Debug, Default, Clone, Copy, PartialEq, Eq, IntoBytes, FromBytes, Immutable, KnownLayout,
)]
pub struct RgbaPixel {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
#[derive(Debug)]
pub struct FilterProcVideo {
pub scene: SceneInfo,
pub object: ObjectInfo,
pub video_object: VideoObjectInfo,
pub(crate) inner: *const aviutl2_sys::filter2::FILTER_PROC_VIDEO,
}
unsafe impl Send for FilterProcVideo {}
unsafe impl Sync for FilterProcVideo {}
impl FilterProcVideo {
pub fn get_image_data<T>(&mut self, buffer: &mut [T]) -> usize
where
T: Copy + FromBytes + Immutable,
{
if self.video_object.width == 0 || self.video_object.height == 0 {
log::warn!("width or height is 0, perhaps the filter plugin is a custom object");
return 0;
}
assert_eq!(
std::mem::size_of_val(buffer),
(self.video_object.width * self.video_object.height * 4) as usize,
"buffer length as bytes does not match width * height * 4"
);
assert!(
std::mem::align_of::<T>() >= std::mem::align_of::<aviutl2_sys::filter2::PIXEL_RGBA>(),
"buffer alignment is not sufficient"
);
let width = self.video_object.width as usize;
let height = self.video_object.height as usize;
let inner = unsafe { &*self.inner };
unsafe {
(inner.get_image_data)(
buffer.as_mut_ptr() as *mut u8 as *mut aviutl2_sys::filter2::PIXEL_RGBA
)
};
width * height * 4
}
pub fn set_image_data<T: IntoBytes + Immutable>(
&mut self,
data: &[T],
width: u32,
height: u32,
) {
let bytes = &data.as_bytes();
assert_eq!(
bytes.len(),
(width * height * 4) as usize,
"data length does not match width * height * 4"
);
let inner = unsafe { &*self.inner };
unsafe {
(inner.set_image_data)(
bytes.as_ptr() as *const aviutl2_sys::filter2::PIXEL_RGBA,
width as i32,
height as i32,
)
};
}
}
#[derive(Debug)]
pub struct FilterProcAudio {
pub scene: SceneInfo,
pub object: ObjectInfo,
pub audio_object: AudioObjectInfo,
pub(crate) inner: *const aviutl2_sys::filter2::FILTER_PROC_AUDIO,
}
unsafe impl Send for FilterProcAudio {}
unsafe impl Sync for FilterProcAudio {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AudioChannel {
Left,
Right,
Any(i32),
}
impl From<i32> for AudioChannel {
fn from(value: i32) -> Self {
match value {
0 => AudioChannel::Left,
1 => AudioChannel::Right,
v => AudioChannel::Any(v),
}
}
}
impl From<AudioChannel> for i32 {
fn from(value: AudioChannel) -> Self {
match value {
AudioChannel::Left => 0,
AudioChannel::Right => 1,
AudioChannel::Any(v) => v,
}
}
}
impl FilterProcAudio {
pub fn get_sample_data(&mut self, channel: AudioChannel, buffer: &mut [f32]) -> usize {
let sample_num = self.audio_object.sample_num as usize;
assert_eq!(
buffer.len(),
sample_num,
"buffer length does not match sample_num"
);
let inner = unsafe { &*self.inner };
unsafe { (inner.get_sample_data)(buffer.as_mut_ptr(), channel.into()) };
sample_num
}
pub fn set_sample_data(&mut self, channel: AudioChannel, data: &[f32]) {
let sample_num = self.audio_object.sample_num as usize;
assert_eq!(
data.len(),
sample_num,
"data length does not match sample_num"
);
let inner = unsafe { &*self.inner };
unsafe { (inner.set_sample_data)(data.as_ptr(), channel.into()) };
}
}