aviutl2\input/
binding.rs

1use std::borrow::Cow;
2
3use crate::common::{AnyResult, AviUtl2Info, FileFilter, Rational32, Win32WindowHandle, Yc48, f16};
4use zerocopy::IntoBytes;
5
6/// 入力プラグインの情報を表す構造体。
7#[derive(Debug, Clone)]
8pub struct InputPluginTable {
9    /// プラグインの名前。
10    pub name: String,
11    /// プラグインの情報。
12    /// 「プラグイン情報」ダイアログで表示されます。
13    pub information: String,
14
15    /// 入力の種類。
16    pub input_type: InputType,
17    /// 音声・動画の同時取得が可能かどうか。
18    ///
19    /// <div class="warning">
20    ///
21    /// このフラグによって、呼ばれるトレイトのメソッドが変わります。
22    /// `true` の場合は [`InputPlugin::read_video`] と [`InputPlugin::read_audio`] が呼ばれ、
23    /// `false` の場合は [`InputPlugin::read_video_mut`] と [`InputPlugin::read_audio_mut`] が呼ばれます。
24    ///
25    /// </div>
26    pub concurrent: bool,
27    /// プラグインがサポートするファイルフィルタのリスト。
28    pub file_filters: Vec<FileFilter>,
29
30    /// プラグインが設定可能かどうか。
31    pub can_config: bool,
32}
33
34/// 動画・画像の入力情報を表す構造体。
35#[derive(Debug, Clone)]
36pub struct VideoInputInfo {
37    /// 動画のフレームレート。
38    pub fps: Rational32,
39
40    /// 動画のフレーム数。
41    /// 画像の場合は1フレームとしてください。
42    pub num_frames: u32,
43
44    /// 動画のフレームを手動で算出するかどうか。
45    ///
46    /// # See Also
47    /// [`InputPlugin::time_to_frame`]
48    pub manual_frame_index: bool,
49
50    /// 画像の幅。
51    pub width: u32,
52    /// 画像の高さ。
53    pub height: u32,
54
55    /// 画像のフォーマット。
56    pub format: InputPixelFormat,
57}
58
59/// 画像のフォーマット。
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub enum InputPixelFormat {
62    /// RGB形式。
63    /// `(u8, u8, u8)`相当。
64    ///
65    /// <div class="warning">
66    ///
67    /// この形式では、左下から右上に向かって色が並びます。
68    ///
69    /// </div>
70    ///
71    /// # See Also
72    /// [`crate::utils::rgb_to_bgr`]
73    Bgr,
74    /// BGRA形式。
75    /// `(u8, u8, u8, u8)`相当。
76    ///
77    /// <div class="warning">
78    ///
79    /// この形式では、左下から右上に向かって色が並びます。
80    ///
81    /// </div>
82    ///
83    /// # See Also
84    /// [`crate::utils::rgba_to_bgra`]
85    Bgra,
86    /// YUV 4:2:2形式。
87    /// `(u8, u8, u8, u8)`相当。
88    Yuy2,
89    /// DXGI_FORMAT_R16G16B16A16_UNORM(乗算済みα)形式。
90    /// `(u16, u16, u16, u16)`相当。
91    Pa64,
92    /// YC48(互換対応の旧内部フォーマット)形式。
93    /// `(i16, i16, i16)`相当。
94    ///
95    /// # See Also
96    /// [`Yc48`]
97    Yc48,
98    /// DXGI_FORMAT_R16G16B16A16_FLOAT(乗算済みα)形式。
99    /// `(f16, f16, f16, f16)`相当。
100    Hf64,
101}
102
103/// 音声の入力情報を表す構造体。
104#[derive(Debug, Clone)]
105pub struct AudioInputInfo {
106    /// 音声のサンプルレート。
107    pub sample_rate: u32,
108    /// 音声のサンプル数。
109    pub num_samples: u32,
110    /// 音声のチャンネル数。
111    pub channels: u16,
112
113    /// 音声のフォーマット。
114    pub format: AudioFormat,
115}
116
117/// 音声のフォーマットを表す列挙型。
118#[derive(Debug, Clone)]
119pub enum AudioFormat {
120    /// PCM 16bit形式。
121    Pcm16,
122    /// IEEE Float 32bit形式。
123    IeeeFloat32,
124}
125
126/// 動画・画像と音声の入力情報をまとめた構造体。
127#[derive(Debug, Clone)]
128pub struct InputInfo {
129    /// 動画・画像のフォーマット。
130    pub video: Option<VideoInputInfo>,
131    /// 音声のフォーマット。
132    pub audio: Option<AudioInputInfo>,
133}
134
135/// 入力の種類を表す列挙型。
136#[derive(Debug, Clone)]
137pub enum InputType {
138    /// 動画のみ。
139    Video,
140    /// 音声のみ。
141    Audio,
142    /// 動画と音声の両方。
143    Both,
144}
145
146impl InputType {
147    pub(crate) fn to_bits(&self) -> i32 {
148        match self {
149            InputType::Video => 1,
150            InputType::Audio => 2,
151            InputType::Both => 3,
152        }
153    }
154}
155
156/// 画像のバッファを表す構造体。
157#[derive(Debug, Clone)]
158pub struct ImageBuffer(pub Vec<u8>);
159
160impl std::ops::Deref for ImageBuffer {
161    type Target = [u8];
162    fn deref(&self) -> &Self::Target {
163        &self.0
164    }
165}
166
167/// 画像データを `ImageBuffer` に変換するトレイト。
168pub trait IntoImage {
169    fn into_image(self) -> ImageBuffer;
170}
171
172impl<T: AsImage> IntoImage for T {
173    fn into_image(self) -> ImageBuffer {
174        ImageBuffer(self.as_image().into_owned())
175    }
176}
177
178/// 画像データを `Cow<[u8]>` に変換するトレイト。
179pub trait AsImage {
180    fn as_image(&'_ self) -> Cow<'_, [u8]>;
181}
182
183impl AsImage for ImageBuffer {
184    fn as_image(&'_ self) -> Cow<'_, [u8]> {
185        Cow::Borrowed(&self.0)
186    }
187}
188
189impl AsImage for Vec<u8> {
190    fn as_image(&'_ self) -> Cow<'_, [u8]> {
191        Cow::Borrowed(self)
192    }
193}
194
195impl AsImage for &[u8] {
196    fn as_image(&'_ self) -> Cow<'_, [u8]> {
197        Cow::Borrowed(self)
198    }
199}
200
201impl AsImage for Cow<'_, [u8]> {
202    fn as_image(&'_ self) -> Cow<'_, [u8]> {
203        match self {
204            Cow::Borrowed(b) => Cow::Borrowed(b),
205            Cow::Owned(b) => Cow::Borrowed(b),
206        }
207    }
208}
209
210duplicate::duplicate! {
211    [
212        Name            Trait     method;
213        [ImageReturner] [AsImage] [as_image];
214        [AudioReturner] [AsAudio] [as_audio];
215    ]
216    /// AviUtl2側にバイト列を返すためのstruct。
217    pub struct Name {
218        ptr: *mut u8,
219        pub(crate) written: usize,
220    }
221
222    impl Name {
223        /// # Safety
224        ///
225        /// AviUtl2側から渡されるポインタのみが許容される。
226        pub(crate) unsafe fn new(ptr: *mut u8) -> Self {
227            Self { ptr, written: 0 }
228        }
229
230        pub fn write(&mut self, data: &impl Trait) {
231            let image = data.method();
232            unsafe {
233                std::ptr::copy_nonoverlapping(image.as_ptr(), self.ptr.add(self.written), image.len());
234            }
235            self.written += image.len();
236        }
237    }
238}
239
240#[duplicate::duplicate_item(
241    T;
242    [Vec<u16>];
243    [Vec<i16>];
244    [Vec<f16>];
245    [Vec<Yc48>];
246)]
247impl AsImage for T {
248    fn as_image(&'_ self) -> Cow<'_, [u8]> {
249        Cow::Borrowed(self.as_bytes())
250    }
251}
252
253#[cfg(feature = "image")]
254impl AsImage for image::RgbImage {
255    fn as_image(&'_ self) -> Cow<'_, [u8]> {
256        let mut data = self.as_raw().to_owned();
257        crate::utils::bgr_to_rgb_bytes(&mut data);
258        crate::utils::flip_vertical(&mut data, self.width() as usize * 3, self.height() as usize);
259        Cow::Owned(data)
260    }
261}
262
263#[cfg(feature = "image")]
264impl AsImage for image::RgbaImage {
265    fn as_image(&'_ self) -> Cow<'_, [u8]> {
266        let mut data = self.as_raw().to_owned();
267        crate::utils::bgra_to_rgba_bytes(&mut data);
268        crate::utils::flip_vertical(&mut data, self.width() as usize * 4, self.height() as usize);
269        Cow::Owned(data)
270    }
271}
272
273#[cfg(feature = "image")]
274impl AsImage for image::ImageBuffer<image::Rgb<u16>, Vec<u16>> {
275    fn as_image(&'_ self) -> Cow<'_, [u8]> {
276        let data = self.as_raw();
277        Cow::Owned(data.as_bytes().to_vec())
278    }
279}
280
281#[cfg(feature = "image")]
282impl AsImage for image::ImageBuffer<image::Rgba<u16>, Vec<u16>> {
283    fn as_image(&'_ self) -> Cow<'_, [u8]> {
284        let data = self.as_raw();
285        Cow::Owned(data.as_bytes().to_vec())
286    }
287}
288
289macro_rules! as_image_impl_for_tuple {
290    ($type:ty, $($name:ident),+) => {
291        impl AsImage for Vec<$type> {
292            fn as_image(&'_ self) -> Cow<'_, [u8]> {
293                let mut img_data = Vec::with_capacity(self.len() * std::mem::size_of::<$type>());
294                for ($($name,)+) in self {
295                    $(img_data.extend_from_slice(&$name.to_le_bytes());)+
296                }
297                Cow::Owned(img_data)
298            }
299        }
300    };
301}
302
303as_image_impl_for_tuple!((u8, u8, u8), r, g, b);
304as_image_impl_for_tuple!((u8, u8, u8, u8), r, g, b, a);
305as_image_impl_for_tuple!((u16, u16, u16, u16), r, g, b, a);
306as_image_impl_for_tuple!((f16, f16, f16, f16), r, g, b, a);
307as_image_impl_for_tuple!((i16, i16, i16), y, cb, cr);
308
309/// 音声のバッファを表す構造体。
310#[derive(Debug, Clone)]
311pub struct AudioBuffer(pub Vec<u8>);
312
313impl std::ops::Deref for AudioBuffer {
314    type Target = [u8];
315    fn deref(&self) -> &Self::Target {
316        &self.0
317    }
318}
319
320/// 音声データを `AudioBuffer` に変換するトレイト。
321pub trait IntoAudio {
322    fn into_audio(self) -> AudioBuffer;
323}
324
325impl<T: AsAudio> IntoAudio for T {
326    fn into_audio(self) -> AudioBuffer {
327        AudioBuffer(self.as_audio().into_owned())
328    }
329}
330
331/// 音声データを `Cow<[u8]>` に変換するトレイト。
332pub trait AsAudio {
333    fn as_audio(&'_ self) -> Cow<'_, [u8]>;
334}
335
336impl AsAudio for AudioBuffer {
337    fn as_audio(&'_ self) -> Cow<'_, [u8]> {
338        Cow::Borrowed(&self.0)
339    }
340}
341impl AsAudio for Vec<u8> {
342    fn as_audio(&'_ self) -> Cow<'_, [u8]> {
343        Cow::Borrowed(self)
344    }
345}
346#[duplicate::duplicate_item(
347    T;
348    [Vec<u16>];
349    [Vec<f32>];
350)]
351impl AsAudio for T {
352    fn as_audio(&'_ self) -> Cow<'_, [u8]> {
353        Cow::Borrowed(self.as_bytes())
354    }
355}
356
357macro_rules! into_audio_impl_for_tuple {
358    ($type:ty, $($name:ident),+) => {
359        impl AsAudio for Vec<$type> {
360            fn as_audio(&'_ self) -> Cow<'_, [u8]> {
361                let mut audio_data = Vec::with_capacity(self.len() * std::mem::size_of::<$type>());
362                for ($($name,)+) in self {
363                    $(audio_data.extend_from_slice(&$name.to_le_bytes());)+
364                }
365                Cow::Owned(audio_data)
366            }
367        }
368    };
369}
370into_audio_impl_for_tuple!((u16, u16), l, r);
371into_audio_impl_for_tuple!((f32, f32), l, r);
372
373/// 入力プラグインのトレイト。
374/// このトレイトを実装し、[`crate::register_input_plugin!`] マクロを使用してプラグインを登録します。
375pub trait InputPlugin: Send + Sync + Sized {
376    /// 入力ハンドルの型。
377    type InputHandle: std::any::Any + Send + Sync;
378
379    /// プラグインを初期化する。
380    fn new(info: AviUtl2Info) -> AnyResult<Self>;
381
382    /// プラグインの情報を返す。
383    fn plugin_info(&self) -> InputPluginTable;
384
385    /// 入力を開く。
386    fn open(&self, file: std::path::PathBuf) -> AnyResult<Self::InputHandle>;
387    /// 入力を閉じる。
388    fn close(&self, handle: Self::InputHandle) -> AnyResult<()>;
389
390    /// 動画・音声のトラック数を取得する。
391    fn get_track_count(&self, handle: &mut Self::InputHandle) -> AnyResult<(u32, u32)> {
392        let info = self.get_input_info(handle, 0, 0)?;
393        let video_tracks = info.video.as_ref().map_or(0, |_| 1);
394        let audio_tracks = info.audio.as_ref().map_or(0, |_| 1);
395        Ok((video_tracks, audio_tracks))
396    }
397
398    /// 入力の情報を取得する。
399    fn get_input_info(
400        &self,
401        handle: &mut Self::InputHandle,
402        video_track: u32,
403        audio_track: u32,
404    ) -> AnyResult<InputInfo>;
405
406    /// 動画・画像を読み込む。
407    ///
408    /// <div class="warning">
409    ///
410    /// [`InputPluginTable::concurrent`] が `true` の場合に呼ばれます。
411    /// `false` の場合は [`Self::read_video_mut`] が呼ばれます。
412    ///
413    /// </div>
414    fn read_video(
415        &self,
416        handle: &Self::InputHandle,
417        frame: u32,
418        returner: &mut ImageReturner,
419    ) -> AnyResult<()> {
420        let _ = (handle, frame, returner);
421        Result::<(), anyhow::Error>::Err(anyhow::anyhow!(
422            "read_video is not implemented for this plugin"
423        ))
424    }
425
426    /// 動画・画像を読み込む。
427    ///
428    /// <div class="warning">
429    ///
430    /// [`InputPluginTable::concurrent`] が `false` の場合に呼ばれます。
431    /// `true` の場合は [`Self::read_video`] が呼ばれます。
432    ///
433    /// </div>
434    fn read_video_mut(
435        &self,
436        handle: &mut Self::InputHandle,
437        frame: u32,
438        returner: &mut ImageReturner,
439    ) -> AnyResult<()> {
440        self.read_video(handle, frame, returner)
441    }
442
443    /// 動画のトラックが利用可能かどうかを確認する。
444    ///
445    /// # Returns
446    /// トラック番号を返します。基本的には `track` をそのまま返します。
447    /// これがErrを返した場合、トラックの変更が失敗したものとして扱われます。
448    fn can_set_video_track(&self, _handle: &mut Self::InputHandle, track: u32) -> AnyResult<u32> {
449        Ok(track)
450    }
451
452    // TODO: これが他の関数と同時に呼ばれるかどうかは未検証なので、検証する(handleが `&mut` でいいかどうかに影響するため)
453    /// 現在の時刻からフレーム数を取得する。
454    /// [`VideoInputInfo::manual_frame_index`] が `true` の場合に使用されます。
455    fn time_to_frame(
456        &self,
457        handle: &mut Self::InputHandle,
458        track: u32,
459        time: f64,
460    ) -> AnyResult<u32> {
461        const RESOLUTION: i32 = 1000; // ミリ秒単位での解像度
462        let info = self.get_input_info(handle, track, 0)?;
463        if let Some(video_info) = &info.video {
464            Ok(
465                (video_info.fps * Rational32::new((time * RESOLUTION as f64) as i32, RESOLUTION))
466                    .to_integer() as u32,
467            )
468        } else {
469            Err(anyhow::anyhow!("No video information available"))
470        }
471    }
472
473    /// 音声を読み込む。
474    ///
475    /// <div class="warning">
476    ///
477    /// [`InputPluginTable::concurrent`] が `true` の場合に呼ばれます。
478    /// `false` の場合は [`Self::read_audio_mut`] が呼ばれます。
479    ///
480    /// </div>
481    fn read_audio(
482        &self,
483        handle: &Self::InputHandle,
484        start: i32,
485        length: i32,
486        returner: &mut AudioReturner,
487    ) -> AnyResult<()> {
488        let _ = (handle, start, length, returner);
489        Result::<(), anyhow::Error>::Err(anyhow::anyhow!(
490            "read_audio is not implemented for this plugin"
491        ))
492    }
493
494    /// 音声を読み込む。
495    ///
496    /// <div class="warning">
497    ///
498    /// [`InputPluginTable::concurrent`] が `false` の場合に呼ばれます。
499    /// `true` の場合は [`Self::read_audio`] が呼ばれます。
500    ///
501    /// </div>
502    fn read_audio_mut(
503        &self,
504        handle: &mut Self::InputHandle,
505        start: i32,
506        length: i32,
507        returner: &mut AudioReturner,
508    ) -> AnyResult<()> {
509        self.read_audio(handle, start, length, returner)
510    }
511
512    /// 音声のトラックが利用可能かどうかを確認する。
513    ///
514    /// # Returns
515    /// トラック番号を返します。基本的には `track` をそのまま返します。
516    /// これがErrを返した場合、トラックの変更が失敗したものとして扱われます。
517    fn can_set_audio_track(&self, _handle: &mut Self::InputHandle, track: u32) -> AnyResult<u32> {
518        Ok(track)
519    }
520
521    /// 設定ダイアログを表示する。
522    fn config(&self, _hwnd: Win32WindowHandle) -> AnyResult<()> {
523        Ok(())
524    }
525
526    /// シングルトンインスタンスを参照するためのヘルパーメソッド。
527    ///
528    /// # Panics
529    ///
530    /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。
531    fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R
532    where
533        Self: crate::input::__bridge::InputSingleton,
534    {
535        <Self as crate::input::__bridge::InputSingleton>::with_instance(f)
536    }
537
538    /// シングルトンインスタンスを可変参照するためのヘルパーメソッド。
539    ///
540    /// # Panics
541    ///
542    /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。
543    fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R
544    where
545        Self: crate::input::__bridge::InputSingleton,
546    {
547        <Self as crate::input::__bridge::InputSingleton>::with_instance_mut(f)
548    }
549}