1use crate::{
2 common::{AnyResult, LeakManager, alert_error},
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 }
55 }
56}
57impl VideoObjectInfo {
58 unsafe fn from_raw(raw: *const aviutl2_sys::filter2::OBJECT_INFO) -> VideoObjectInfo {
59 let raw = unsafe { &*raw };
60 VideoObjectInfo {
61 width: raw.width as u32,
62 height: raw.height as u32,
63 }
64 }
65}
66impl AudioObjectInfo {
67 unsafe fn from_raw(raw: *const aviutl2_sys::filter2::OBJECT_INFO) -> AudioObjectInfo {
68 let raw = unsafe { &*raw };
69 AudioObjectInfo {
70 sample_index: raw.sample_index as u64,
71 sample_total: raw.sample_total as u64,
72 sample_num: raw.sample_num as u32,
73 channel_num: raw.channel_num as u32,
74 }
75 }
76}
77
78pub struct InternalFilterPluginState<T: Send + Sync + FilterPlugin> {
79 plugin_info: FilterPluginTable,
80 global_leak_manager: LeakManager,
81 leak_manager: LeakManager,
82 config_pointers: Vec<*const aviutl2_sys::filter2::FILTER_ITEM>,
83 config_items: Vec<FilterConfigItem>,
84
85 instance: T,
86}
87unsafe impl<T: Send + Sync + FilterPlugin> Send for InternalFilterPluginState<T> {}
88unsafe impl<T: Send + Sync + FilterPlugin> Sync for InternalFilterPluginState<T> {}
89
90impl<T: Send + Sync + FilterPlugin> InternalFilterPluginState<T> {
91 pub fn new(instance: T) -> Self {
92 let plugin_info = instance.plugin_info();
93 let config_items = plugin_info.config_items.clone();
94 Self {
95 plugin_info,
96 global_leak_manager: LeakManager::new(),
97 leak_manager: LeakManager::new(),
98 config_pointers: Vec::new(),
99 config_items,
100
101 instance,
102 }
103 }
104
105 pub fn should_apply_configs(&self) -> bool {
106 for (item, raw) in self.config_items.iter().zip(self.config_pointers.iter()) {
107 if unsafe { item.should_apply_from_raw(*raw) } {
108 return true;
109 }
110 }
111 false
112 }
113
114 pub fn apply_configs(&mut self) {
115 for (item, raw) in self
116 .config_items
117 .iter_mut()
118 .zip(self.config_pointers.iter())
119 {
120 unsafe { item.apply_from_raw(*raw) };
121 }
122 }
123}
124
125fn update_configs<T: Send + Sync + FilterPlugin>(
126 plugin_state: &std::sync::RwLock<Option<InternalFilterPluginState<T>>>,
127) {
128 let plugin_lock = plugin_state.read().unwrap();
132 let plugin = plugin_lock.as_ref().expect("Plugin not initialized");
133 if plugin.should_apply_configs() {
134 drop(plugin_lock);
135 plugin_state
136 .write()
137 .unwrap()
138 .as_mut()
139 .unwrap()
140 .apply_configs();
141 }
142}
143
144pub trait FilterSingleton
145where
146 Self: 'static + Send + Sync + FilterPlugin,
147{
148 fn __get_singleton_state() -> &'static std::sync::RwLock<Option<InternalFilterPluginState<Self>>>;
149 fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R {
150 let lock = Self::__get_singleton_state();
151 let guard = lock.read().unwrap();
152 let state = guard.as_ref().expect("Plugin not initialized");
153 f(&state.instance)
154 }
155 fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
156 let lock = Self::__get_singleton_state();
157 let mut guard = lock.write().unwrap();
158 let state = guard.as_mut().expect("Plugin not initialized");
159 f(&mut state.instance)
160 }
161}
162
163pub unsafe fn initialize_plugin_c<T: FilterSingleton>(version: u32) -> bool {
164 match initialize_plugin::<T>(version) {
165 Ok(_) => true,
166 Err(e) => {
167 log::error!("Failed to initialize plugin: {}", e);
168 alert_error(&e);
169 false
170 }
171 }
172}
173
174pub(crate) fn initialize_plugin<T: FilterSingleton>(version: u32) -> AnyResult<()> {
175 let plugin_state = T::__get_singleton_state();
176 let info = crate::common::AviUtl2Info {
177 version: version.into(),
178 };
179 let internal = T::new(info)?;
180 let plugin = InternalFilterPluginState::new(internal);
181 *plugin_state.write().unwrap() = Some(plugin);
182
183 Ok(())
184}
185pub unsafe fn uninitialize_plugin<T: FilterSingleton>() {
186 let plugin_state = T::__get_singleton_state();
187 let mut plugin_state = plugin_state.write().unwrap();
188 *plugin_state = None;
189}
190pub unsafe fn create_table<T: FilterSingleton>() -> *mut aviutl2_sys::filter2::FILTER_PLUGIN_TABLE {
191 let plugin_state = T::__get_singleton_state();
192 let mut plugin_state = plugin_state.write().unwrap();
193 let plugin_state = plugin_state.as_mut().expect("Plugin not initialized");
194 let plugin_info = &plugin_state.plugin_info;
195
196 let name = if cfg!(debug_assertions) {
197 format!("{} (Debug)", plugin_info.name)
198 } else {
199 plugin_info.name.clone()
200 };
201 let information = if cfg!(debug_assertions) {
202 format!("(Debug Build) {}", plugin_info.information)
203 } else {
204 plugin_info.information.clone()
205 };
206
207 let config_items = plugin_info
208 .config_items
209 .iter()
210 .map(|item| {
211 plugin_state
212 .global_leak_manager
213 .leak(item.to_raw(&plugin_state.global_leak_manager))
214 })
215 .collect::<Vec<_>>();
216 plugin_state.config_pointers = config_items.to_vec();
217 plugin_state
219 .config_pointers
220 .push(std::ptr::null::<aviutl2_sys::filter2::FILTER_ITEM>());
221 let config_items = plugin_state.global_leak_manager.leak_value_vec(
222 plugin_state
223 .config_pointers
224 .iter()
225 .map(|p| *p as usize)
226 .collect(),
227 );
228
229 let table = aviutl2_sys::filter2::FILTER_PLUGIN_TABLE {
231 flag: plugin_info.flags.to_bits(),
232 name: plugin_state.global_leak_manager.leak_as_wide_string(&name),
233 information: plugin_state
234 .global_leak_manager
235 .leak_as_wide_string(&information),
236 label: plugin_info.label.as_ref().map_or(std::ptr::null(), |s| {
237 plugin_state.global_leak_manager.leak_as_wide_string(s)
238 }),
239 items: config_items as _,
240 func_proc_video: Some(func_proc_video::<T>),
241 func_proc_audio: Some(func_proc_audio::<T>),
242 };
243 let table = Box::new(table);
244 Box::leak(table)
245}
246
247extern "C" fn func_proc_video<T: FilterSingleton>(
248 video: *mut aviutl2_sys::filter2::FILTER_PROC_VIDEO,
249) -> bool {
250 match catch_unwind_with_panic_info(|| {
251 let plugin_lock = T::__get_singleton_state();
252 anyhow::ensure!(!plugin_lock.is_poisoned(), "Plugin state lock is poisoned");
253 update_configs::<T>(plugin_lock);
254 let plugin_state = plugin_lock.read().unwrap();
255 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
256
257 plugin_state.leak_manager.free_leaked_memory();
258 let plugin = &plugin_state.instance;
259 let mut video = unsafe { FilterProcVideo::from_raw(video) };
260 plugin.proc_video(&plugin_state.config_items, &mut video)
261 }) {
262 Ok(Ok(())) => true,
263 Ok(Err(e)) => {
264 log::error!("Error in proc_video: {}", e);
265 false
266 }
267 Err(e) => {
268 log::error!("Panic in proc_video: {}", e);
269 false
270 }
271 }
272}
273extern "C" fn func_proc_audio<T: FilterSingleton>(
274 audio: *mut aviutl2_sys::filter2::FILTER_PROC_AUDIO,
275) -> bool {
276 match catch_unwind_with_panic_info(|| {
277 let plugin_lock = T::__get_singleton_state();
278 update_configs::<T>(plugin_lock);
279 let plugin_state = plugin_lock.read().unwrap();
280 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
281 plugin_state.leak_manager.free_leaked_memory();
282 let plugin = &plugin_state.instance;
283 let mut audio = unsafe { FilterProcAudio::from_raw(audio) };
284 plugin.proc_audio(&plugin_state.config_items, &mut audio)
285 }) {
286 Ok(Ok(())) => true,
287 Ok(Err(e)) => {
288 log::error!("Error in proc_audio: {}", e);
289 false
290 }
291 Err(e) => {
292 log::error!("Panic in proc_audio: {}", e);
293 false
294 }
295 }
296}
297
298#[macro_export]
300macro_rules! register_filter_plugin {
301 ($struct:ident) => {
302 ::aviutl2::__internal_module! {
303 #[unsafe(no_mangle)]
304 unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
305 $crate::logger::__initialize_logger(logger)
306 }
307
308 #[unsafe(no_mangle)]
309 unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
310 unsafe { $crate::filter::__bridge::initialize_plugin_c::<$struct>(version) }
311 }
312
313 #[unsafe(no_mangle)]
314 unsafe extern "C" fn UninitializePlugin() {
315 unsafe { $crate::filter::__bridge::uninitialize_plugin::<$struct>() }
316 }
317
318 #[unsafe(no_mangle)]
319 unsafe extern "C" fn GetFilterPluginTable()
320 -> *mut aviutl2::sys::filter2::FILTER_PLUGIN_TABLE {
321 unsafe { $crate::filter::__bridge::create_table::<$struct>() }
322 }
323 }
324 };
325}