Skip to main content

aviutl2\filter/
bridge.rs

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    // AviUtl2 -> aviutl2-rsの設定の反映は2回行っても特に問題ないはずなので、
131    // read()ロックをアップグレードしてロックが途切れないようにするといった
132    // 高等テクニックは使わない。
133    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    // null終端
243    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    // NOTE: プラグイン名などの文字列はAviUtlが終了するまで解放しない
266    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/// フィルタプラグインを登録するマクロ。
381///
382/// # Arguments
383///
384/// - `unwind`: panic時にunwindするかどうか。デフォルトは`true`。
385#[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}