1use crate::{
2 common::{AnyResult, LeakManager},
3 filter::{
4 AudioObjectInfo, FilterConfigItem, FilterPlugin, FilterPluginTable, FilterProcAudio,
5 FilterProcVideo, ObjectInfo, SceneInfo, VideoObjectInfo,
6 },
7 utils::catch_unwind_with_panic_info,
8};
9
10impl FilterProcAudio {
11 unsafe fn from_raw(raw_ptr: *const aviutl2_sys::filter2::FILTER_PROC_AUDIO) -> FilterProcAudio {
12 let raw = unsafe { &*raw_ptr };
13 FilterProcAudio {
14 scene: unsafe { SceneInfo::from_raw(raw.scene) },
15 object: unsafe { ObjectInfo::from_raw(raw.object) },
16 audio_object: unsafe { AudioObjectInfo::from_raw(raw.object) },
17 inner: raw_ptr,
18 }
19 }
20}
21impl FilterProcVideo {
22 unsafe fn from_raw(raw_ptr: *const aviutl2_sys::filter2::FILTER_PROC_VIDEO) -> FilterProcVideo {
23 let raw = unsafe { &*raw_ptr };
24 FilterProcVideo {
25 scene: unsafe { SceneInfo::from_raw(raw.scene) },
26 object: unsafe { ObjectInfo::from_raw(raw.object) },
27 video_object: unsafe { VideoObjectInfo::from_raw(raw.object) },
28 inner: raw_ptr,
29 }
30 }
31}
32
33impl SceneInfo {
34 unsafe fn from_raw(raw: *const aviutl2_sys::filter2::SCENE_INFO) -> SceneInfo {
35 let raw = unsafe { &*raw };
36 SceneInfo {
37 width: raw.width as u32,
38 height: raw.height as u32,
39 frame_rate: num_rational::Rational32::new(raw.rate, raw.scale),
40 sample_rate: raw.sample_rate as u32,
41 }
42 }
43}
44impl ObjectInfo {
45 unsafe fn from_raw(raw: *const aviutl2_sys::filter2::OBJECT_INFO) -> ObjectInfo {
46 let raw = unsafe { &*raw };
47 ObjectInfo {
48 id: raw.id,
49 effect_id: raw.effect_id,
50 frame: raw.frame as u32,
51 frame_total: raw.frame_total as u32,
52 time: raw.time,
53 time_total: raw.time_total,
54 is_filter_object: (raw.flag & aviutl2_sys::filter2::OBJECT_INFO::FLAG_FILTER_OBJECT)
55 != 0,
56 }
57 }
58}
59impl VideoObjectInfo {
60 unsafe fn from_raw(raw: *const aviutl2_sys::filter2::OBJECT_INFO) -> VideoObjectInfo {
61 let raw = unsafe { &*raw };
62 VideoObjectInfo {
63 width: raw.width as u32,
64 height: raw.height as u32,
65 }
66 }
67}
68impl AudioObjectInfo {
69 unsafe fn from_raw(raw: *const aviutl2_sys::filter2::OBJECT_INFO) -> AudioObjectInfo {
70 let raw = unsafe { &*raw };
71 AudioObjectInfo {
72 sample_index: raw.sample_index as u64,
73 sample_total: raw.sample_total as u64,
74 sample_num: raw.sample_num as u32,
75 channel_num: raw.channel_num as u32,
76 }
77 }
78}
79
80pub struct InternalFilterPluginState<T: Send + Sync + FilterPlugin> {
81 plugin_info: FilterPluginTable,
82 global_leak_manager: LeakManager,
83 leak_manager: LeakManager,
84 config_pointers: Vec<*const aviutl2_sys::filter2::FILTER_ITEM>,
85 config_items: Vec<FilterConfigItem>,
86
87 instance: T,
88}
89unsafe impl<T: Send + Sync + FilterPlugin> Send for InternalFilterPluginState<T> {}
90unsafe impl<T: Send + Sync + FilterPlugin> Sync for InternalFilterPluginState<T> {}
91
92impl<T: Send + Sync + FilterPlugin> InternalFilterPluginState<T> {
93 pub fn new(instance: T) -> Self {
94 let plugin_info = instance.plugin_info();
95 let config_items = plugin_info.config_items.clone();
96 Self {
97 plugin_info,
98 global_leak_manager: LeakManager::new(),
99 leak_manager: LeakManager::new(),
100 config_pointers: Vec::new(),
101 config_items,
102
103 instance,
104 }
105 }
106
107 pub fn should_apply_configs(&self) -> bool {
108 for (item, raw) in self.config_items.iter().zip(self.config_pointers.iter()) {
109 if unsafe { item.should_apply_from_raw(*raw) } {
110 return true;
111 }
112 }
113 false
114 }
115
116 pub fn apply_configs(&mut self) {
117 for (item, raw) in self
118 .config_items
119 .iter_mut()
120 .zip(self.config_pointers.iter())
121 {
122 unsafe { item.apply_from_raw(*raw) };
123 }
124 }
125}
126
127fn update_configs<T: Send + Sync + FilterPlugin>(
128 plugin_state: &std::sync::RwLock<Option<InternalFilterPluginState<T>>>,
129) {
130 let plugin_lock = plugin_state.read().unwrap();
134 let plugin = plugin_lock.as_ref().expect("Plugin not initialized");
135 if plugin.should_apply_configs() {
136 drop(plugin_lock);
137 plugin_state
138 .write()
139 .unwrap()
140 .as_mut()
141 .unwrap()
142 .apply_configs();
143 }
144}
145
146pub trait FilterSingleton
147where
148 Self: 'static + Send + Sync + crate::filter::FilterPlugin,
149{
150 fn __get_singleton_state()
151 -> &'static std::sync::RwLock<Option<crate::filter::__bridge::InternalFilterPluginState<Self>>>;
152 fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R {
153 let lock = Self::__get_singleton_state();
154 let guard = lock.read().unwrap();
155 let state = guard.as_ref().expect("Plugin not initialized");
156 f(&state.instance)
157 }
158 fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
159 let lock = Self::__get_singleton_state();
160 let mut guard = lock.write().unwrap();
161 let state = guard.as_mut().expect("Plugin not initialized");
162 f(&mut state.instance)
163 }
164}
165
166pub unsafe fn initialize_plugin_c<T: FilterSingleton>(version: u32) -> bool {
167 match initialize_plugin::<T>(version) {
168 Ok(_) => true,
169 Err(e) => {
170 tracing::error!("Failed to initialize plugin: {}", e);
171 let _ = crate::logger::write_error_log(&format!("{e}"));
172 false
173 }
174 }
175}
176
177pub unsafe fn initialize_plugin_c_unwind<T: FilterSingleton>(version: u32) -> bool {
178 match catch_unwind_with_panic_info(|| unsafe { initialize_plugin_c::<T>(version) }) {
179 Ok(result) => result,
180 Err(panic_info) => {
181 tracing::error!(
182 "Panic occurred during plugin initialization: {}",
183 panic_info
184 );
185 let _ = crate::logger::write_error_log(&panic_info);
186 false
187 }
188 }
189}
190
191pub(crate) fn initialize_plugin<T: FilterSingleton>(version: u32) -> AnyResult<()> {
192 crate::common::ensure_minimum_aviutl2_version(version.into())?;
193 let plugin_state = T::__get_singleton_state();
194 let info = crate::common::AviUtl2Info {
195 version: version.into(),
196 };
197 let internal = T::new(info)?;
198 let plugin = InternalFilterPluginState::new(internal);
199 *plugin_state.write().unwrap() = Some(plugin);
200
201 Ok(())
202}
203pub unsafe fn uninitialize_plugin<T: FilterSingleton>() {
204 let plugin_state = T::__get_singleton_state();
205 let mut plugin_state = plugin_state.write().unwrap();
206 *plugin_state = None;
207}
208
209pub unsafe fn uninitialize_plugin_c_unwind<T: FilterSingleton>() {
210 match crate::utils::catch_unwind_with_panic_info(|| unsafe { uninitialize_plugin::<T>() }) {
211 Ok(()) => {}
212 Err(panic_info) => {
213 tracing::error!(
214 "Panic occurred during plugin uninitialization: {}",
215 panic_info
216 );
217 let _ = crate::logger::write_error_log(&panic_info);
218 }
219 }
220}
221fn create_table_impl<T: FilterSingleton>(
222 unwind: bool,
223) -> *mut aviutl2_sys::filter2::FILTER_PLUGIN_TABLE {
224 let plugin_state = T::__get_singleton_state();
225 let mut plugin_state = plugin_state.write().unwrap();
226 let plugin_state = plugin_state.as_mut().expect("Plugin not initialized");
227 let plugin_info = &plugin_state.plugin_info;
228
229 let name = plugin_info.name.clone();
230 let information = plugin_info.information.clone();
231
232 let config_items = plugin_info
233 .config_items
234 .iter()
235 .map(|item| {
236 plugin_state
237 .global_leak_manager
238 .leak(item.to_raw(&plugin_state.global_leak_manager))
239 })
240 .collect::<Vec<_>>();
241 plugin_state.config_pointers = config_items.to_vec();
242 plugin_state
244 .config_pointers
245 .push(std::ptr::null::<aviutl2_sys::filter2::FILTER_ITEM>());
246 let config_items = plugin_state.global_leak_manager.leak_value_vec(
247 plugin_state
248 .config_pointers
249 .iter()
250 .map(|p| *p as usize)
251 .collect(),
252 );
253
254 let func_proc_video = if unwind {
255 func_proc_video_unwind::<T>
256 } else {
257 func_proc_video::<T>
258 };
259 let func_proc_audio = if unwind {
260 func_proc_audio_unwind::<T>
261 } else {
262 func_proc_audio::<T>
263 };
264
265 let table = aviutl2_sys::filter2::FILTER_PLUGIN_TABLE {
267 flag: plugin_info.flags.to_bits(),
268 name: plugin_state.global_leak_manager.leak_as_wide_string(&name),
269 information: plugin_state
270 .global_leak_manager
271 .leak_as_wide_string(&information),
272 label: plugin_info.label.as_ref().map_or(std::ptr::null(), |s| {
273 plugin_state.global_leak_manager.leak_as_wide_string(s)
274 }),
275 items: config_items as _,
276 func_proc_video: Some(func_proc_video),
277 func_proc_audio: Some(func_proc_audio),
278 };
279 let table = Box::new(table);
280 Box::leak(table)
281}
282
283pub unsafe fn create_table<T: FilterSingleton>() -> *mut aviutl2_sys::filter2::FILTER_PLUGIN_TABLE {
284 create_table_impl::<T>(false)
285}
286
287pub unsafe fn create_table_unwind<T: FilterSingleton>()
288-> *mut aviutl2_sys::filter2::FILTER_PLUGIN_TABLE {
289 match crate::utils::catch_unwind_with_panic_info(|| create_table_impl::<T>(true)) {
290 Ok(table) => table,
291 Err(panic_info) => {
292 tracing::error!("Panic occurred during create_table: {}", panic_info);
293 let _ = crate::logger::write_error_log(&panic_info);
294 std::ptr::null_mut()
295 }
296 }
297}
298
299fn proc_video_impl<T: FilterSingleton>(
300 video: *mut aviutl2_sys::filter2::FILTER_PROC_VIDEO,
301) -> AnyResult<()> {
302 let plugin_lock = T::__get_singleton_state();
303 anyhow::ensure!(!plugin_lock.is_poisoned(), "Plugin state lock is poisoned");
304 update_configs::<T>(plugin_lock);
305 let plugin_state = plugin_lock.read().unwrap();
306 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
307
308 plugin_state.leak_manager.free_leaked_memory();
309 let plugin = &plugin_state.instance;
310 let mut video = unsafe { FilterProcVideo::from_raw(video) };
311 plugin.proc_video(&plugin_state.config_items, &mut video)
312}
313
314fn proc_audio_impl<T: FilterSingleton>(
315 audio: *mut aviutl2_sys::filter2::FILTER_PROC_AUDIO,
316) -> AnyResult<()> {
317 let plugin_lock = T::__get_singleton_state();
318 update_configs::<T>(plugin_lock);
319 let plugin_state = plugin_lock.read().unwrap();
320 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
321 plugin_state.leak_manager.free_leaked_memory();
322 let plugin = &plugin_state.instance;
323 let mut audio = unsafe { FilterProcAudio::from_raw(audio) };
324 plugin.proc_audio(&plugin_state.config_items, &mut audio)
325}
326
327extern "C" fn func_proc_video<T: FilterSingleton>(
328 video: *mut aviutl2_sys::filter2::FILTER_PROC_VIDEO,
329) -> bool {
330 match proc_video_impl::<T>(video) {
331 Ok(()) => true,
332 Err(e) => {
333 tracing::error!("Error in proc_video: {}", e);
334 false
335 }
336 }
337}
338extern "C" fn func_proc_video_unwind<T: FilterSingleton>(
339 video: *mut aviutl2_sys::filter2::FILTER_PROC_VIDEO,
340) -> bool {
341 match catch_unwind_with_panic_info(|| proc_video_impl::<T>(video)) {
342 Ok(Ok(())) => true,
343 Ok(Err(e)) => {
344 tracing::error!("Error in proc_video: {}", e);
345 false
346 }
347 Err(e) => {
348 tracing::error!("Panic in proc_video: {}", e);
349 false
350 }
351 }
352}
353extern "C" fn func_proc_audio<T: FilterSingleton>(
354 audio: *mut aviutl2_sys::filter2::FILTER_PROC_AUDIO,
355) -> bool {
356 match proc_audio_impl::<T>(audio) {
357 Ok(()) => true,
358 Err(e) => {
359 tracing::error!("Error in proc_audio: {}", e);
360 false
361 }
362 }
363}
364extern "C" fn func_proc_audio_unwind<T: FilterSingleton>(
365 audio: *mut aviutl2_sys::filter2::FILTER_PROC_AUDIO,
366) -> bool {
367 match catch_unwind_with_panic_info(|| proc_audio_impl::<T>(audio)) {
368 Ok(Ok(())) => true,
369 Ok(Err(e)) => {
370 tracing::error!("Error in proc_audio: {}", e);
371 false
372 }
373 Err(e) => {
374 tracing::error!("Panic in proc_audio: {}", e);
375 false
376 }
377 }
378}
379
380#[macro_export]
386macro_rules! register_filter_plugin {
387 ($struct:ident, $($key:ident = $value:expr),* $(,)?) => {
388 $crate::__internal_module! {
389 #[unsafe(no_mangle)]
390 unsafe extern "C" fn RequiredVersion() -> u32 {
391 $crate::MINIMUM_AVIUTL2_VERSION.into()
392 }
393
394 #[unsafe(no_mangle)]
395 unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
396 $crate::comptime_if::comptime_if! {
397 if unwind where (unwind = true, $( $key = $value ),* ) {
398 $crate::logger::__initialize_logger_unwind(logger)
399 } else {
400 $crate::logger::__initialize_logger(logger)
401 }
402 }
403 }
404
405 #[unsafe(no_mangle)]
406 unsafe extern "C" fn InitializeConfig(
407 config: *mut $crate::sys::config2::CONFIG_HANDLE
408 ) {
409 $crate::comptime_if::comptime_if! {
410 if unwind where (unwind = true, $( $key = $value ),* ) {
411 $crate::config::__initialize_config_handle_unwind(config)
412 } else {
413 $crate::config::__initialize_config_handle(config)
414 }
415 }
416 }
417
418 #[unsafe(no_mangle)]
419 unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
420 unsafe {
421 $crate::comptime_if::comptime_if! {
422 if unwind where (unwind = true, $( $key = $value ),* ) {
423 $crate::filter::__bridge::initialize_plugin_c_unwind::<$struct>(version)
424 } else {
425 $crate::filter::__bridge::initialize_plugin_c::<$struct>(version)
426 }
427 }
428 }
429 }
430
431 #[unsafe(no_mangle)]
432 unsafe extern "C" fn UninitializePlugin() {
433 unsafe {
434 $crate::comptime_if::comptime_if! {
435 if unwind where (unwind = true, $( $key = $value ),* ) {
436 $crate::filter::__bridge::uninitialize_plugin_c_unwind::<$struct>()
437 } else {
438 $crate::filter::__bridge::uninitialize_plugin::<$struct>()
439 }
440 }
441 }
442 }
443
444 #[unsafe(no_mangle)]
445 unsafe extern "C" fn GetFilterPluginTable()
446 -> *mut aviutl2::sys::filter2::FILTER_PLUGIN_TABLE {
447 $crate::comptime_if::comptime_if! {
448 if unwind where (unwind = true, $( $key = $value ),* ) {
449 unsafe { $crate::filter::__bridge::create_table_unwind::<$struct>() }
450 } else {
451 unsafe { $crate::filter::__bridge::create_table::<$struct>() }
452 }
453 }
454 }
455 }
456 };
457 ($struct:ident, $($key:ident),* $(,)?) => {
458 $crate::register_filter_plugin!($struct, $( $key = true ),* );
459 };
460 ($struct:ident) => {
461 $crate::register_filter_plugin!($struct, );
462 };
463}