Skip to main content

aviutl2\input/
binding.rs

1use std::borrow::Cow;
2
3use crate::common::{FileFilter, Rational32, 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) -> crate::input::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) -> crate::input::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: crate::common::AviUtl2Info) -> crate::common::AnyResult<Self>;
381
382    /// プラグインの情報を返す。
383    fn plugin_info(&self) -> crate::input::InputPluginTable;
384
385    /// 入力を開く。
386    fn open(&self, file: std::path::PathBuf) -> crate::common::AnyResult<Self::InputHandle>;
387    /// 入力を閉じる。
388    fn close(&self, handle: Self::InputHandle) -> crate::common::AnyResult<()>;
389
390    /// 動画・音声のトラック数を取得する。
391    fn get_track_count(
392        &self,
393        handle: &mut Self::InputHandle,
394    ) -> crate::common::AnyResult<(u32, u32)> {
395        let info = self.get_input_info(handle, 0, 0)?;
396        let video_tracks = info.video.as_ref().map_or(0, |_| 1);
397        let audio_tracks = info.audio.as_ref().map_or(0, |_| 1);
398        Ok((video_tracks, audio_tracks))
399    }
400
401    /// 入力の情報を取得する。
402    fn get_input_info(
403        &self,
404        handle: &mut Self::InputHandle,
405        video_track: u32,
406        audio_track: u32,
407    ) -> crate::common::AnyResult<crate::input::InputInfo>;
408
409    /// 動画・画像を読み込む。
410    ///
411    /// <div class="warning">
412    ///
413    /// [`InputPluginTable::concurrent`] が `true` の場合に呼ばれます。
414    /// `false` の場合は [`Self::read_video_mut`] が呼ばれます。
415    ///
416    /// </div>
417    fn read_video(
418        &self,
419        handle: &Self::InputHandle,
420        frame: u32,
421        returner: &mut crate::input::ImageReturner,
422    ) -> crate::common::AnyResult<()> {
423        let _ = (handle, frame, returner);
424        Result::<(), anyhow::Error>::Err(anyhow::anyhow!(
425            "read_video is not implemented for this plugin"
426        ))
427    }
428
429    /// 動画・画像を読み込む。
430    ///
431    /// <div class="warning">
432    ///
433    /// [`InputPluginTable::concurrent`] が `false` の場合に呼ばれます。
434    /// `true` の場合は [`Self::read_video`] が呼ばれます。
435    ///
436    /// </div>
437    fn read_video_mut(
438        &self,
439        handle: &mut Self::InputHandle,
440        frame: u32,
441        returner: &mut crate::input::ImageReturner,
442    ) -> crate::common::AnyResult<()> {
443        self.read_video(handle, frame, returner)
444    }
445
446    /// 動画のトラックが利用可能かどうかを確認する。
447    ///
448    /// # Returns
449    /// トラック番号を返します。基本的には `track` をそのまま返します。
450    /// これがErrを返した場合、トラックの変更が失敗したものとして扱われます。
451    fn can_set_video_track(
452        &self,
453        handle: &mut Self::InputHandle,
454        track: u32,
455    ) -> crate::common::AnyResult<u32> {
456        let _ = handle;
457        Ok(track)
458    }
459
460    // TODO: これが他の関数と同時に呼ばれるかどうかは未検証なので、検証する(handleが `&mut` でいいかどうかに影響するため)
461    /// 現在の時刻からフレーム数を取得する。
462    /// [`VideoInputInfo::manual_frame_index`] が `true` の場合に使用されます。
463    fn time_to_frame(
464        &self,
465        handle: &mut Self::InputHandle,
466        track: u32,
467        time: f64,
468    ) -> crate::common::AnyResult<u32> {
469        const RESOLUTION: i32 = 1000; // ミリ秒単位での解像度
470        let info = self.get_input_info(handle, track, 0)?;
471        if let Some(video_info) = &info.video {
472            Ok(
473                (video_info.fps * Rational32::new((time * RESOLUTION as f64) as i32, RESOLUTION))
474                    .to_integer() as u32,
475            )
476        } else {
477            Err(anyhow::anyhow!("No video information available"))
478        }
479    }
480
481    /// 音声を読み込む。
482    ///
483    /// <div class="warning">
484    ///
485    /// [`InputPluginTable::concurrent`] が `true` の場合に呼ばれます。
486    /// `false` の場合は [`Self::read_audio_mut`] が呼ばれます。
487    ///
488    /// </div>
489    fn read_audio(
490        &self,
491        handle: &Self::InputHandle,
492        start: i32,
493        length: i32,
494        returner: &mut crate::input::AudioReturner,
495    ) -> crate::common::AnyResult<()> {
496        let _ = (handle, start, length, returner);
497        Result::<(), anyhow::Error>::Err(anyhow::anyhow!(
498            "read_audio is not implemented for this plugin"
499        ))
500    }
501
502    /// 音声を読み込む。
503    ///
504    /// <div class="warning">
505    ///
506    /// [`InputPluginTable::concurrent`] が `false` の場合に呼ばれます。
507    /// `true` の場合は [`Self::read_audio`] が呼ばれます。
508    ///
509    /// </div>
510    fn read_audio_mut(
511        &self,
512        handle: &mut Self::InputHandle,
513        start: i32,
514        length: i32,
515        returner: &mut crate::input::AudioReturner,
516    ) -> crate::common::AnyResult<()> {
517        self.read_audio(handle, start, length, returner)
518    }
519
520    /// 音声のトラックが利用可能かどうかを確認する。
521    ///
522    /// # Returns
523    /// トラック番号を返します。基本的には `track` をそのまま返します。
524    /// これがErrを返した場合、トラックの変更が失敗したものとして扱われます。
525    fn can_set_audio_track(
526        &self,
527        handle: &mut Self::InputHandle,
528        track: u32,
529    ) -> crate::common::AnyResult<u32> {
530        let _ = handle;
531        Ok(track)
532    }
533
534    /// 設定ダイアログを表示する。
535    fn config(&self, hwnd: crate::common::Win32WindowHandle) -> crate::common::AnyResult<()> {
536        let _ = hwnd;
537        Ok(())
538    }
539
540    /// シングルトンインスタンスを参照するためのヘルパーメソッド。
541    ///
542    /// # Panics
543    ///
544    /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。
545    fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R
546    where
547        Self: crate::input::__bridge::InputSingleton,
548    {
549        <Self as crate::input::__bridge::InputSingleton>::with_instance(f)
550    }
551
552    /// シングルトンインスタンスを可変参照するためのヘルパーメソッド。
553    ///
554    /// # Panics
555    ///
556    /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。
557    fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R
558    where
559        Self: crate::input::__bridge::InputSingleton,
560    {
561        <Self as crate::input::__bridge::InputSingleton>::with_instance_mut(f)
562    }
563}