1use std::borrow::Cow;
2
3use crate::common::{FileFilter, Rational32, Yc48, f16};
4use zerocopy::IntoBytes;
5
6#[derive(Debug, Clone)]
8pub struct InputPluginTable {
9 pub name: String,
11 pub information: String,
14
15 pub input_type: InputType,
17 pub concurrent: bool,
27 pub file_filters: Vec<FileFilter>,
29
30 pub can_config: bool,
32}
33
34#[derive(Debug, Clone)]
36pub struct VideoInputInfo {
37 pub fps: Rational32,
39
40 pub num_frames: u32,
43
44 pub manual_frame_index: bool,
49
50 pub width: u32,
52 pub height: u32,
54
55 pub format: InputPixelFormat,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub enum InputPixelFormat {
62 Bgr,
76 Bgra,
88 Yuy2,
91 Pa64,
94 Yc48,
100 Hf64,
103}
104
105#[derive(Debug, Clone)]
107pub struct AudioInputInfo {
108 pub sample_rate: u32,
110 pub num_samples: u32,
112 pub channels: u16,
114
115 pub format: AudioFormat,
117}
118
119#[derive(Debug, Clone)]
121pub enum AudioFormat {
122 Pcm16,
124 IeeeFloat32,
126}
127
128#[derive(Debug, Clone)]
130pub struct InputInfo {
131 pub video: Option<VideoInputInfo>,
133 pub audio: Option<AudioInputInfo>,
135}
136
137#[derive(Debug, Clone)]
139pub enum InputType {
140 Video,
142 Audio,
144 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#[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
169pub 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
180pub 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 pub struct Name {
225 ptr: *mut u8,
226 capacity: usize,
227 pub(crate) written: usize,
228 }
229
230 impl Name {
231 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 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 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#[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
409pub 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
420pub 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
462pub trait InputPlugin: Send + Sync + Sized {
465 type InputHandle: std::any::Any + Send + Sync;
467
468 fn new(info: crate::common::AviUtl2Info) -> crate::common::AnyResult<Self>;
470
471 fn plugin_info(&self) -> crate::input::InputPluginTable;
473
474 fn open(&self, file: std::path::PathBuf) -> crate::common::AnyResult<Self::InputHandle>;
476 fn close(&self, handle: Self::InputHandle) -> crate::common::AnyResult<()>;
478
479 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 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 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 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 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 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; 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 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 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 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 fn config(&self, hwnd: crate::common::Win32WindowHandle) -> crate::common::AnyResult<()> {
625 let _ = hwnd;
626 Ok(())
627 }
628
629 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 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}