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    /// BGR24形式。
63    /// `(u8, u8, u8)`相当。
64    ///
65    /// <div class="warning">
66    ///
67    /// この形式では、左下から右上に向かって色が並びます。
68    /// 各行は4バイト境界に揃える必要があります。
69    /// 行末のパディングを含むバイト数は [`crate::utils::bgr_stride`] で取得できます。
70    ///
71    /// </div>
72    ///
73    /// # See Also
74    /// [`crate::utils::rgb_to_bgr`]
75    Bgr,
76    /// BGRA形式。
77    /// `(u8, u8, u8, u8)`相当。
78    ///
79    /// <div class="warning">
80    ///
81    /// この形式では、左下から右上に向かって色が並びます。
82    ///
83    /// </div>
84    ///
85    /// # See Also
86    /// [`crate::utils::rgba_to_bgra`]
87    Bgra,
88    /// YUV 4:2:2形式。
89    /// `(u8, u8, u8, u8)`相当。
90    Yuy2,
91    /// DXGI_FORMAT_R16G16B16A16_UNORM(乗算済みα)形式。
92    /// `(u16, u16, u16, u16)`相当。
93    Pa64,
94    /// YC48(互換対応の旧内部フォーマット)形式。
95    /// `(i16, i16, i16)`相当。
96    ///
97    /// # See Also
98    /// [`Yc48`]
99    Yc48,
100    /// DXGI_FORMAT_R16G16B16A16_FLOAT(乗算済みα)形式。
101    /// `(f16, f16, f16, f16)`相当。
102    Hf64,
103}
104
105/// 音声の入力情報を表す構造体。
106#[derive(Debug, Clone)]
107pub struct AudioInputInfo {
108    /// 音声のサンプルレート。
109    pub sample_rate: u32,
110    /// 音声のサンプル数。
111    pub num_samples: u32,
112    /// 音声のチャンネル数。
113    pub channels: u16,
114
115    /// 音声のフォーマット。
116    pub format: AudioFormat,
117}
118
119/// 音声のフォーマットを表す列挙型。
120#[derive(Debug, Clone)]
121pub enum AudioFormat {
122    /// PCM 16bit形式。
123    Pcm16,
124    /// IEEE Float 32bit形式。
125    IeeeFloat32,
126}
127
128/// 動画・画像と音声の入力情報をまとめた構造体。
129#[derive(Debug, Clone)]
130pub struct InputInfo {
131    /// 動画・画像のフォーマット。
132    pub video: Option<VideoInputInfo>,
133    /// 音声のフォーマット。
134    pub audio: Option<AudioInputInfo>,
135}
136
137/// 入力の種類を表す列挙型。
138#[derive(Debug, Clone)]
139pub enum InputType {
140    /// 動画のみ。
141    Video,
142    /// 音声のみ。
143    Audio,
144    /// 動画と音声の両方。
145    Both,
146}
147
148impl InputType {
149    pub(crate) fn to_bits(&self) -> i32 {
150        match self {
151            InputType::Video => 1,
152            InputType::Audio => 2,
153            InputType::Both => 3,
154        }
155    }
156}
157
158/// 画像のバッファを表す構造体。
159#[derive(Debug, Clone)]
160pub struct ImageBuffer(pub Vec<u8>);
161
162impl std::ops::Deref for ImageBuffer {
163    type Target = [u8];
164    fn deref(&self) -> &Self::Target {
165        &self.0
166    }
167}
168
169/// 画像データを `ImageBuffer` に変換するトレイト。
170pub trait IntoImage {
171    fn into_image(self) -> crate::input::ImageBuffer;
172}
173
174impl<T: AsImage> IntoImage for T {
175    fn into_image(self) -> ImageBuffer {
176        ImageBuffer(self.as_image().into_owned())
177    }
178}
179
180/// 画像データを `Cow<[u8]>` に変換するトレイト。
181///
182/// # Note
183///
184/// バイト列やタプル列には行末のパディングを自動追加しません。
185/// [`InputPixelFormat::Bgr`] では、呼び出し側で各行を4バイト境界に揃えてください。
186pub trait AsImage {
187    fn as_image(&'_ self) -> Cow<'_, [u8]>;
188}
189
190impl AsImage for ImageBuffer {
191    fn as_image(&'_ self) -> Cow<'_, [u8]> {
192        Cow::Borrowed(&self.0)
193    }
194}
195
196impl AsImage for Vec<u8> {
197    fn as_image(&'_ self) -> Cow<'_, [u8]> {
198        Cow::Borrowed(self)
199    }
200}
201
202impl AsImage for &[u8] {
203    fn as_image(&'_ self) -> Cow<'_, [u8]> {
204        Cow::Borrowed(self)
205    }
206}
207
208impl AsImage for Cow<'_, [u8]> {
209    fn as_image(&'_ self) -> Cow<'_, [u8]> {
210        match self {
211            Cow::Borrowed(b) => Cow::Borrowed(b),
212            Cow::Owned(b) => Cow::Borrowed(b),
213        }
214    }
215}
216
217duplicate::duplicate! {
218    [
219        Name            Trait     method;
220        [ImageReturner] [AsImage] [as_image];
221        [AudioReturner] [AsAudio] [as_audio];
222    ]
223    /// AviUtl2側にバイト列を返すためのstruct。
224    pub struct Name {
225        ptr: *mut u8,
226        capacity: usize,
227        pub(crate) written: usize,
228    }
229
230    impl Name {
231        /// # Safety
232        ///
233        /// `ptr` はAviUtl2側から渡された、`capacity` バイト書き込み可能な
234        /// バッファを指している必要があります。
235        pub(crate) unsafe fn new(ptr: *mut u8, capacity: usize) -> Self {
236            Self {
237                ptr,
238                capacity,
239                written: 0,
240            }
241        }
242
243        fn assert_writable(&self, len: usize) {
244            let remaining = self.capacity - self.written;
245            assert!(
246                len <= remaining,
247                "Output buffer overflow: attempted to write {len} bytes with {remaining} bytes remaining"
248            );
249        }
250
251        /// AviUtl2側の出力バッファに書き込む。
252        pub fn write(&mut self, data: &impl Trait) {
253            let image = data.method();
254            self.assert_writable(image.len());
255            unsafe {
256                std::ptr::copy_nonoverlapping(image.as_ptr(), self.ptr.add(self.written), image.len());
257            }
258            self.written += image.len();
259        }
260
261        /// AviUtl2側の出力バッファに直接書き込む。
262        ///
263        /// 書き込み処理が成功した場合のみ、書き込み済みサイズを更新します。
264        pub fn write_with<E>(
265            &mut self,
266            len: usize,
267            writer: impl FnOnce(&mut [u8]) -> Result<(), E>,
268        ) -> Result<(), E> {
269            self.assert_writable(len);
270            let buffer = unsafe {
271                std::slice::from_raw_parts_mut(self.ptr.add(self.written), len)
272            };
273            writer(buffer)?;
274            self.written += len;
275            Ok(())
276        }
277    }
278}
279
280#[cfg(test)]
281mod returner_tests {
282    use super::ImageReturner;
283
284    #[test]
285    fn write_with_writes_directly_and_updates_length() {
286        let mut output = [0u8; 4];
287        let mut returner = unsafe { ImageReturner::new(output.as_mut_ptr(), output.len()) };
288
289        returner
290            .write_with(output.len(), |destination| {
291                destination.copy_from_slice(&[1, 2, 3, 4]);
292                Ok::<(), ()>(())
293            })
294            .unwrap();
295
296        assert_eq!(returner.written, output.len());
297        assert_eq!(output, [1, 2, 3, 4]);
298    }
299
300    #[test]
301    #[should_panic(expected = "Output buffer overflow")]
302    fn write_rejects_data_larger_than_remaining_capacity() {
303        let mut output = [0u8; 4];
304        let mut returner = unsafe { ImageReturner::new(output.as_mut_ptr(), output.len()) };
305
306        returner.write(&vec![0u8; output.len() + 1]);
307    }
308
309    #[test]
310    #[should_panic(expected = "Output buffer overflow")]
311    fn write_with_rejects_length_larger_than_remaining_capacity() {
312        let mut output = [0u8; 4];
313        let mut returner = unsafe { ImageReturner::new(output.as_mut_ptr(), output.len()) };
314
315        returner
316            .write_with(output.len() + 1, |_| Ok::<(), ()>(()))
317            .unwrap();
318    }
319}
320
321#[duplicate::duplicate_item(
322    T;
323
324    [Vec<u16>];
325    [Vec<i16>];
326    [Vec<f16>];
327    [Vec<Yc48>];
328)]
329impl AsImage for T {
330    fn as_image(&'_ self) -> Cow<'_, [u8]> {
331        Cow::Borrowed(self.as_bytes())
332    }
333}
334
335#[cfg(feature = "image")]
336impl AsImage for image::RgbImage {
337    fn as_image(&'_ self) -> Cow<'_, [u8]> {
338        let row_bytes = self.width() as usize * 3;
339        let stride = crate::utils::bgr_stride(self.width() as usize);
340        let height = self.height() as usize;
341        let mut data = vec![0; stride * height];
342        for y in 0..height {
343            let source_start = (height - 1 - y) * row_bytes;
344            let row = &mut data[y * stride..y * stride + row_bytes];
345            row.copy_from_slice(&self.as_raw()[source_start..source_start + row_bytes]);
346            crate::utils::rgb_to_bgr_bytes(row);
347        }
348        Cow::Owned(data)
349    }
350}
351
352#[cfg(feature = "image")]
353impl AsImage for image::RgbaImage {
354    fn as_image(&'_ self) -> Cow<'_, [u8]> {
355        let mut data = self.as_raw().to_owned();
356        crate::utils::bgra_to_rgba_bytes(&mut data);
357        crate::utils::flip_vertical(&mut data, self.width() as usize * 4, self.height() as usize);
358        Cow::Owned(data)
359    }
360}
361
362#[cfg(feature = "image")]
363impl AsImage for image::ImageBuffer<image::Rgb<u16>, Vec<u16>> {
364    fn as_image(&'_ self) -> Cow<'_, [u8]> {
365        let data = self.as_raw();
366        Cow::Owned(data.as_bytes().to_vec())
367    }
368}
369
370#[cfg(feature = "image")]
371impl AsImage for image::ImageBuffer<image::Rgba<u16>, Vec<u16>> {
372    fn as_image(&'_ self) -> Cow<'_, [u8]> {
373        let data = self.as_raw();
374        Cow::Owned(data.as_bytes().to_vec())
375    }
376}
377
378macro_rules! as_image_impl_for_tuple {
379    ($type:ty, $($name:ident),+) => {
380        impl AsImage for Vec<$type> {
381            fn as_image(&'_ self) -> Cow<'_, [u8]> {
382                let mut img_data = Vec::with_capacity(self.len() * std::mem::size_of::<$type>());
383                for ($($name,)+) in self {
384                    $(img_data.extend_from_slice(&$name.to_le_bytes());)+
385                }
386                Cow::Owned(img_data)
387            }
388        }
389    };
390}
391
392as_image_impl_for_tuple!((u8, u8, u8), r, g, b);
393as_image_impl_for_tuple!((u8, u8, u8, u8), r, g, b, a);
394as_image_impl_for_tuple!((u16, u16, u16, u16), r, g, b, a);
395as_image_impl_for_tuple!((f16, f16, f16, f16), r, g, b, a);
396as_image_impl_for_tuple!((i16, i16, i16), y, cb, cr);
397
398/// 音声のバッファを表す構造体。
399#[derive(Debug, Clone)]
400pub struct AudioBuffer(pub Vec<u8>);
401
402impl std::ops::Deref for AudioBuffer {
403    type Target = [u8];
404    fn deref(&self) -> &Self::Target {
405        &self.0
406    }
407}
408
409/// 音声データを `AudioBuffer` に変換するトレイト。
410pub trait IntoAudio {
411    fn into_audio(self) -> crate::input::AudioBuffer;
412}
413
414impl<T: AsAudio> IntoAudio for T {
415    fn into_audio(self) -> AudioBuffer {
416        AudioBuffer(self.as_audio().into_owned())
417    }
418}
419
420/// 音声データを `Cow<[u8]>` に変換するトレイト。
421pub trait AsAudio {
422    fn as_audio(&'_ self) -> Cow<'_, [u8]>;
423}
424
425impl AsAudio for AudioBuffer {
426    fn as_audio(&'_ self) -> Cow<'_, [u8]> {
427        Cow::Borrowed(&self.0)
428    }
429}
430impl AsAudio for Vec<u8> {
431    fn as_audio(&'_ self) -> Cow<'_, [u8]> {
432        Cow::Borrowed(self)
433    }
434}
435#[duplicate::duplicate_item(
436    T;
437    [Vec<u16>];
438    [Vec<f32>];
439)]
440impl AsAudio for T {
441    fn as_audio(&'_ self) -> Cow<'_, [u8]> {
442        Cow::Borrowed(self.as_bytes())
443    }
444}
445
446macro_rules! into_audio_impl_for_tuple {
447    ($type:ty, $($name:ident),+) => {
448        impl AsAudio for Vec<$type> {
449            fn as_audio(&'_ self) -> Cow<'_, [u8]> {
450                let mut audio_data = Vec::with_capacity(self.len() * std::mem::size_of::<$type>());
451                for ($($name,)+) in self {
452                    $(audio_data.extend_from_slice(&$name.to_le_bytes());)+
453                }
454                Cow::Owned(audio_data)
455            }
456        }
457    };
458}
459into_audio_impl_for_tuple!((u16, u16), l, r);
460into_audio_impl_for_tuple!((f32, f32), l, r);
461
462/// 入力プラグインのトレイト。
463/// このトレイトを実装し、[`crate::register_input_plugin!`] マクロを使用してプラグインを登録します。
464pub trait InputPlugin: Send + Sync + Sized {
465    /// 入力ハンドルの型。
466    type InputHandle: std::any::Any + Send + Sync;
467
468    /// プラグインを初期化する。
469    fn new(info: crate::common::AviUtl2Info) -> crate::common::AnyResult<Self>;
470
471    /// プラグインの情報を返す。
472    fn plugin_info(&self) -> crate::input::InputPluginTable;
473
474    /// 入力を開く。
475    fn open(&self, file: std::path::PathBuf) -> crate::common::AnyResult<Self::InputHandle>;
476    /// 入力を閉じる。
477    fn close(&self, handle: Self::InputHandle) -> crate::common::AnyResult<()>;
478
479    /// 動画・音声のトラック数を取得する。
480    fn get_track_count(
481        &self,
482        handle: &mut Self::InputHandle,
483    ) -> crate::common::AnyResult<(u32, u32)> {
484        let info = self.get_input_info(handle, 0, 0)?;
485        let video_tracks = info.video.as_ref().map_or(0, |_| 1);
486        let audio_tracks = info.audio.as_ref().map_or(0, |_| 1);
487        Ok((video_tracks, audio_tracks))
488    }
489
490    /// 入力の情報を取得する。
491    fn get_input_info(
492        &self,
493        handle: &mut Self::InputHandle,
494        video_track: u32,
495        audio_track: u32,
496    ) -> crate::common::AnyResult<crate::input::InputInfo>;
497
498    /// 動画・画像を読み込む。
499    ///
500    /// <div class="warning">
501    ///
502    /// [`InputPluginTable::concurrent`] が `true` の場合に呼ばれます。
503    /// `false` の場合は [`Self::read_video_mut`] が呼ばれます。
504    ///
505    /// </div>
506    fn read_video(
507        &self,
508        handle: &Self::InputHandle,
509        frame: u32,
510        returner: &mut crate::input::ImageReturner,
511    ) -> crate::common::AnyResult<()> {
512        let _ = (handle, frame, returner);
513        Result::<(), anyhow::Error>::Err(anyhow::anyhow!(
514            "read_video is not implemented for this plugin"
515        ))
516    }
517
518    /// 動画・画像を読み込む。
519    ///
520    /// <div class="warning">
521    ///
522    /// [`InputPluginTable::concurrent`] が `false` の場合に呼ばれます。
523    /// `true` の場合は [`Self::read_video`] が呼ばれます。
524    ///
525    /// </div>
526    fn read_video_mut(
527        &self,
528        handle: &mut Self::InputHandle,
529        frame: u32,
530        returner: &mut crate::input::ImageReturner,
531    ) -> crate::common::AnyResult<()> {
532        self.read_video(handle, frame, returner)
533    }
534
535    /// 動画のトラックが利用可能かどうかを確認する。
536    ///
537    /// # Returns
538    /// トラック番号を返します。基本的には `track` をそのまま返します。
539    /// これがErrを返した場合、トラックの変更が失敗したものとして扱われます。
540    fn can_set_video_track(
541        &self,
542        handle: &mut Self::InputHandle,
543        track: u32,
544    ) -> crate::common::AnyResult<u32> {
545        let _ = handle;
546        Ok(track)
547    }
548
549    // TODO: これが他の関数と同時に呼ばれるかどうかは未検証なので、検証する(handleが `&mut` でいいかどうかに影響するため)
550    /// 現在の時刻からフレーム数を取得する。
551    /// [`VideoInputInfo::manual_frame_index`] が `true` の場合に使用されます。
552    fn time_to_frame(
553        &self,
554        handle: &mut Self::InputHandle,
555        track: u32,
556        time: f64,
557    ) -> crate::common::AnyResult<u32> {
558        const RESOLUTION: i32 = 1000; // ミリ秒単位での解像度
559        let info = self.get_input_info(handle, track, 0)?;
560        if let Some(video_info) = &info.video {
561            Ok(
562                (video_info.fps * Rational32::new((time * RESOLUTION as f64) as i32, RESOLUTION))
563                    .to_integer() as u32,
564            )
565        } else {
566            Err(anyhow::anyhow!("No video information available"))
567        }
568    }
569
570    /// 音声を読み込む。
571    ///
572    /// <div class="warning">
573    ///
574    /// [`InputPluginTable::concurrent`] が `true` の場合に呼ばれます。
575    /// `false` の場合は [`Self::read_audio_mut`] が呼ばれます。
576    ///
577    /// </div>
578    fn read_audio(
579        &self,
580        handle: &Self::InputHandle,
581        start: i32,
582        length: i32,
583        returner: &mut crate::input::AudioReturner,
584    ) -> crate::common::AnyResult<()> {
585        let _ = (handle, start, length, returner);
586        Result::<(), anyhow::Error>::Err(anyhow::anyhow!(
587            "read_audio is not implemented for this plugin"
588        ))
589    }
590
591    /// 音声を読み込む。
592    ///
593    /// <div class="warning">
594    ///
595    /// [`InputPluginTable::concurrent`] が `false` の場合に呼ばれます。
596    /// `true` の場合は [`Self::read_audio`] が呼ばれます。
597    ///
598    /// </div>
599    fn read_audio_mut(
600        &self,
601        handle: &mut Self::InputHandle,
602        start: i32,
603        length: i32,
604        returner: &mut crate::input::AudioReturner,
605    ) -> crate::common::AnyResult<()> {
606        self.read_audio(handle, start, length, returner)
607    }
608
609    /// 音声のトラックが利用可能かどうかを確認する。
610    ///
611    /// # Returns
612    /// トラック番号を返します。基本的には `track` をそのまま返します。
613    /// これがErrを返した場合、トラックの変更が失敗したものとして扱われます。
614    fn can_set_audio_track(
615        &self,
616        handle: &mut Self::InputHandle,
617        track: u32,
618    ) -> crate::common::AnyResult<u32> {
619        let _ = handle;
620        Ok(track)
621    }
622
623    /// 設定ダイアログを表示する。
624    fn config(&self, hwnd: crate::common::Win32WindowHandle) -> crate::common::AnyResult<()> {
625        let _ = hwnd;
626        Ok(())
627    }
628
629    /// シングルトンインスタンスを参照するためのヘルパーメソッド。
630    ///
631    /// # Panics
632    ///
633    /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。
634    fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R
635    where
636        Self: crate::input::__bridge::InputSingleton,
637    {
638        <Self as crate::input::__bridge::InputSingleton>::with_instance(f)
639    }
640
641    /// シングルトンインスタンスを可変参照するためのヘルパーメソッド。
642    ///
643    /// # Panics
644    ///
645    /// プラグインが初期化されていない場合や、二重に呼び出された場合にパニックします。
646    fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R
647    where
648        Self: crate::input::__bridge::InputSingleton,
649    {
650        <Self as crate::input::__bridge::InputSingleton>::with_instance_mut(f)
651    }
652}