use std::borrow::Cow;
use crate::common::{AnyResult, AviUtl2Info, FileFilter, Rational32, Win32WindowHandle, Yc48, f16};
use zerocopy::IntoBytes;
#[derive(Debug, Clone)]
pub struct InputPluginTable {
pub name: String,
pub information: String,
pub input_type: InputType,
pub concurrent: bool,
pub file_filters: Vec<FileFilter>,
pub can_config: bool,
}
#[derive(Debug, Clone)]
pub struct VideoInputInfo {
pub fps: Rational32,
pub num_frames: u32,
pub manual_frame_index: bool,
pub width: u32,
pub height: u32,
pub format: InputPixelFormat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum InputPixelFormat {
Bgr,
Bgra,
Yuy2,
Pa64,
Yc48,
Hf64,
}
#[derive(Debug, Clone)]
pub struct AudioInputInfo {
pub sample_rate: u32,
pub num_samples: u32,
pub channels: u16,
pub format: AudioFormat,
}
#[derive(Debug, Clone)]
pub enum AudioFormat {
Pcm16,
IeeeFloat32,
}
#[derive(Debug, Clone)]
pub struct InputInfo {
pub video: Option<VideoInputInfo>,
pub audio: Option<AudioInputInfo>,
}
#[derive(Debug, Clone)]
pub enum InputType {
Video,
Audio,
Both,
}
impl InputType {
pub(crate) fn to_bits(&self) -> i32 {
match self {
InputType::Video => 1,
InputType::Audio => 2,
InputType::Both => 3,
}
}
}
#[derive(Debug, Clone)]
pub struct ImageBuffer(pub Vec<u8>);
impl std::ops::Deref for ImageBuffer {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub trait IntoImage {
fn into_image(self) -> ImageBuffer;
}
impl<T: AsImage> IntoImage for T {
fn into_image(self) -> ImageBuffer {
ImageBuffer(self.as_image().into_owned())
}
}
pub trait AsImage {
fn as_image(&'_ self) -> Cow<'_, [u8]>;
}
impl AsImage for ImageBuffer {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
Cow::Borrowed(&self.0)
}
}
impl AsImage for Vec<u8> {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
Cow::Borrowed(self)
}
}
impl AsImage for &[u8] {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
Cow::Borrowed(self)
}
}
impl AsImage for Cow<'_, [u8]> {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
match self {
Cow::Borrowed(b) => Cow::Borrowed(b),
Cow::Owned(b) => Cow::Borrowed(b),
}
}
}
duplicate::duplicate! {
[
Name Trait method;
[ImageReturner] [AsImage] [as_image];
[AudioReturner] [AsAudio] [as_audio];
]
pub struct Name {
ptr: *mut u8,
pub(crate) written: usize,
}
impl Name {
pub(crate) unsafe fn new(ptr: *mut u8) -> Self {
Self { ptr, written: 0 }
}
pub fn write(&mut self, data: &impl Trait) {
let image = data.method();
unsafe {
std::ptr::copy_nonoverlapping(image.as_ptr(), self.ptr.add(self.written), image.len());
}
self.written += image.len();
}
}
}
#[duplicate::duplicate_item(
T;
[Vec<u16>];
[Vec<i16>];
[Vec<f16>];
[Vec<Yc48>];
)]
impl AsImage for T {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
Cow::Borrowed(self.as_bytes())
}
}
#[cfg(feature = "image")]
impl AsImage for image::RgbImage {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
let mut data = self.as_raw().to_owned();
crate::utils::bgr_to_rgb_bytes(&mut data);
crate::utils::flip_vertical(&mut data, self.width() as usize * 3, self.height() as usize);
Cow::Owned(data)
}
}
#[cfg(feature = "image")]
impl AsImage for image::RgbaImage {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
let mut data = self.as_raw().to_owned();
crate::utils::bgra_to_rgba_bytes(&mut data);
crate::utils::flip_vertical(&mut data, self.width() as usize * 4, self.height() as usize);
Cow::Owned(data)
}
}
#[cfg(feature = "image")]
impl AsImage for image::ImageBuffer<image::Rgb<u16>, Vec<u16>> {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
let data = self.as_raw();
Cow::Owned(data.as_bytes().to_vec())
}
}
#[cfg(feature = "image")]
impl AsImage for image::ImageBuffer<image::Rgba<u16>, Vec<u16>> {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
let data = self.as_raw();
Cow::Owned(data.as_bytes().to_vec())
}
}
macro_rules! as_image_impl_for_tuple {
($type:ty, $($name:ident),+) => {
impl AsImage for Vec<$type> {
fn as_image(&'_ self) -> Cow<'_, [u8]> {
let mut img_data = Vec::with_capacity(self.len() * std::mem::size_of::<$type>());
for ($($name,)+) in self {
$(img_data.extend_from_slice(&$name.to_le_bytes());)+
}
Cow::Owned(img_data)
}
}
};
}
as_image_impl_for_tuple!((u8, u8, u8), r, g, b);
as_image_impl_for_tuple!((u8, u8, u8, u8), r, g, b, a);
as_image_impl_for_tuple!((u16, u16, u16, u16), r, g, b, a);
as_image_impl_for_tuple!((f16, f16, f16, f16), r, g, b, a);
as_image_impl_for_tuple!((i16, i16, i16), y, cb, cr);
#[derive(Debug, Clone)]
pub struct AudioBuffer(pub Vec<u8>);
impl std::ops::Deref for AudioBuffer {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub trait IntoAudio {
fn into_audio(self) -> AudioBuffer;
}
impl<T: AsAudio> IntoAudio for T {
fn into_audio(self) -> AudioBuffer {
AudioBuffer(self.as_audio().into_owned())
}
}
pub trait AsAudio {
fn as_audio(&'_ self) -> Cow<'_, [u8]>;
}
impl AsAudio for AudioBuffer {
fn as_audio(&'_ self) -> Cow<'_, [u8]> {
Cow::Borrowed(&self.0)
}
}
impl AsAudio for Vec<u8> {
fn as_audio(&'_ self) -> Cow<'_, [u8]> {
Cow::Borrowed(self)
}
}
#[duplicate::duplicate_item(
T;
[Vec<u16>];
[Vec<f32>];
)]
impl AsAudio for T {
fn as_audio(&'_ self) -> Cow<'_, [u8]> {
Cow::Borrowed(self.as_bytes())
}
}
macro_rules! into_audio_impl_for_tuple {
($type:ty, $($name:ident),+) => {
impl AsAudio for Vec<$type> {
fn as_audio(&'_ self) -> Cow<'_, [u8]> {
let mut audio_data = Vec::with_capacity(self.len() * std::mem::size_of::<$type>());
for ($($name,)+) in self {
$(audio_data.extend_from_slice(&$name.to_le_bytes());)+
}
Cow::Owned(audio_data)
}
}
};
}
into_audio_impl_for_tuple!((u16, u16), l, r);
into_audio_impl_for_tuple!((f32, f32), l, r);
pub trait InputPlugin: Send + Sync + Sized {
type InputHandle: std::any::Any + Send + Sync;
fn new(info: AviUtl2Info) -> AnyResult<Self>;
fn plugin_info(&self) -> InputPluginTable;
fn open(&self, file: std::path::PathBuf) -> AnyResult<Self::InputHandle>;
fn close(&self, handle: Self::InputHandle) -> AnyResult<()>;
fn get_track_count(&self, handle: &mut Self::InputHandle) -> AnyResult<(u32, u32)> {
let info = self.get_input_info(handle, 0, 0)?;
let video_tracks = info.video.as_ref().map_or(0, |_| 1);
let audio_tracks = info.audio.as_ref().map_or(0, |_| 1);
Ok((video_tracks, audio_tracks))
}
fn get_input_info(
&self,
handle: &mut Self::InputHandle,
video_track: u32,
audio_track: u32,
) -> AnyResult<InputInfo>;
fn read_video(
&self,
handle: &Self::InputHandle,
frame: u32,
returner: &mut ImageReturner,
) -> AnyResult<()> {
let _ = (handle, frame, returner);
Result::<(), anyhow::Error>::Err(anyhow::anyhow!(
"read_video is not implemented for this plugin"
))
}
fn read_video_mut(
&self,
handle: &mut Self::InputHandle,
frame: u32,
returner: &mut ImageReturner,
) -> AnyResult<()> {
self.read_video(handle, frame, returner)
}
fn can_set_video_track(&self, _handle: &mut Self::InputHandle, track: u32) -> AnyResult<u32> {
Ok(track)
}
fn time_to_frame(
&self,
handle: &mut Self::InputHandle,
track: u32,
time: f64,
) -> AnyResult<u32> {
const RESOLUTION: i32 = 1000; let info = self.get_input_info(handle, track, 0)?;
if let Some(video_info) = &info.video {
Ok(
(video_info.fps * Rational32::new((time * RESOLUTION as f64) as i32, RESOLUTION))
.to_integer() as u32,
)
} else {
Err(anyhow::anyhow!("No video information available"))
}
}
fn read_audio(
&self,
handle: &Self::InputHandle,
start: i32,
length: i32,
returner: &mut AudioReturner,
) -> AnyResult<()> {
let _ = (handle, start, length, returner);
Result::<(), anyhow::Error>::Err(anyhow::anyhow!(
"read_audio is not implemented for this plugin"
))
}
fn read_audio_mut(
&self,
handle: &mut Self::InputHandle,
start: i32,
length: i32,
returner: &mut AudioReturner,
) -> AnyResult<()> {
self.read_audio(handle, start, length, returner)
}
fn can_set_audio_track(&self, _handle: &mut Self::InputHandle, track: u32) -> AnyResult<u32> {
Ok(track)
}
fn config(&self, _hwnd: Win32WindowHandle) -> AnyResult<()> {
Ok(())
}
fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R
where
Self: crate::input::__bridge::InputSingleton,
{
<Self as crate::input::__bridge::InputSingleton>::with_instance(f)
}
fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R
where
Self: crate::input::__bridge::InputSingleton,
{
<Self as crate::input::__bridge::InputSingleton>::with_instance_mut(f)
}
}