use crate::common::{AnyResult, FileFilter, Yc48};
pub use half::f16;
pub use num_rational::Rational32;
pub use raw_window_handle::Win32WindowHandle;
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: ImageFormat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ImageFormat {
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>);
pub trait IntoImage {
fn into_image(self) -> ImageBuffer;
}
impl IntoImage for ImageBuffer {
fn into_image(self) -> ImageBuffer {
self
}
}
impl IntoImage for Vec<u8> {
fn into_image(self) -> ImageBuffer {
ImageBuffer(self)
}
}
#[duplicate::duplicate_item(
T;
[Vec<u16>];
[Vec<i16>];
[Vec<f16>];
[Vec<Yc48>];
)]
impl IntoImage for T {
fn into_image(self) -> ImageBuffer {
let image_data = self.as_bytes().to_vec();
ImageBuffer(image_data)
}
}
macro_rules! into_image_impl_for_tuple {
($type:ty, $($name:ident),+) => {
impl IntoImage for Vec<$type> {
fn into_image(self) -> ImageBuffer {
let mut image_data = Vec::with_capacity(self.len() * std::mem::size_of::<$type>());
for ($($name,)+) in self {
$(image_data.extend_from_slice(&$name.to_le_bytes());)+
}
ImageBuffer(image_data)
}
}
};
}
into_image_impl_for_tuple!((u8, u8, u8), r, g, b);
into_image_impl_for_tuple!((u8, u8, u8, u8), r, g, b, a);
into_image_impl_for_tuple!((u16, u16, u16, u16), r, g, b, a);
into_image_impl_for_tuple!((f16, f16, f16, f16), r, g, b, a);
into_image_impl_for_tuple!((i16, i16, i16), y, cb, cr);
#[derive(Debug, Clone)]
pub struct AudioBuffer(pub Vec<u8>);
pub trait IntoAudio {
fn into_audio(self) -> AudioBuffer;
}
impl IntoAudio for AudioBuffer {
fn into_audio(self) -> AudioBuffer {
self
}
}
impl IntoAudio for Vec<u8> {
fn into_audio(self) -> AudioBuffer {
AudioBuffer(self)
}
}
#[duplicate::duplicate_item(
T;
[Vec<u16>];
[Vec<f32>];
)]
impl IntoAudio for T {
fn into_audio(self) -> AudioBuffer {
let audio_data = self.as_bytes().to_vec();
AudioBuffer(audio_data)
}
}
macro_rules! into_audio_impl_for_tuple {
($type:ty, $($name:ident),+) => {
impl IntoAudio for Vec<$type> {
fn into_audio(self) -> AudioBuffer {
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());)+
}
AudioBuffer(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 {
type InputHandle: std::any::Any + Send + Sync;
fn new() -> 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) -> AnyResult<impl IntoImage> {
Result::<ImageBuffer, anyhow::Error>::Err(anyhow::anyhow!(
"read_video is not implemented for this plugin"
))
}
fn read_video_mut(
&self,
handle: &mut Self::InputHandle,
frame: u32,
) -> AnyResult<impl IntoImage> {
self.read_video(handle, frame)
}
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,
) -> AnyResult<impl IntoAudio> {
Result::<AudioBuffer, 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,
) -> AnyResult<impl IntoAudio> {
self.read_audio(handle, start, length)
}
fn can_set_audio_track(&self, _handle: &mut Self::InputHandle, track: u32) -> AnyResult<u32> {
Ok(track)
}
fn config(&self, _hwnd: Win32WindowHandle) -> AnyResult<()> {
Ok(())
}
}