1use parking_lot::lock_api::RawRwLock;
2use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
3
4use super::{ErasedFilterConfigData, config};
5use crate::common::{AnyResult, AviUtl2Info, Rational32};
6
7#[derive(Debug, Clone)]
9pub struct FilterPluginTable {
10 pub name: String,
12 pub label: Option<String>,
15 pub information: String,
18
19 pub flags: FilterPluginFlags,
21
22 pub config_items: Vec<config::FilterConfigItem>,
24}
25
26define_bitflag! {
27 #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
33 #[non_exhaustive]
34 pub struct FilterPluginFlags: i32 {
35 video: aviutl2_sys::filter2::FILTER_PLUGIN_TABLE::FLAG_VIDEO,
37
38 audio: aviutl2_sys::filter2::FILTER_PLUGIN_TABLE::FLAG_AUDIO,
40
41 as_object: aviutl2_sys::filter2::FILTER_PLUGIN_TABLE::FLAG_INPUT,
45
46 as_filter: aviutl2_sys::filter2::FILTER_PLUGIN_TABLE::FLAG_FILTER,
49 }
50}
51
52pub trait FilterPlugin: Send + Sync + Sized {
55 fn new(info: AviUtl2Info) -> AnyResult<Self>;
57
58 fn plugin_info(&self) -> FilterPluginTable;
60
61 fn proc_video(
67 &self,
68 _config: &[config::FilterConfigItem],
69 _video: &mut FilterProcVideo,
70 ) -> AnyResult<()> {
71 anyhow::bail!("proc_video is not implemented");
72 }
73
74 fn proc_audio(
76 &self,
77 _config: &[config::FilterConfigItem],
78 _audio: &mut FilterProcAudio,
79 ) -> AnyResult<()> {
80 anyhow::bail!("proc_audio is not implemented");
81 }
82
83 fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R
89 where
90 Self: crate::filter::__bridge::FilterSingleton,
91 {
92 <Self as crate::filter::__bridge::FilterSingleton>::with_instance(f)
93 }
94
95 fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R
101 where
102 Self: crate::filter::__bridge::FilterSingleton,
103 {
104 <Self as crate::filter::__bridge::FilterSingleton>::with_instance_mut(f)
105 }
106}
107
108#[derive(Debug, Clone, Copy)]
110pub struct SceneInfo {
111 pub width: u32,
113 pub height: u32,
115 pub frame_rate: Rational32,
117 pub sample_rate: u32,
119}
120
121#[derive(Debug, Clone, Copy)]
123pub struct ObjectInfo {
124 pub id: i64,
127 pub effect_id: i64,
130 pub frame: u32,
132 pub frame_total: u32,
134 pub time: f64,
136 pub time_total: f64,
138}
139
140#[derive(Debug, Clone, Copy)]
142pub struct VideoObjectInfo {
143 pub width: u32,
145 pub height: u32,
147}
148
149#[derive(Debug, Clone, Copy)]
151pub struct AudioObjectInfo {
152 pub sample_index: u64,
154 pub sample_total: u64,
156 pub sample_num: u32,
158 pub channel_num: u32,
161}
162
163#[derive(
165 Debug, Default, Clone, Copy, PartialEq, Eq, IntoBytes, FromBytes, Immutable, KnownLayout,
166)]
167pub struct RgbaPixel {
168 pub r: u8,
170 pub g: u8,
172 pub b: u8,
174 pub a: u8,
176}
177
178#[derive(Debug)]
180pub struct FilterProcVideo {
181 pub scene: SceneInfo,
183 pub object: ObjectInfo,
185 pub video_object: VideoObjectInfo,
187
188 pub(crate) inner: *const aviutl2_sys::filter2::FILTER_PROC_VIDEO,
189}
190unsafe impl Send for FilterProcVideo {}
191unsafe impl Sync for FilterProcVideo {}
192
193impl FilterProcVideo {
194 pub fn get_image_data<T>(&mut self, buffer: &mut [T]) -> usize
207 where
208 T: Copy + FromBytes + Immutable,
209 {
210 if self.video_object.width == 0 || self.video_object.height == 0 {
211 log::warn!("width or height is 0, perhaps the filter plugin is a custom object");
212 return 0;
213 }
214 assert_eq!(
215 std::mem::size_of_val(buffer),
216 (self.video_object.width * self.video_object.height * 4) as usize,
217 "buffer length as bytes does not match width * height * 4"
218 );
219 assert!(
220 std::mem::align_of::<T>() >= std::mem::align_of::<aviutl2_sys::filter2::PIXEL_RGBA>(),
221 "buffer alignment is not sufficient"
222 );
223 let width = self.video_object.width as usize;
224 let height = self.video_object.height as usize;
225 let inner = unsafe { &*self.inner };
226 unsafe {
227 (inner.get_image_data)(
228 buffer.as_mut_ptr() as *mut u8 as *mut aviutl2_sys::filter2::PIXEL_RGBA
229 )
230 };
231
232 width * height * 4
233 }
234
235 pub fn set_image_data<T: IntoBytes + Immutable>(
241 &mut self,
242 data: &[T],
243 width: u32,
244 height: u32,
245 ) {
246 let bytes = &data.as_bytes();
247 assert_eq!(
248 bytes.len(),
249 (width * height * 4) as usize,
250 "data length does not match width * height * 4"
251 );
252 let inner = unsafe { &*self.inner };
253 unsafe {
254 (inner.set_image_data)(
255 bytes.as_ptr() as *const aviutl2_sys::filter2::PIXEL_RGBA,
256 width as i32,
257 height as i32,
258 )
259 };
260 }
261
262 pub fn get_image_texture2d(&mut self) -> *mut std::ffi::c_void {
268 let inner = unsafe { &*self.inner };
269 unsafe { (inner.get_image_texture2d)() }
270 }
271
272 pub fn get_framebuffer_texture2d(&mut self) -> *mut std::ffi::c_void {
278 let inner = unsafe { &*self.inner };
279 unsafe { (inner.get_framebuffer_texture2d)() }
280 }
281}
282
283#[derive(Debug)]
285pub struct FilterProcAudio {
286 pub scene: SceneInfo,
288 pub object: ObjectInfo,
290 pub audio_object: AudioObjectInfo,
292
293 pub(crate) inner: *const aviutl2_sys::filter2::FILTER_PROC_AUDIO,
294}
295
296unsafe impl Send for FilterProcAudio {}
297unsafe impl Sync for FilterProcAudio {}
298
299#[derive(Debug, Clone, Copy, PartialEq, Eq)]
300pub enum AudioChannel {
301 Left,
302 Right,
303 Any(i32),
304}
305impl From<i32> for AudioChannel {
306 fn from(value: i32) -> Self {
307 match value {
308 0 => AudioChannel::Left,
309 1 => AudioChannel::Right,
310 v => AudioChannel::Any(v),
311 }
312 }
313}
314impl From<AudioChannel> for i32 {
315 fn from(value: AudioChannel) -> Self {
316 match value {
317 AudioChannel::Left => 0,
318 AudioChannel::Right => 1,
319 AudioChannel::Any(v) => v,
320 }
321 }
322}
323
324impl FilterProcAudio {
325 pub fn get_sample_data(&mut self, channel: AudioChannel, buffer: &mut [f32]) -> usize {
332 let sample_num = self.audio_object.sample_num as usize;
333 assert_eq!(
334 buffer.len(),
335 sample_num,
336 "buffer length does not match sample_num"
337 );
338 let inner = unsafe { &*self.inner };
339 unsafe { (inner.get_sample_data)(buffer.as_mut_ptr(), channel.into()) };
340 sample_num
341 }
342
343 pub fn set_sample_data(&mut self, channel: AudioChannel, data: &[f32]) {
350 let sample_num = self.audio_object.sample_num as usize;
351 assert_eq!(
352 data.len(),
353 sample_num,
354 "data length does not match sample_num"
355 );
356 let inner = unsafe { &*self.inner };
357 unsafe { (inner.set_sample_data)(data.as_ptr(), channel.into()) };
358 }
359}
360
361#[derive(Debug)]
364pub struct FilterConfigDataHandle<T: Copy> {
365 pub(crate) inner: *mut T,
366}
367
368unsafe impl<T: Send + Sync + Copy> Send for FilterConfigDataHandle<T> {}
369unsafe impl<T: Send + Sync + Copy> Sync for FilterConfigDataHandle<T> {}
370
371static HANDLES: std::sync::LazyLock<dashmap::DashMap<usize, parking_lot::RawRwLock>> =
372 std::sync::LazyLock::new(dashmap::DashMap::new);
373static OWNED_REFERENCES: std::sync::LazyLock<
374 std::sync::Arc<dashmap::DashMap<usize, std::sync::atomic::AtomicUsize>>,
375> = std::sync::LazyLock::new(|| std::sync::Arc::new(dashmap::DashMap::new()));
376
377impl<T: Copy> Clone for FilterConfigDataHandle<T> {
378 fn clone(&self) -> Self {
379 if !self.inner.is_null() {
380 let addr = self.inner as usize;
381 if OWNED_REFERENCES.contains_key(&addr) {
382 let entry = OWNED_REFERENCES.get(&addr).unwrap();
383 entry.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
384 }
385 }
386 Self { inner: self.inner }
387 }
388}
389impl<T: Copy> Drop for FilterConfigDataHandle<T> {
390 fn drop(&mut self) {
391 if !self.inner.is_null() {
392 let addr = self.inner as usize;
393 if let Some(entry) = OWNED_REFERENCES.get(&addr) {
394 let prev = entry.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
395 if prev == 1 {
396 unsafe {
397 let _boxed = Box::from_raw(self.inner);
398 }
399 drop(entry);
401 OWNED_REFERENCES.remove(&addr);
402 }
403 }
404 }
405 }
406}
407
408impl<T: Copy> FilterConfigDataHandle<T> {
409 #[doc(hidden)]
410 pub fn __generics_default_value() -> T
411 where
412 T: Default,
413 {
414 T::default()
415 }
416
417 #[doc(hidden)]
418 pub fn __from_erased(erased: &ErasedFilterConfigData) -> Self {
419 Self {
420 inner: erased.value.map_or(std::ptr::null_mut(), |v| v.as_ptr()) as *mut T,
421 }
422 }
423
424 #[doc(hidden)]
425 pub fn __new_owned(value: T) -> Self {
426 let boxed = Box::new(value);
427 let pointer = Box::into_raw(boxed);
428 let addr = pointer as *mut () as usize;
429 OWNED_REFERENCES.insert(addr, std::sync::atomic::AtomicUsize::new(1));
430 Self { inner: pointer }
431 }
432
433 pub fn read<'handle>(&'handle self) -> FilterConfigDataReadGuard<'handle, T> {
435 let addr = self.inner as *mut () as usize;
436 let lock = HANDLES
437 .entry(addr)
438 .or_insert_with(|| parking_lot::RawRwLock::INIT);
439 let lock = lock.value();
440
441 lock.lock_shared();
442 FilterConfigDataReadGuard::new(self.inner)
443 }
444
445 pub fn try_read<'handle>(&'handle self) -> Option<FilterConfigDataReadGuard<'handle, T>> {
448 let addr = self.inner as *mut () as usize;
449 let lock = HANDLES
450 .entry(addr)
451 .or_insert_with(|| parking_lot::RawRwLock::INIT);
452 let lock = lock.value();
453
454 if lock.try_lock_shared() {
455 Some(FilterConfigDataReadGuard::new(self.inner))
456 } else {
457 None
458 }
459 }
460
461 pub fn write<'handle>(&'handle self) -> FilterConfigDataWriteGuard<'handle, T> {
463 let addr = self.inner as *mut () as usize;
464 let lock = HANDLES
465 .entry(addr)
466 .or_insert_with(|| parking_lot::RawRwLock::INIT);
467 let lock = lock.value();
468 lock.lock_exclusive();
469 FilterConfigDataWriteGuard::new(self.inner)
470 }
471
472 pub fn try_write<'handle>(&'handle self) -> Option<FilterConfigDataWriteGuard<'handle, T>> {
475 let addr = self.inner as *mut () as usize;
476 let lock = HANDLES
477 .entry(addr)
478 .or_insert_with(|| parking_lot::RawRwLock::INIT);
479 let lock = lock.value();
480 if lock.try_lock_exclusive() {
481 Some(FilterConfigDataWriteGuard::new(self.inner))
482 } else {
483 None
484 }
485 }
486
487 pub fn as_ptr(&self) -> *mut T {
493 self.inner
494 }
495}
496
497pub struct FilterConfigDataReadGuard<'handle, T: Copy> {
499 pub(crate) inner: *mut T,
500 _handle: std::marker::PhantomData<&'handle FilterConfigDataHandle<T>>,
501}
502unsafe impl<T: Send + Sync + Copy> Send for FilterConfigDataReadGuard<'_, T> {}
503unsafe impl<T: Send + Sync + Copy> Sync for FilterConfigDataReadGuard<'_, T> {}
504impl<T: Copy> FilterConfigDataReadGuard<'_, T> {
505 fn new<'handle>(inner: *mut T) -> FilterConfigDataReadGuard<'handle, T> {
506 FilterConfigDataReadGuard {
507 inner,
508 _handle: std::marker::PhantomData,
509 }
510 }
511}
512impl<T: Copy> Drop for FilterConfigDataReadGuard<'_, T> {
513 fn drop(&mut self) {
514 let addr = self.inner as *mut () as usize;
515 if let Some(entry) = HANDLES.get(&addr) {
516 let lock = entry.value();
517 unsafe { lock.unlock_shared() };
518 }
519 }
520}
521impl<T: Copy> std::convert::AsRef<T> for FilterConfigDataReadGuard<'_, T> {
522 fn as_ref(&self) -> &T {
523 unsafe { &*self.inner }
524 }
525}
526impl<T: Copy> std::ops::Deref for FilterConfigDataReadGuard<'_, T> {
527 type Target = T;
528
529 fn deref(&self) -> &Self::Target {
530 self.as_ref()
531 }
532}
533
534pub struct FilterConfigDataWriteGuard<'handle, T: Copy> {
536 pub(crate) inner: *mut T,
537 _handle: std::marker::PhantomData<&'handle FilterConfigDataHandle<T>>,
538}
539
540unsafe impl<T: Send + Sync + Copy> Send for FilterConfigDataWriteGuard<'_, T> {}
541unsafe impl<T: Send + Sync + Copy> Sync for FilterConfigDataWriteGuard<'_, T> {}
542impl<T: Copy> FilterConfigDataWriteGuard<'_, T> {
543 fn new<'handle>(inner: *mut T) -> FilterConfigDataWriteGuard<'handle, T> {
544 FilterConfigDataWriteGuard {
545 inner,
546 _handle: std::marker::PhantomData,
547 }
548 }
549}
550impl<T: Copy> Drop for FilterConfigDataWriteGuard<'_, T> {
551 fn drop(&mut self) {
552 let addr = self.inner as *mut () as usize;
553 if let Some(entry) = HANDLES.get(&addr) {
554 let lock = entry.value();
555 unsafe { lock.unlock_exclusive() };
556 }
557 }
558}
559impl<T: Copy> std::convert::AsMut<T> for FilterConfigDataWriteGuard<'_, T> {
560 fn as_mut(&mut self) -> &mut T {
561 unsafe { &mut *self.inner }
562 }
563}
564impl<T: Copy> std::ops::Deref for FilterConfigDataWriteGuard<'_, T> {
565 type Target = T;
566 fn deref(&self) -> &Self::Target {
567 unsafe { &*self.inner }
568 }
569}
570impl<T: Copy> std::ops::DerefMut for FilterConfigDataWriteGuard<'_, T> {
571 fn deref_mut(&mut self) -> &mut Self::Target {
572 self.as_mut()
573 }
574}
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579
580 #[test]
581 fn filter_config_data_handle_reads_initial_value() {
582 let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
583 let read_guard = handle.read();
584 assert_eq!(*read_guard, 42);
585 }
586
587 #[test]
588 fn filter_config_data_handle_writes_and_reads_updated_value() {
589 let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
590 {
591 let mut write_guard = handle.write();
592 *write_guard = 100;
593 }
594 let read_guard = handle.read();
595 assert_eq!(*read_guard, 100);
596 }
597
598 #[test]
599 fn filter_config_data_handle_try_read_fails_when_locked_for_write() {
600 let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
601 let _write_guard = handle.write();
602 let try_read_guard = handle.try_read();
603 assert!(try_read_guard.is_none());
604 }
605
606 #[test]
607 fn filter_config_data_handle_try_write_fails_when_locked_for_read() {
608 let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
609 let _read_guard = handle.read();
610 let try_write_guard = handle.try_write();
611 assert!(try_write_guard.is_none());
612 }
613
614 #[test]
615 fn filter_config_data_handle_clone_shares_state() {
616 let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
617 let cloned_handle = handle.clone();
618 {
619 let mut write_guard = handle.write();
620 *write_guard = 100;
621 }
622 let read_guard = cloned_handle.read();
623 assert_eq!(*read_guard, 100);
624 }
625
626 #[test]
627 fn filter_config_data_handle_never_drops_data_for_borrowed() {
628 let mut data =
629 crate::filter::ErasedFilterConfigData::with_default_value("test".to_string(), 42);
630 let data_ptr = Box::into_raw(Box::new(42u32));
631 data.value = Some(std::ptr::NonNull::new(data_ptr as _).unwrap());
632 let handle = FilterConfigDataHandle::<u32>::__from_erased(&data);
633 drop(handle);
634
635 assert_eq!(unsafe { *data_ptr }, 42);
636 }
637
638 #[test]
639 fn filter_config_data_handle_reads_value_from_erased_data() {
640 let boxed = Box::new(77u32);
641 let ptr = std::ptr::NonNull::from(boxed.as_ref());
642 let data = crate::filter::FilterConfigData {
643 name: "test".to_string(),
644 value: Some(ptr),
645 default_value: 0,
646 };
647 let erased = data.erase_type();
648 let handle = FilterConfigDataHandle::<u32>::__from_erased(&erased);
649 let read_guard = handle.read();
650
651 assert_eq!(*read_guard, 77);
652 assert_eq!(erased.value.unwrap().as_ptr() as *mut u32, ptr.as_ptr());
653
654 drop(read_guard);
655 drop(handle);
656 drop(boxed);
657 }
658}