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 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#[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}