aviutl2\output/
bridge.rs

1use std::num::NonZeroIsize;
2
3use crate::{
4    common::{AnyResult, LeakManager, alert_error, format_file_filters},
5    output::{FromRawAudioSamples, OutputInfo, OutputPlugin},
6};
7
8use aviutl2_sys::common::{WAVE_FORMAT_IEEE_FLOAT, WAVE_FORMAT_PCM};
9
10pub struct InternalOutputPluginState<T: Send + Sync + OutputPlugin> {
11    leak_manager: LeakManager,
12    global_leak_manager: LeakManager,
13
14    instance: T,
15}
16
17impl<T: Send + Sync + OutputPlugin> InternalOutputPluginState<T> {
18    pub fn new(instance: T) -> Self {
19        Self {
20            leak_manager: LeakManager::new(),
21            global_leak_manager: LeakManager::new(),
22            instance,
23        }
24    }
25}
26
27impl FromRawAudioSamples for f32 {
28    const FORMAT: u32 = WAVE_FORMAT_IEEE_FLOAT;
29
30    unsafe fn from_raw(length: i32, num_channels: u32, frame_data_ptr: *const u8) -> Vec<Self> {
31        let frame_data_slice = unsafe {
32            std::slice::from_raw_parts(
33                frame_data_ptr as *const f32,
34                length as usize * num_channels as usize,
35            )
36        };
37        frame_data_slice.to_vec()
38    }
39}
40impl FromRawAudioSamples for i16 {
41    const FORMAT: u32 = WAVE_FORMAT_PCM;
42
43    unsafe fn from_raw(length: i32, num_channels: u32, frame_data_ptr: *const u8) -> Vec<Self> {
44        let frame_data_slice = unsafe {
45            std::slice::from_raw_parts(
46                frame_data_ptr as *const i16,
47                length as usize * num_channels as usize,
48            )
49        };
50        frame_data_slice.to_vec()
51    }
52}
53
54pub unsafe fn initialize_plugin_c<T: OutputSingleton>(version: u32) -> bool {
55    match initialize_plugin::<T>(version) {
56        Ok(_) => true,
57        Err(e) => {
58            log::error!("Failed to initialize plugin: {}", e);
59            alert_error(&e);
60            false
61        }
62    }
63}
64
65pub(crate) fn initialize_plugin<T: OutputSingleton>(version: u32) -> AnyResult<()> {
66    let plugin_state = T::__get_singleton_state();
67    let info = crate::common::AviUtl2Info {
68        version: version.into(),
69    };
70    let internal = T::new(info)?;
71    let plugin = InternalOutputPluginState::new(internal);
72    *plugin_state.write().unwrap() = Some(plugin);
73
74    Ok(())
75}
76
77pub unsafe fn uninitialize_plugin<T: OutputSingleton>() {
78    let plugin_state = T::__get_singleton_state();
79    let mut plugin_state = plugin_state.write().unwrap();
80    *plugin_state = None;
81}
82
83pub unsafe fn create_table<T: OutputSingleton>() -> *mut aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE {
84    let plugin_state = T::__get_singleton_state();
85    let mut plugin_state = plugin_state.write().unwrap();
86    let plugin_state = plugin_state.as_mut().expect("Plugin not initialized");
87    log::info!("Creating OUTPUT_PLUGIN_TABLE");
88    plugin_state.leak_manager.free_leaked_memory();
89    let plugin = &plugin_state.instance;
90    let plugin_info = plugin.plugin_info();
91    let filefilter = format_file_filters(&plugin_info.file_filters);
92
93    let name = if cfg!(debug_assertions) {
94        format!("{} (Debug)", plugin_info.name)
95    } else {
96        plugin_info.name
97    };
98    let information = if cfg!(debug_assertions) {
99        format!("{} (Debug Build)", plugin_info.information)
100    } else {
101        plugin_info.information
102    };
103
104    // NOTE: プラグイン名などの文字列はAviUtlが終了するまで解放しない
105    let table = aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE {
106        flag: plugin_info.output_type.to_bits(),
107        name: plugin_state.global_leak_manager.leak_as_wide_string(&name),
108        filefilter: plugin_state
109            .global_leak_manager
110            .leak_as_wide_string(&filefilter),
111        information: plugin_state
112            .global_leak_manager
113            .leak_as_wide_string(&information),
114        func_output: Some(func_output::<T>),
115        func_config: plugin_info.can_config.then_some(func_config::<T>),
116        func_get_config_text: Some(func_get_config_text::<T>),
117    };
118    let table = Box::new(table);
119    Box::leak(table)
120}
121
122extern "C" fn func_output<T: OutputSingleton>(oip: *mut aviutl2_sys::output2::OUTPUT_INFO) -> bool {
123    let plugin_state = T::__get_singleton_state();
124    let plugin_state = plugin_state.read().unwrap();
125    let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
126    plugin_state.leak_manager.free_leaked_memory();
127    let plugin = &plugin_state.instance;
128    let oip = unsafe { &mut *oip };
129    let output_info = OutputInfo::from_raw(oip);
130    match plugin.output(output_info) {
131        Ok(()) => true,
132        Err(e) => {
133            log::error!("Error during func_output: {}", e);
134            alert_error(&e);
135            false
136        }
137    }
138}
139
140extern "C" fn func_config<T: OutputSingleton>(
141    hwnd: aviutl2_sys::output2::HWND,
142    dll_hinst: aviutl2_sys::output2::HINSTANCE,
143) -> bool {
144    let plugin_state = T::__get_singleton_state();
145    let plugin_state = plugin_state.read().unwrap();
146    let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
147    plugin_state.leak_manager.free_leaked_memory();
148    let plugin = &plugin_state.instance;
149    let mut handle =
150        raw_window_handle::Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
151    handle.hinstance = Some(NonZeroIsize::new(dll_hinst as isize).unwrap());
152    match plugin.config(handle) {
153        Ok(()) => true,
154        Err(e) => {
155            log::error!("Error during func_config: {}", e);
156            alert_error(&e);
157            false
158        }
159    }
160}
161
162extern "C" fn func_get_config_text<T: OutputSingleton>() -> *const u16 {
163    let plugin_state = T::__get_singleton_state();
164    let plugin_state = plugin_state.read().unwrap();
165    let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
166    plugin_state.leak_manager.free_leaked_memory();
167    let plugin = &plugin_state.instance;
168    let text = plugin.config_text();
169    match text {
170        Ok(text) => plugin_state.leak_manager.leak_as_wide_string(&text),
171        Err(e) => {
172            log::error!("Error during func_get_config_text: {}", e);
173            plugin_state
174                .leak_manager
175                .leak_as_wide_string(format!("エラー:{}", e).as_str())
176        }
177    }
178}
179
180pub trait OutputSingleton
181where
182    Self: 'static + Send + Sync + OutputPlugin,
183{
184    fn __get_singleton_state() -> &'static std::sync::RwLock<Option<InternalOutputPluginState<Self>>>;
185    fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R {
186        let lock = Self::__get_singleton_state();
187        let guard = lock.read().unwrap();
188        let state = guard.as_ref().expect("Plugin not initialized");
189        f(&state.instance)
190    }
191    fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
192        let lock = Self::__get_singleton_state();
193        let mut guard = lock.write().unwrap();
194        let state = guard.as_mut().expect("Plugin not initialized");
195        f(&mut state.instance)
196    }
197}
198
199/// 出力プラグインを登録するマクロ。
200#[macro_export]
201macro_rules! register_output_plugin {
202    ($struct:ident) => {
203        ::aviutl2::__internal_module! {
204            #[unsafe(no_mangle)]
205            unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
206                $crate::logger::__initialize_logger(logger)
207            }
208
209            #[unsafe(no_mangle)]
210            unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
211                $crate::output::__bridge::initialize_plugin_c::<$struct>(version)
212            }
213
214            #[unsafe(no_mangle)]
215            unsafe extern "C" fn UninitializePlugin() {
216                $crate::output::__bridge::uninitialize_plugin::<$struct>()
217            }
218
219            #[unsafe(no_mangle)]
220            unsafe extern "C" fn GetOutputPluginTable()
221            -> *mut aviutl2::sys::output2::OUTPUT_PLUGIN_TABLE {
222                $crate::output::__bridge::create_table::<$struct>()
223            }
224        }
225    };
226}