1use std::num::NonZeroIsize;
2
3use crate::{
4 common::{AnyResult, LeakManager, 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 tracing::error!("Failed to initialize plugin: {}", e);
118 let _ = crate::logger::write_error_log(&format!("{e}"));
119 false
120 }
121 }
122}
123
124pub unsafe fn initialize_plugin_c_unwind<T: InputSingleton>(version: u32) -> bool {
125 match crate::utils::catch_unwind_with_panic_info(|| unsafe {
126 initialize_plugin_c::<T>(version)
127 }) {
128 Ok(result) => result,
129 Err(panic_info) => {
130 tracing::error!(
131 "Panic occurred during plugin initialization: {}",
132 panic_info
133 );
134 let _ = crate::logger::write_error_log(&panic_info);
135 false
136 }
137 }
138}
139
140pub(crate) fn initialize_plugin<T: InputSingleton>(version: u32) -> AnyResult<()> {
141 crate::common::ensure_minimum_aviutl2_version(version.into())?;
142 let plugin_state = T::__get_singleton_state();
143 let info = crate::common::AviUtl2Info {
144 version: version.into(),
145 };
146 let internal = T::new(info)?;
147 let plugin = InternalInputPluginState::new(internal);
148 *plugin_state.write().unwrap() = Some(plugin);
149
150 Ok(())
151}
152
153pub unsafe fn uninitialize_plugin<T: InputSingleton>() {
154 let plugin_state = T::__get_singleton_state();
155 let mut plugin_state = plugin_state.write().unwrap();
156 *plugin_state = None;
157}
158
159pub unsafe fn uninitialize_plugin_c_unwind<T: InputSingleton>() {
160 match crate::utils::catch_unwind_with_panic_info(|| unsafe { uninitialize_plugin::<T>() }) {
161 Ok(()) => {}
162 Err(panic_info) => {
163 tracing::error!(
164 "Panic occurred during plugin uninitialization: {}",
165 panic_info
166 );
167 let _ = crate::logger::write_error_log(&panic_info);
168 }
169 }
170}
171
172fn create_table_impl<T: InputSingleton>(
173 unwind: bool,
174) -> *mut aviutl2_sys::input2::INPUT_PLUGIN_TABLE {
175 let plugin_state = T::__get_singleton_state();
176 let mut plugin_state = plugin_state.write().unwrap();
177 let plugin_state = plugin_state.as_mut().expect("Plugin not initialized");
178 let plugin_info = &plugin_state.plugin_info;
179 let file_filter = format_file_filters(&plugin_info.file_filters);
180
181 let name = plugin_info.name.clone();
182 let information = plugin_info.information.clone();
183
184 let mut flag = plugin_info.input_type.to_bits();
185 if plugin_info.concurrent {
186 flag |= aviutl2_sys::input2::INPUT_PLUGIN_TABLE::FLAG_CONCURRENT;
187 }
188 flag |= aviutl2_sys::input2::INPUT_PLUGIN_TABLE::FLAG_MULTI_TRACK;
189
190 let func_open = if unwind {
191 func_open_unwind::<T>
192 } else {
193 func_open::<T>
194 };
195 let func_close = if unwind {
196 func_close_unwind::<T>
197 } else {
198 func_close::<T>
199 };
200 let func_info_get = if unwind {
201 func_info_get_unwind::<T>
202 } else {
203 func_info_get::<T>
204 };
205 let func_read_video = if unwind {
206 func_read_video_unwind::<T>
207 } else {
208 func_read_video::<T>
209 };
210 let func_read_audio = if unwind {
211 func_read_audio_unwind::<T>
212 } else {
213 func_read_audio::<T>
214 };
215 let func_config = if unwind {
216 func_config_unwind::<T>
217 } else {
218 func_config::<T>
219 };
220 let func_set_track = if unwind {
221 func_set_track_unwind::<T>
222 } else {
223 func_set_track::<T>
224 };
225 let func_time_to_frame = if unwind {
226 func_time_to_frame_unwind::<T>
227 } else {
228 func_time_to_frame::<T>
229 };
230
231 let table = aviutl2_sys::input2::INPUT_PLUGIN_TABLE {
233 flag,
234 name: plugin_state.global_leak_manager.leak_as_wide_string(&name),
235 filefilter: plugin_state
236 .global_leak_manager
237 .leak_as_wide_string(&file_filter),
238 information: plugin_state
239 .global_leak_manager
240 .leak_as_wide_string(&information),
241 func_open: Some(func_open),
242 func_close: Some(func_close),
243 func_info_get: Some(func_info_get),
244 func_read_video: Some(func_read_video),
245 func_read_audio: Some(func_read_audio),
246 func_config: plugin_info.can_config.then_some(func_config),
247 func_set_track: Some(func_set_track),
248 func_time_to_frame: Some(func_time_to_frame),
249 };
250 let table = Box::new(table);
251 Box::leak(table)
252}
253
254pub unsafe fn create_table<T: InputSingleton>() -> *mut aviutl2_sys::input2::INPUT_PLUGIN_TABLE {
255 create_table_impl::<T>(false)
256}
257
258pub unsafe fn create_table_unwind<T: InputSingleton>()
259-> *mut aviutl2_sys::input2::INPUT_PLUGIN_TABLE {
260 match crate::utils::catch_unwind_with_panic_info(|| create_table_impl::<T>(true)) {
261 Ok(table) => table,
262 Err(panic_info) => {
263 tracing::error!("Panic occurred during create_table: {}", panic_info);
264 let _ = crate::logger::write_error_log(&panic_info);
265 std::ptr::null_mut()
266 }
267 }
268}
269
270extern "C" fn func_open<T: InputSingleton>(
271 file: aviutl2_sys::common::LPCWSTR,
272) -> aviutl2_sys::input2::INPUT_HANDLE {
273 let plugin_state = T::__get_singleton_state();
274 let plugin_state = plugin_state.read().unwrap();
275 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
276 plugin_state.leak_manager.free_leaked_memory();
277 let path = unsafe { load_wide_string(file) };
278 tracing::info!("func_open called with path: {}", path);
279 let plugin = &plugin_state.instance;
280 match plugin.open(std::path::PathBuf::from(path)) {
281 Ok(handle) => {
282 let boxed_handle: Box<InternalInputHandle<T::InputHandle>> =
283 Box::new(InternalInputHandle {
284 input_info: None,
285 num_tracks: std::sync::Mutex::new(None),
286 current_video_track: std::sync::OnceLock::new(),
287 current_audio_track: std::sync::OnceLock::new(),
288 handle,
289 });
290 Box::into_raw(boxed_handle) as aviutl2_sys::input2::INPUT_HANDLE
291 }
292 Err(e) => {
293 tracing::error!("Error during func_open: {}", e);
294 std::ptr::null_mut()
295 }
296 }
297}
298extern "C" fn func_open_unwind<T: InputSingleton>(
299 file: aviutl2_sys::common::LPCWSTR,
300) -> aviutl2_sys::input2::INPUT_HANDLE {
301 match crate::utils::catch_unwind_with_panic_info(|| func_open::<T>(file)) {
302 Ok(handle) => handle,
303 Err(panic_info) => {
304 tracing::error!("Panic occurred during func_open: {}", panic_info);
305 let _ = crate::logger::write_error_log(&panic_info);
306 std::ptr::null_mut()
307 }
308 }
309}
310extern "C" fn func_close<T: InputSingleton>(ih: aviutl2_sys::input2::INPUT_HANDLE) -> bool {
311 let plugin_state = T::__get_singleton_state();
312 let plugin_state = plugin_state.read().unwrap();
313 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
314 plugin_state.leak_manager.free_leaked_memory();
315 let handle = unsafe { Box::from_raw(ih as *mut InternalInputHandle<T::InputHandle>) };
316 let plugin = &plugin_state.instance;
317 match plugin.close(handle.handle) {
318 Ok(()) => true,
319 Err(e) => {
320 tracing::error!("Error during func_close: {}", e);
321 false
322 }
323 }
324}
325extern "C" fn func_close_unwind<T: InputSingleton>(ih: aviutl2_sys::input2::INPUT_HANDLE) -> bool {
326 match crate::utils::catch_unwind_with_panic_info(|| func_close::<T>(ih)) {
327 Ok(result) => result,
328 Err(panic_info) => {
329 tracing::error!("Panic occurred during func_close: {}", panic_info);
330 let _ = crate::logger::write_error_log(&panic_info);
331 false
332 }
333 }
334}
335extern "C" fn func_info_get<T: InputSingleton>(
336 ih: aviutl2_sys::input2::INPUT_HANDLE,
337 iip: *mut aviutl2_sys::input2::INPUT_INFO,
338) -> bool {
339 let plugin_state = T::__get_singleton_state();
340 let plugin_state = plugin_state.read().unwrap();
341 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
342 plugin_state.leak_manager.free_leaked_memory();
343 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
344 let video_track = {
345 *handle
346 .current_video_track
347 .get()
348 .expect("unreachable: func_set_track should have been called before func_info_get")
349 };
350 let audio_track = {
351 *handle
352 .current_audio_track
353 .get()
354 .expect("unreachable: func_set_track should have been called before func_info_get")
355 };
356 let plugin = &plugin_state.instance;
357
358 match T::get_input_info(plugin, &mut handle.handle, video_track, audio_track) {
359 Ok(info) => {
360 handle.input_info = Some(info.clone());
361 if let Some(video_info) = info.video {
362 let fps = video_info.fps;
363 let num_frames = video_info.num_frames;
364 let manual_frame_index = video_info.manual_frame_index;
365 let width = video_info.width;
366 let height = video_info.height;
367 let image_format = video_info.into_raw();
368 unsafe {
369 (*iip).flag |= aviutl2_sys::input2::INPUT_INFO::FLAG_VIDEO;
370 if manual_frame_index {
371 (*iip).flag |= aviutl2_sys::input2::INPUT_INFO::FLAG_TIME_TO_FRAME;
372 }
373 (*iip).rate = *fps.numer();
374 (*iip).scale = *fps.denom();
375 (*iip).n = num_frames as _;
376 (*iip).format = plugin_state.leak_manager.leak(image_format);
377 (*iip).format_size = (4 * width * height) as i32; (*iip).audio_n = 0;
379 (*iip).audio_format = std::ptr::null_mut();
380 (*iip).audio_format_size = 0;
381 }
382 }
383
384 if let Some(audio_info) = info.audio {
385 let num_samples = audio_info.num_samples;
386 let audio_format = audio_info.into_raw();
387 let audio_format_size = std::mem::size_of_val(&audio_format) as i32;
388 unsafe {
389 (*iip).flag |= aviutl2_sys::input2::INPUT_INFO::FLAG_AUDIO;
390 (*iip).audio_n = num_samples as _;
391 (*iip).audio_format = plugin_state.leak_manager.leak(audio_format);
392 (*iip).audio_format_size = audio_format_size;
393 }
394 }
395
396 true
397 }
398 Err(e) => {
399 tracing::error!("Error during func_info_get: {}", e);
400 false
401 }
402 }
403}
404extern "C" fn func_info_get_unwind<T: InputSingleton>(
405 ih: aviutl2_sys::input2::INPUT_HANDLE,
406 iip: *mut aviutl2_sys::input2::INPUT_INFO,
407) -> bool {
408 match crate::utils::catch_unwind_with_panic_info(|| func_info_get::<T>(ih, iip)) {
409 Ok(result) => result,
410 Err(panic_info) => {
411 tracing::error!("Panic occurred during func_info_get: {}", panic_info);
412 let _ = crate::logger::write_error_log(&panic_info);
413 false
414 }
415 }
416}
417extern "C" fn func_read_video<T: InputSingleton>(
418 ih: aviutl2_sys::input2::INPUT_HANDLE,
419 frame: i32,
420 buf: *mut std::ffi::c_void,
421) -> i32 {
422 let plugin_state = T::__get_singleton_state();
423 let plugin_state = plugin_state.read().unwrap();
424 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
425 plugin_state.leak_manager.free_leaked_memory();
426 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
427 let plugin = &plugin_state.instance;
428 let frame = frame as u32;
429 let mut returner = unsafe { ImageReturner::new(buf as *mut u8) };
430 let read_result = if plugin_state.plugin_info.concurrent {
431 T::read_video(plugin, &handle.handle, frame, &mut returner)
432 } else {
433 T::read_video_mut(plugin, &mut handle.handle, frame, &mut returner)
434 };
435 match read_result {
436 Ok(()) => {
437 #[cfg(debug_assertions)]
438 {
439 let video_format = handle
440 .input_info
441 .as_ref()
442 .expect("Unreachable: Input info not set")
443 .video
444 .as_ref()
445 .expect("Unreachable: Video format not set");
446 assert_eq!(
447 returner.written,
448 ((video_format.width * video_format.height) as usize
449 * video_format.format.bytes_count_per_pixel()),
450 "Image data size does not match expected size"
451 );
452 }
453 returner.written as i32
454 }
455 Err(e) => {
456 tracing::error!("Error during func_read_video: {}", e);
457 0
458 }
459 }
460}
461
462extern "C" fn func_read_video_unwind<T: InputSingleton>(
463 ih: aviutl2_sys::input2::INPUT_HANDLE,
464 frame: i32,
465 buf: *mut std::ffi::c_void,
466) -> i32 {
467 match crate::utils::catch_unwind_with_panic_info(|| func_read_video::<T>(ih, frame, buf)) {
468 Ok(result) => result,
469 Err(panic_info) => {
470 tracing::error!("Panic occurred during func_read_video: {}", panic_info);
471 let _ = crate::logger::write_error_log(&panic_info);
472 0
473 }
474 }
475}
476
477extern "C" fn func_read_audio<T: InputSingleton>(
478 ih: aviutl2_sys::input2::INPUT_HANDLE,
479 start: i32,
480 length: i32,
481 buf: *mut std::ffi::c_void,
482) -> i32 {
483 let plugin_state = T::__get_singleton_state();
484 let plugin_state = plugin_state.read().unwrap();
485 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
486 plugin_state.leak_manager.free_leaked_memory();
487 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
488 let plugin = &plugin_state.instance;
489 let mut returner = unsafe { AudioReturner::new(buf as *mut u8) };
490 let read_result = if plugin_state.plugin_info.concurrent {
491 T::read_audio(plugin, &handle.handle, start, length, &mut returner)
492 } else {
493 T::read_audio_mut(plugin, &mut handle.handle, start, length, &mut returner)
494 };
495 match read_result {
496 Ok(()) => {
497 #[cfg(debug_assertions)]
498 {
499 let audio_format = handle
500 .input_info
501 .as_ref()
502 .expect("Unreachable: Input info not set")
503 .audio
504 .as_ref()
505 .expect("Unreachable: Audio format not set");
506 assert_eq!(
507 returner.written,
508 ((length as usize)
509 * (audio_format.channels as usize)
510 * audio_format.format.bytes_per_sample()),
511 "Audio data size does not match expected size"
512 );
513 }
514 returner.written as i32
515 }
516 Err(e) => {
517 tracing::error!("Error during func_read_audio: {}", e);
518 0
519 }
520 }
521}
522
523extern "C" fn func_read_audio_unwind<T: InputSingleton>(
524 ih: aviutl2_sys::input2::INPUT_HANDLE,
525 start: i32,
526 length: i32,
527 buf: *mut std::ffi::c_void,
528) -> i32 {
529 match crate::utils::catch_unwind_with_panic_info(|| {
530 func_read_audio::<T>(ih, start, length, buf)
531 }) {
532 Ok(result) => result,
533 Err(panic_info) => {
534 tracing::error!("Panic occurred during func_read_audio: {}", panic_info);
535 let _ = crate::logger::write_error_log(&panic_info);
536 0
537 }
538 }
539}
540
541extern "C" fn func_config<T: InputSingleton>(
542 hwnd: aviutl2_sys::input2::HWND,
543 dll_hinst: aviutl2_sys::input2::HINSTANCE,
544) -> bool {
545 let plugin_state = T::__get_singleton_state();
546 let plugin_state = plugin_state.read().unwrap();
547 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
548 plugin_state.leak_manager.free_leaked_memory();
549 let mut handle =
550 raw_window_handle::Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
551 handle.hinstance = Some(NonZeroIsize::new(dll_hinst as isize).unwrap());
552 let plugin = &plugin_state.instance;
553 match plugin.config(handle) {
554 Ok(()) => true,
555 Err(e) => {
556 tracing::error!("Error during func_config: {}", e);
557 let _ = crate::logger::write_error_log(&format!("{e}"));
558 false
559 }
560 }
561}
562extern "C" fn func_config_unwind<T: InputSingleton>(
563 hwnd: aviutl2_sys::input2::HWND,
564 dll_hinst: aviutl2_sys::input2::HINSTANCE,
565) -> bool {
566 match crate::utils::catch_unwind_with_panic_info(|| func_config::<T>(hwnd, dll_hinst)) {
567 Ok(result) => result,
568 Err(panic_info) => {
569 tracing::error!("Panic occurred during func_config: {}", panic_info);
570 let _ = crate::logger::write_error_log(&panic_info);
571 false
572 }
573 }
574}
575extern "C" fn func_set_track<T: InputSingleton>(
576 ih: aviutl2_sys::input2::INPUT_HANDLE,
577 track_type: i32,
578 track: i32,
579) -> i32 {
580 let plugin_state = T::__get_singleton_state();
581 let plugin_state = plugin_state.read().unwrap();
582 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
583 plugin_state.leak_manager.free_leaked_memory();
584 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
585 let plugin = &plugin_state.instance;
586 if track == -1 {
587 if handle.num_tracks.lock().unwrap().is_none() {
589 let num_tracks = plugin.get_track_count(&mut handle.handle).map_err(|e| {
590 tracing::error!("Failed to get track count: {}", e);
591 e
592 });
593
594 if matches!(num_tracks, Ok((0, _))) {
595 handle
596 .current_video_track
597 .set(0)
598 .expect("unreachable: func_set_track should only be called once per handle");
599 }
600 if matches!(num_tracks, Ok((_, 0))) {
601 handle
602 .current_audio_track
603 .set(0)
604 .expect("unreachable: func_set_track should only be called once per handle");
605 }
606 *handle.num_tracks.lock().unwrap() = Some(num_tracks);
607 }
608 match &*handle.num_tracks.lock().unwrap() {
609 Some(Ok((video_tracks, audio_tracks))) => {
610 if track_type == aviutl2_sys::input2::INPUT_PLUGIN_TABLE::TRACK_TYPE_VIDEO {
611 *video_tracks as i32
612 } else if track_type == aviutl2_sys::input2::INPUT_PLUGIN_TABLE::TRACK_TYPE_AUDIO {
613 *audio_tracks as i32
614 } else {
615 tracing::error!("Invalid track type: {}", track_type);
616 -1 }
618 }
619 Some(Err(e)) => {
620 tracing::error!("Error occurred while getting track count: {}", e);
621 -1 }
623 None => {
624 unreachable!("Track count should have been initialized before this point");
625 }
626 }
627 } else {
628 match track_type {
630 aviutl2_sys::input2::INPUT_PLUGIN_TABLE::TRACK_TYPE_VIDEO => {
631 let new_track = plugin
632 .can_set_video_track(&mut handle.handle, track as u32)
633 .map_or_else(
634 |e| {
635 tracing::debug!("Failed to set video track: {}", e);
636 -1
637 },
638 |t| t as i32,
639 );
640 handle
641 .current_video_track
642 .set(new_track as u32)
643 .expect("unreachable: func_set_track should only be called once per handle");
644 new_track
645 }
646 aviutl2_sys::input2::INPUT_PLUGIN_TABLE::TRACK_TYPE_AUDIO => {
647 let new_track = plugin
648 .can_set_audio_track(&mut handle.handle, track as u32)
649 .map_or_else(
650 |e| {
651 tracing::debug!("Failed to set audio track: {}", e);
652 -1
653 },
654 |t| t as i32,
655 );
656 handle
657 .current_audio_track
658 .set(new_track as u32)
659 .expect("unreachable: func_set_track should only be called once per handle");
660 new_track
661 }
662 _ => -1, }
664 }
665}
666extern "C" fn func_set_track_unwind<T: InputSingleton>(
667 ih: aviutl2_sys::input2::INPUT_HANDLE,
668 track_type: i32,
669 track: i32,
670) -> i32 {
671 match crate::utils::catch_unwind_with_panic_info(|| func_set_track::<T>(ih, track_type, track))
672 {
673 Ok(result) => result,
674 Err(panic_info) => {
675 tracing::error!("Panic occurred during func_set_track: {}", panic_info);
676 let _ = crate::logger::write_error_log(&panic_info);
677 -1
678 }
679 }
680}
681extern "C" fn func_time_to_frame<T: InputSingleton>(
682 ih: aviutl2_sys::input2::INPUT_HANDLE,
683 time: f64,
684) -> i32 {
685 let plugin_state = T::__get_singleton_state();
686 let plugin_state = plugin_state.read().unwrap();
687 let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
688 plugin_state.leak_manager.free_leaked_memory();
689 let handle = unsafe { &mut *(ih as *mut InternalInputHandle<T::InputHandle>) };
690 let video_track = {
691 *handle
692 .current_video_track
693 .get()
694 .expect("unreachable: func_set_track should have been called before func_time_to_frame")
695 };
696 let plugin = &plugin_state.instance;
697 match T::time_to_frame(plugin, &mut handle.handle, video_track, time) {
698 Ok(frame) => frame as i32,
699 Err(e) => {
700 tracing::error!("Error during func_time_to_frame: {}", e);
701 0
702 }
703 }
704}
705extern "C" fn func_time_to_frame_unwind<T: InputSingleton>(
706 ih: aviutl2_sys::input2::INPUT_HANDLE,
707 time: f64,
708) -> i32 {
709 match crate::utils::catch_unwind_with_panic_info(|| func_time_to_frame::<T>(ih, time)) {
710 Ok(result) => result,
711 Err(panic_info) => {
712 tracing::error!("Panic occurred during func_time_to_frame: {}", panic_info);
713 let _ = crate::logger::write_error_log(&panic_info);
714 0
715 }
716 }
717}
718
719pub trait InputSingleton
720where
721 Self: 'static + Send + Sync + crate::input::InputPlugin,
722{
723 fn __get_singleton_state()
724 -> &'static std::sync::RwLock<Option<crate::input::__bridge::InternalInputPluginState<Self>>>;
725 fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R {
726 let lock = Self::__get_singleton_state();
727 let guard = lock.read().unwrap();
728 let state = guard.as_ref().expect("Plugin not initialized");
729 f(&state.instance)
730 }
731 fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
732 let lock = Self::__get_singleton_state();
733 let mut guard = lock.write().unwrap();
734 let state = guard.as_mut().expect("Plugin not initialized");
735 f(&mut state.instance)
736 }
737}
738
739#[macro_export]
771macro_rules! register_input_plugin {
772 ($struct:ident, $($key:ident = $value:expr),* $(,)?) => {
773 $crate::__internal_module! {
774 #[unsafe(no_mangle)]
775 unsafe extern "C" fn RequiredVersion() -> u32 {
776 $crate::MINIMUM_AVIUTL2_VERSION.into()
777 }
778
779 #[unsafe(no_mangle)]
780 unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
781 $crate::comptime_if::comptime_if! {
782 if unwind where (unwind = true, $( $key = $value ),* ) {
783 $crate::logger::__initialize_logger_unwind(logger)
784 } else {
785 $crate::logger::__initialize_logger(logger)
786 }
787 }
788 }
789
790 #[unsafe(no_mangle)]
791 unsafe extern "C" fn InitializeConfig(
792 config: *mut $crate::sys::config2::CONFIG_HANDLE
793 ) {
794 $crate::comptime_if::comptime_if! {
795 if unwind where (unwind = true, $( $key = $value ),* ) {
796 $crate::config::__initialize_config_handle_unwind(config)
797 } else {
798 $crate::config::__initialize_config_handle(config)
799 }
800 }
801 }
802
803 #[unsafe(no_mangle)]
804 unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
805 unsafe {
806 $crate::comptime_if::comptime_if! {
807 if unwind where (unwind = true, $( $key = $value ),* ) {
808 $crate::input::__bridge::initialize_plugin_c_unwind::<$struct>(version)
809 } else {
810 $crate::input::__bridge::initialize_plugin_c::<$struct>(version)
811 }
812 }
813 }
814 }
815
816 #[unsafe(no_mangle)]
817 unsafe extern "C" fn UninitializePlugin() {
818 unsafe {
819 $crate::comptime_if::comptime_if! {
820 if unwind where (unwind = true, $( $key = $value ),* ) {
821 $crate::input::__bridge::uninitialize_plugin_c_unwind::<$struct>()
822 } else {
823 $crate::input::__bridge::uninitialize_plugin::<$struct>()
824 }
825 }
826 }
827 }
828
829 #[unsafe(no_mangle)]
830 unsafe extern "C" fn GetInputPluginTable()
831 -> *mut aviutl2::sys::input2::INPUT_PLUGIN_TABLE {
832 $crate::comptime_if::comptime_if! {
833 if unwind where (unwind = true, $( $key = $value ),* ) {
834 unsafe { $crate::input::__bridge::create_table_unwind::<$struct>() }
835 } else {
836 unsafe { $crate::input::__bridge::create_table::<$struct>() }
837 }
838 }
839 }
840 }
841 };
842 ($struct:ident, $($key:ident),* $(,)?) => {
843 $crate::register_input_plugin!($struct, $( $key = true ),* );
844 };
845 ($struct:ident) => {
846 $crate::register_input_plugin!($struct, );
847 };
848}