aviutl2\input/
bridge.rs

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,  // RGB format
15            InputPixelFormat::Bgra => 4, // RGBA format
16            InputPixelFormat::Yuy2 => 2, // YUY2 format (packed YUV 4:2:2, 4 bytes per 2 pixels)
17            InputPixelFormat::Pa64 => 8, // DXGI_FORMAT_R16G16B16A16_UNORM (packed 16-bit per channel)
18            InputPixelFormat::Hf64 => 8, // DXGI_FORMAT_R16G16B16A16_FLOAT (half-float)
19            InputPixelFormat::Yc48 => 6, // YC48 (AviUtl1)
20        }
21    }
22}
23
24impl AudioFormat {
25    fn bytes_per_sample(&self) -> usize {
26        match self {
27            AudioFormat::IeeeFloat32 => 4, // 32-bit float
28            AudioFormat::Pcm16 => 2,       // 16-bit PCM
29        }
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        // NOTE:
44        // biHeightをマイナスにしてBI_RGBでも上からにするやつは使えない(AviUtが落ちる)
45        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, // Bits per pixel
51            biCompression: bi_compression,
52            biSizeImage: (self.width * self.height * self.format.bytes_count_per_pixel() as u32),
53            biXPelsPerMeter: 0, // Not used
54            biYPelsPerMeter: 0, // Not used
55            biClrUsed: 0,       // Not used
56            biClrImportant: 0,  // Not used
57        }
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, // No extra data
79        }
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    // NOTE: プラグイン名などの文字列はAviUtlが終了するまで解放しない
167    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; // 4 bytes per pixel for RGBA
275                    (*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        // track == -1:トラック数取得
426        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 // Invalid track type
455                }
456            }
457            Some(Err(e)) => {
458                log::error!("Error occurred while getting track count: {}", e);
459                -1 // Error occurred
460            }
461            None => {
462                unreachable!("Track count should have been initialized before this point");
463            }
464        }
465    } else {
466        // track != -1:トラック設定
467        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, // Invalid track type
501        }
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/// 入力プラグインを登録するマクロ。
549#[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}