aviutl2\filter/
bridge.rs

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    // AviUtl2 -> aviutl2-rsの設定の反映は2回行っても特に問題ないはずなので、
129    // read()ロックをアップグレードしてロックが途切れないようにするといった
130    // 高等テクニックは使わない。
131    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    // null終端
218    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    // NOTE: プラグイン名などの文字列はAviUtlが終了するまで解放しない
230    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/// フィルタプラグインを登録するマクロ。
299#[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}