1use std::num::NonZeroIsize;
2
3use crate::{
4 common::{AnyResult, LeakManager, alert_error, format_file_filters, load_wide_string},
5 input::{
6 AudioFormat, AudioInputInfo, AudioReturner, ImageReturner, InputInfo, InputPixelFormat,
7 InputPlugin, InputPluginTable, VideoInputInfo,
8 },
9};
10
11impl InputPixelFormat {
12 fn bytes_count_per_pixel(&self) -> usize {
13 match self {
14 InputPixelFormat::Bgr => 3, InputPixelFormat::Bgra => 4, InputPixelFormat::Yuy2 => 2, InputPixelFormat::Pa64 => 8, InputPixelFormat::Hf64 => 8, InputPixelFormat::Yc48 => 6, }
21 }
22}
23
24impl AudioFormat {
25 fn bytes_per_sample(&self) -> usize {
26 match self {
27 AudioFormat::IeeeFloat32 => 4, AudioFormat::Pcm16 => 2, }
30 }
31}
32
33impl VideoInputInfo {
34 fn into_raw(self) -> aviutl2_sys::input2::BITMAPINFOHEADER {
35 let bi_compression = match self.format {
36 InputPixelFormat::Bgr | InputPixelFormat::Bgra => aviutl2_sys::common::BI_RGB,
37 InputPixelFormat::Yuy2 => aviutl2_sys::common::BI_YUY2,
38 InputPixelFormat::Pa64 => aviutl2_sys::common::BI_PA64,
39 InputPixelFormat::Hf64 => aviutl2_sys::common::BI_HF64,
40 InputPixelFormat::Yc48 => aviutl2_sys::common::BI_YC48,
41 };
42
43 aviutl2_sys::input2::BITMAPINFOHEADER {
46 biSize: std::mem::size_of::<aviutl2_sys::input2::BITMAPINFOHEADER>() as u32,
47 biWidth: self.width as i32,
48 biHeight: self.height as i32,
49 biPlanes: 1,
50 biBitCount: (self.format.bytes_count_per_pixel() * 8) as u16, biCompression: bi_compression,
52 biSizeImage: (self.width * self.height * self.format.bytes_count_per_pixel() as u32),
53 biXPelsPerMeter: 0, biYPelsPerMeter: 0, biClrUsed: 0, biClrImportant: 0, }
58 }
59}
60
61impl AudioInputInfo {
62 fn into_raw(self) -> aviutl2_sys::input2::WAVEFORMATEX {
63 let format = match self.format {
64 AudioFormat::IeeeFloat32 => aviutl2_sys::common::WAVE_FORMAT_IEEE_FLOAT,
65 AudioFormat::Pcm16 => aviutl2_sys::common::WAVE_FORMAT_PCM,
66 };
67 let bytes_per_sample = self.format.bytes_per_sample();
68 aviutl2_sys::input2::WAVEFORMATEX {
69 wFormatTag: format as u16,
70 nChannels: self.channels,
71 nSamplesPerSec: self.sample_rate,
72 nAvgBytesPerSec: (self.sample_rate
73 * (self.channels as u32)
74 * (bytes_per_sample as u32)),
75 nBlockAlign: (self.channels * bytes_per_sample as u16),
76 wBitsPerSample: u16::try_from(bytes_per_sample * 8usize)
77 .expect("Invalid bits per sample"),
78 cbSize: 0, }
80 }
81}
82
83#[doc(hidden)]
84pub struct InternalInputPluginState<T: Send + Sync + InputPlugin> {
85 plugin_info: InputPluginTable,
86 global_leak_manager: LeakManager,
87 leak_manager: LeakManager,
88
89 instance: T,
90}
91
92impl<T: Send + Sync + InputPlugin> InternalInputPluginState<T> {
93 pub fn new(instance: T) -> Self {
94 let plugin_info = instance.plugin_info();
95 Self {
96 plugin_info,
97 global_leak_manager: LeakManager::new(),
98 leak_manager: LeakManager::new(),
99 instance,
100 }
101 }
102}
103
104struct InternalInputHandle<T: Send + Sync> {
105 input_info: Option<InputInfo>,
106 num_tracks: std::sync::Mutex<Option<AnyResult<(u32, u32)>>>,
107 current_video_track: std::sync::OnceLock<u32>,
108 current_audio_track: std::sync::OnceLock<u32>,
109
110 handle: T,
111}
112
113pub unsafe fn initialize_plugin_c<T: InputSingleton>(version: u32) -> bool {
114 match initialize_plugin::<T>(version) {
115 Ok(_) => true,
116 Err(e) => {
117 log::error!("Failed to initialize plugin: {}", e);
118 alert_error(&e);
119 false
120 }
121 }
122}
123
124pub(crate) fn initialize_plugin<T: InputSingleton>(version: u32) -> AnyResult<()> {
125 let plugin_state = T::__get_singleton_state();
126 let info = crate::common::AviUtl2Info {
127 version: version.into(),
128 };
129 let internal = T::new(info)?;
130 let plugin = InternalInputPluginState::new(internal);
131 *plugin_state.write().unwrap() = Some(plugin);
132
133 Ok(())
134}
135
136pub unsafe fn uninitialize_plugin<T: InputSingleton>() {
137 let plugin_state = T::__get_singleton_state();
138 let mut plugin_state = plugin_state.write().unwrap();
139 *plugin_state = None;
140}
141
142pub unsafe fn create_table<T: InputSingleton>() -> *mut aviutl2_sys::input2::INPUT_PLUGIN_TABLE {
143 let plugin_state = T::__get_singleton_state();
144 let mut plugin_state = plugin_state.write().unwrap();
145 let plugin_state = plugin_state.as_mut().expect("Plugin not initialized");
146 let plugin_info = &plugin_state.plugin_info;
147 let file_filter = format_file_filters(&plugin_info.file_filters);
148
149 let name = if cfg!(debug_assertions) {
150 format!("{} (Debug)", plugin_info.name)
151 } else {
152 plugin_info.name.clone()
153 };
154 let information = if cfg!(debug_assertions) {
155 format!("(Debug Build) {}", plugin_info.information)
156 } else {
157 plugin_info.information.clone()
158 };
159
160 let mut flag = plugin_info.input_type.to_bits();
161 if plugin_info.concurrent {
162 flag |= aviutl2_sys::input2::INPUT_PLUGIN_TABLE::FLAG_CONCURRENT;
163 }
164 flag |= aviutl2_sys::input2::INPUT_PLUGIN_TABLE::FLAG_MULTI_TRACK;
165
166 let table = aviutl2_sys::input2::INPUT_PLUGIN_TABLE {
168 flag,
169 name: plugin_state.global_leak_manager.leak_as_wide_string(&name),
170 filefilter: plugin_state
171 .global_leak_manager
172 .leak_as_wide_string(&file_filter),
173 information: plugin_state
174 .global_leak_manager
175 .leak_as_wide_string(&information),
176 func_open: Some(func_open::<T>),
177 func_close: Some(func_close::<T>),
178 func_info_get: Some(func_info_get::<T>),
179 func_read_video: Some(func_read_video::<T>),
180 func_read_audio: Some(func_read_audio::<T>),
181 func_config: plugin_info.can_config.then_some(func_config::<T>),
182 func_set_track: Some(func_set_track::<T>),
183 func_time_to_frame: Some(func_time_to_frame::<T>),
184 };
185 let table = Box::new(table);
186 Box::leak(table)
187}
188
189extern "C" fn func_open<T: InputSingleton>(
190 file: aviutl2_sys::common::LPCWSTR,
191) -> aviutl2_sys::input2::INPUT_HANDLE {
192 let plugin_state = T::__get_singleton_state();
193 let plugin_state = plugin_state.read().unwrap();
194 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
195 plugin_state.leak_manager.free_leaked_memory();
196 let path = unsafe { load_wide_string(file) };
197 log::info!("func_open called with path: {}", path);
198 let plugin = &plugin_state.instance;
199 match plugin.open(std::path::PathBuf::from(path)) {
200 Ok(handle) => {
201 let boxed_handle: Box<InternalInputHandle<T::InputHandle>> =
202 Box::new(InternalInputHandle {
203 input_info: None,
204 num_tracks: std::sync::Mutex::new(None),
205 current_video_track: std::sync::OnceLock::new(),
206 current_audio_track: std::sync::OnceLock::new(),
207 handle,
208 });
209 Box::into_raw(boxed_handle) as aviutl2_sys::input2::INPUT_HANDLE
210 }
211 Err(e) => {
212 log::error!("Error during func_open: {}", e);
213 std::ptr::null_mut()
214 }
215 }
216}
217extern "C" fn func_close<T: InputSingleton>(ih: aviutl2_sys::input2::INPUT_HANDLE) -> bool {
218 let plugin_state = T::__get_singleton_state();
219 let plugin_state = plugin_state.read().unwrap();
220 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
221 plugin_state.leak_manager.free_leaked_memory();
222 let handle = unsafe { Box::from_raw(ih as *mut InternalInputHandle<T::InputHandle>) };
223 let plugin = &plugin_state.instance;
224 match plugin.close(handle.handle) {
225 Ok(()) => true,
226 Err(e) => {
227 log::error!("Error during func_close: {}", e);
228 false
229 }
230 }
231}
232extern "C" fn func_info_get<T: InputSingleton>(
233 ih: aviutl2_sys::input2::INPUT_HANDLE,
234 iip: *mut aviutl2_sys::input2::INPUT_INFO,
235) -> bool {
236 let plugin_state = T::__get_singleton_state();
237 let plugin_state = plugin_state.read().unwrap();
238 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
239 plugin_state.leak_manager.free_leaked_memory();
240 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
241 let video_track = {
242 *handle
243 .current_video_track
244 .get()
245 .expect("unreachable: func_set_track should have been called before func_info_get")
246 };
247 let audio_track = {
248 *handle
249 .current_audio_track
250 .get()
251 .expect("unreachable: func_set_track should have been called before func_info_get")
252 };
253 let plugin = &plugin_state.instance;
254
255 match T::get_input_info(plugin, &mut handle.handle, video_track, audio_track) {
256 Ok(info) => {
257 handle.input_info = Some(info.clone());
258 if let Some(video_info) = info.video {
259 let fps = video_info.fps;
260 let num_frames = video_info.num_frames;
261 let manual_frame_index = video_info.manual_frame_index;
262 let width = video_info.width;
263 let height = video_info.height;
264 let image_format = video_info.into_raw();
265 unsafe {
266 (*iip).flag |= aviutl2_sys::input2::INPUT_INFO::FLAG_VIDEO;
267 if manual_frame_index {
268 (*iip).flag |= aviutl2_sys::input2::INPUT_INFO::FLAG_TIME_TO_FRAME;
269 }
270 (*iip).rate = *fps.numer();
271 (*iip).scale = *fps.denom();
272 (*iip).n = num_frames as _;
273 (*iip).format = plugin_state.leak_manager.leak(image_format);
274 (*iip).format_size = (4 * width * height) as i32; (*iip).audio_n = 0;
276 (*iip).audio_format = std::ptr::null_mut();
277 (*iip).audio_format_size = 0;
278 }
279 }
280
281 if let Some(audio_info) = info.audio {
282 let num_samples = audio_info.num_samples;
283 let audio_format = audio_info.into_raw();
284 let audio_format_size = std::mem::size_of_val(&audio_format) as i32;
285 unsafe {
286 (*iip).flag |= aviutl2_sys::input2::INPUT_INFO::FLAG_AUDIO;
287 (*iip).audio_n = num_samples as _;
288 (*iip).audio_format = plugin_state.leak_manager.leak(audio_format);
289 (*iip).audio_format_size = audio_format_size;
290 }
291 }
292
293 true
294 }
295 Err(e) => {
296 log::error!("Error during func_info_get: {}", e);
297 false
298 }
299 }
300}
301extern "C" fn func_read_video<T: InputSingleton>(
302 ih: aviutl2_sys::input2::INPUT_HANDLE,
303 frame: i32,
304 buf: *mut std::ffi::c_void,
305) -> i32 {
306 let plugin_state = T::__get_singleton_state();
307 let plugin_state = plugin_state.read().unwrap();
308 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
309 plugin_state.leak_manager.free_leaked_memory();
310 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
311 let plugin = &plugin_state.instance;
312 let frame = frame as u32;
313 let mut returner = unsafe { ImageReturner::new(buf as *mut u8) };
314 let read_result = if plugin_state.plugin_info.concurrent {
315 T::read_video(plugin, &handle.handle, frame, &mut returner)
316 } else {
317 T::read_video_mut(plugin, &mut handle.handle, frame, &mut returner)
318 };
319 match read_result {
320 Ok(()) => {
321 #[cfg(debug_assertions)]
322 {
323 let video_format = handle
324 .input_info
325 .as_ref()
326 .expect("Unreachable: Input info not set")
327 .video
328 .as_ref()
329 .expect("Unreachable: Video format not set");
330 assert_eq!(
331 returner.written,
332 ((video_format.width * video_format.height) as usize
333 * video_format.format.bytes_count_per_pixel()),
334 "Image data size does not match expected size"
335 );
336 }
337 returner.written as i32
338 }
339 Err(e) => {
340 log::error!("Error during func_read_video: {}", e);
341 0
342 }
343 }
344}
345
346extern "C" fn func_read_audio<T: InputSingleton>(
347 ih: aviutl2_sys::input2::INPUT_HANDLE,
348 start: i32,
349 length: i32,
350 buf: *mut std::ffi::c_void,
351) -> i32 {
352 let plugin_state = T::__get_singleton_state();
353 let plugin_state = plugin_state.read().unwrap();
354 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
355 plugin_state.leak_manager.free_leaked_memory();
356 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
357 let plugin = &plugin_state.instance;
358 let mut returner = unsafe { AudioReturner::new(buf as *mut u8) };
359 let read_result = if plugin_state.plugin_info.concurrent {
360 T::read_audio(plugin, &handle.handle, start, length, &mut returner)
361 } else {
362 T::read_audio_mut(plugin, &mut handle.handle, start, length, &mut returner)
363 };
364 match read_result {
365 Ok(()) => {
366 #[cfg(debug_assertions)]
367 {
368 let audio_format = handle
369 .input_info
370 .as_ref()
371 .expect("Unreachable: Input info not set")
372 .audio
373 .as_ref()
374 .expect("Unreachable: Audio format not set");
375 assert_eq!(
376 returner.written,
377 ((length as usize)
378 * (audio_format.channels as usize)
379 * audio_format.format.bytes_per_sample()),
380 "Audio data size does not match expected size"
381 );
382 }
383 returner.written as i32
384 }
385 Err(e) => {
386 log::error!("Error during func_read_audio: {}", e);
387 0
388 }
389 }
390}
391
392extern "C" fn func_config<T: InputSingleton>(
393 hwnd: aviutl2_sys::input2::HWND,
394 dll_hinst: aviutl2_sys::input2::HINSTANCE,
395) -> bool {
396 let plugin_state = T::__get_singleton_state();
397 let plugin_state = plugin_state.read().unwrap();
398 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
399 plugin_state.leak_manager.free_leaked_memory();
400 let mut handle =
401 raw_window_handle::Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
402 handle.hinstance = Some(NonZeroIsize::new(dll_hinst as isize).unwrap());
403 let plugin = &plugin_state.instance;
404 match plugin.config(handle) {
405 Ok(()) => true,
406 Err(e) => {
407 log::error!("Error during func_config: {}", e);
408 alert_error(&e);
409 false
410 }
411 }
412}
413extern "C" fn func_set_track<T: InputSingleton>(
414 ih: aviutl2_sys::input2::INPUT_HANDLE,
415 track_type: i32,
416 track: i32,
417) -> i32 {
418 let plugin_state = T::__get_singleton_state();
419 let plugin_state = plugin_state.read().unwrap();
420 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
421 plugin_state.leak_manager.free_leaked_memory();
422 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
423 let plugin = &plugin_state.instance;
424 if track == -1 {
425 if handle.num_tracks.lock().unwrap().is_none() {
427 let num_tracks = plugin.get_track_count(&mut handle.handle).map_err(|e| {
428 log::error!("Failed to get track count: {}", e);
429 e
430 });
431
432 if matches!(num_tracks, Ok((0, _))) {
433 handle
434 .current_video_track
435 .set(0)
436 .expect("unreachable: func_set_track should only be called once per handle");
437 }
438 if matches!(num_tracks, Ok((_, 0))) {
439 handle
440 .current_audio_track
441 .set(0)
442 .expect("unreachable: func_set_track should only be called once per handle");
443 }
444 *handle.num_tracks.lock().unwrap() = Some(num_tracks);
445 }
446 match &*handle.num_tracks.lock().unwrap() {
447 Some(Ok((video_tracks, audio_tracks))) => {
448 if track_type == aviutl2_sys::input2::INPUT_PLUGIN_TABLE::TRACK_TYPE_VIDEO {
449 *video_tracks as i32
450 } else if track_type == aviutl2_sys::input2::INPUT_PLUGIN_TABLE::TRACK_TYPE_AUDIO {
451 *audio_tracks as i32
452 } else {
453 log::error!("Invalid track type: {}", track_type);
454 -1 }
456 }
457 Some(Err(e)) => {
458 log::error!("Error occurred while getting track count: {}", e);
459 -1 }
461 None => {
462 unreachable!("Track count should have been initialized before this point");
463 }
464 }
465 } else {
466 match track_type {
468 aviutl2_sys::input2::INPUT_PLUGIN_TABLE::TRACK_TYPE_VIDEO => {
469 let new_track = plugin
470 .can_set_video_track(&mut handle.handle, track as u32)
471 .map_or_else(
472 |e| {
473 log::debug!("Failed to set video track: {}", e);
474 -1
475 },
476 |t| t as i32,
477 );
478 handle
479 .current_video_track
480 .set(new_track as u32)
481 .expect("unreachable: func_set_track should only be called once per handle");
482 new_track
483 }
484 aviutl2_sys::input2::INPUT_PLUGIN_TABLE::TRACK_TYPE_AUDIO => {
485 let new_track = plugin
486 .can_set_audio_track(&mut handle.handle, track as u32)
487 .map_or_else(
488 |e| {
489 log::debug!("Failed to set audio track: {}", e);
490 -1
491 },
492 |t| t as i32,
493 );
494 handle
495 .current_audio_track
496 .set(new_track as u32)
497 .expect("unreachable: func_set_track should only be called once per handle");
498 new_track
499 }
500 _ => -1, }
502 }
503}
504extern "C" fn func_time_to_frame<T: InputSingleton>(
505 ih: aviutl2_sys::input2::INPUT_HANDLE,
506 time: f64,
507) -> i32 {
508 let plugin_state = T::__get_singleton_state();
509 let plugin_state = plugin_state.read().unwrap();
510 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
511 plugin_state.leak_manager.free_leaked_memory();
512 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
513 let video_track = {
514 *handle
515 .current_video_track
516 .get()
517 .expect("unreachable: func_set_track should have been called before func_time_to_frame")
518 };
519 let plugin = &plugin_state.instance;
520 match T::time_to_frame(plugin, &mut handle.handle, video_track, time) {
521 Ok(frame) => frame as i32,
522 Err(e) => {
523 log::error!("Error during func_time_to_frame: {}", e);
524 0
525 }
526 }
527}
528
529pub trait InputSingleton
530where
531 Self: 'static + Send + Sync + InputPlugin,
532{
533 fn __get_singleton_state() -> &'static std::sync::RwLock<Option<InternalInputPluginState<Self>>>;
534 fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R {
535 let lock = Self::__get_singleton_state();
536 let guard = lock.read().unwrap();
537 let state = guard.as_ref().expect("Plugin not initialized");
538 f(&state.instance)
539 }
540 fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
541 let lock = Self::__get_singleton_state();
542 let mut guard = lock.write().unwrap();
543 let state = guard.as_mut().expect("Plugin not initialized");
544 f(&mut state.instance)
545 }
546}
547
548#[macro_export]
550macro_rules! register_input_plugin {
551 ($struct:ident) => {
552 ::aviutl2::__internal_module! {
553 #[unsafe(no_mangle)]
554 unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
555 $crate::logger::__initialize_logger(logger)
556 }
557
558 #[unsafe(no_mangle)]
559 unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
560 unsafe { $crate::input::__bridge::initialize_plugin_c::<$struct>(version) }
561 }
562
563 #[unsafe(no_mangle)]
564 unsafe extern "C" fn UninitializePlugin() {
565 unsafe { $crate::input::__bridge::uninitialize_plugin::<$struct>() }
566 }
567
568 #[unsafe(no_mangle)]
569 unsafe extern "C" fn GetInputPluginTable()
570 -> *mut aviutl2::sys::input2::INPUT_PLUGIN_TABLE {
571 unsafe { $crate::input::__bridge::create_table::<$struct>() }
572 }
573 }
574 };
575}