use std::ffi::{CStr, c_char};
use std::fmt::{self, Display};
use std::ops::Deref;
use std::ptr;
use vapoursynth_sys as ffi;
#[derive(Debug, Clone, Copy)]
pub struct Format<'core> {
handle: &'core ffi::VSVideoFormat,
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum PresetFormat {
None = 0,
Gray8 = make_video_id(ColorFamily::Gray, SampleType::Integer, 8, 0, 0),
Gray9 = make_video_id(ColorFamily::Gray, SampleType::Integer, 9, 0, 0),
Gray10 = make_video_id(ColorFamily::Gray, SampleType::Integer, 10, 0, 0),
Gray12 = make_video_id(ColorFamily::Gray, SampleType::Integer, 12, 0, 0),
Gray14 = make_video_id(ColorFamily::Gray, SampleType::Integer, 14, 0, 0),
Gray16 = make_video_id(ColorFamily::Gray, SampleType::Integer, 16, 0, 0),
Gray32 = make_video_id(ColorFamily::Gray, SampleType::Integer, 32, 0, 0),
GrayH = make_video_id(ColorFamily::Gray, SampleType::Float, 16, 0, 0),
GrayS = make_video_id(ColorFamily::Gray, SampleType::Float, 32, 0, 0),
YUV410P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 2, 2),
YUV411P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 2, 0),
YUV440P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 0, 1),
YUV420P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 1, 1),
YUV422P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 1, 0),
YUV444P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 0, 0),
YUV420P9 = make_video_id(ColorFamily::YUV, SampleType::Integer, 9, 1, 1),
YUV422P9 = make_video_id(ColorFamily::YUV, SampleType::Integer, 9, 1, 0),
YUV444P9 = make_video_id(ColorFamily::YUV, SampleType::Integer, 9, 0, 0),
YUV420P10 = make_video_id(ColorFamily::YUV, SampleType::Integer, 10, 1, 1),
YUV422P10 = make_video_id(ColorFamily::YUV, SampleType::Integer, 10, 1, 0),
YUV444P10 = make_video_id(ColorFamily::YUV, SampleType::Integer, 10, 0, 0),
YUV420P12 = make_video_id(ColorFamily::YUV, SampleType::Integer, 12, 1, 1),
YUV422P12 = make_video_id(ColorFamily::YUV, SampleType::Integer, 12, 1, 0),
YUV444P12 = make_video_id(ColorFamily::YUV, SampleType::Integer, 12, 0, 0),
YUV420P14 = make_video_id(ColorFamily::YUV, SampleType::Integer, 14, 1, 1),
YUV422P14 = make_video_id(ColorFamily::YUV, SampleType::Integer, 14, 1, 0),
YUV444P14 = make_video_id(ColorFamily::YUV, SampleType::Integer, 14, 0, 0),
YUV420P16 = make_video_id(ColorFamily::YUV, SampleType::Integer, 16, 1, 1),
YUV422P16 = make_video_id(ColorFamily::YUV, SampleType::Integer, 16, 1, 0),
YUV444P16 = make_video_id(ColorFamily::YUV, SampleType::Integer, 16, 0, 0),
YUV420PH = make_video_id(ColorFamily::YUV, SampleType::Float, 16, 1, 1),
YUV420PS = make_video_id(ColorFamily::YUV, SampleType::Float, 32, 1, 1),
YUV422PH = make_video_id(ColorFamily::YUV, SampleType::Float, 16, 1, 0),
YUV422PS = make_video_id(ColorFamily::YUV, SampleType::Float, 32, 1, 0),
YUV444PH = make_video_id(ColorFamily::YUV, SampleType::Float, 16, 0, 0),
YUV444PS = make_video_id(ColorFamily::YUV, SampleType::Float, 32, 0, 0),
RGB24 = make_video_id(ColorFamily::RGB, SampleType::Integer, 8, 0, 0),
RGB27 = make_video_id(ColorFamily::RGB, SampleType::Integer, 9, 0, 0),
RGB30 = make_video_id(ColorFamily::RGB, SampleType::Integer, 10, 0, 0),
RGB36 = make_video_id(ColorFamily::RGB, SampleType::Integer, 12, 0, 0),
RGB42 = make_video_id(ColorFamily::RGB, SampleType::Integer, 14, 0, 0),
RGB48 = make_video_id(ColorFamily::RGB, SampleType::Integer, 16, 0, 0),
RGBH = make_video_id(ColorFamily::RGB, SampleType::Float, 16, 0, 0),
RGBS = make_video_id(ColorFamily::RGB, SampleType::Float, 32, 0, 0),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ColorFamily {
Undefined = 0,
Gray = 1,
RGB = 2,
YUV = 3,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum SampleType {
Integer = 0,
Float = 1,
}
const fn make_video_id(
color_family: ColorFamily,
sample_type: SampleType,
bits_per_sample: i32,
sub_sampling_w: i32,
sub_sampling_h: i32,
) -> i32 {
((color_family as i32) << 28)
| ((sample_type as i32) << 24)
| (bits_per_sample << 16)
| (sub_sampling_w << 8)
| sub_sampling_h
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct FormatID(pub(crate) i32);
impl<'core> PartialEq for Format<'core> {
#[inline]
fn eq(&self, other: &Format<'core>) -> bool {
self.id() == other.id()
}
}
impl<'core> Eq for Format<'core> {}
#[doc(hidden)]
impl<'core> Deref for Format<'core> {
type Target = ffi::VSVideoFormat;
#[inline]
fn deref(&self) -> &Self::Target {
self.handle
}
}
impl<'core> Format<'core> {
#[inline]
pub(crate) unsafe fn from_ptr(ptr: *const ffi::VSVideoFormat) -> Self {
Self { handle: &*ptr }
}
#[inline]
pub fn id(self) -> FormatID {
use crate::api::API;
unsafe {
let api = API::get_cached();
let id = api.query_video_format_id(
self.handle.colorFamily,
self.handle.sampleType,
self.handle.bitsPerSample,
self.handle.subSamplingW,
self.handle.subSamplingH,
ptr::null_mut(), );
FormatID(id as i32)
}
}
#[inline]
pub fn name(self) -> &'core str {
use crate::api::API;
const NAME_BUF_SIZE: usize = 64;
let mut buf = [0 as c_char; NAME_BUF_SIZE];
unsafe {
let api = API::get_cached();
api.get_video_format_name(self.handle as *const _, buf.as_mut_ptr());
let cstr = CStr::from_ptr(buf.as_ptr());
let string = cstr.to_str().unwrap().to_owned();
Box::leak(string.into_boxed_str())
}
}
#[inline]
pub fn plane_count(self) -> usize {
let plane_count = self.handle.numPlanes;
debug_assert!(plane_count >= 0);
plane_count as usize
}
#[inline]
pub fn color_family(self) -> ColorFamily {
match self.handle.colorFamily {
x if x == ffi::VSColorFamily_cfGray as i32 => ColorFamily::Gray,
x if x == ffi::VSColorFamily_cfRGB as i32 => ColorFamily::RGB,
x if x == ffi::VSColorFamily_cfYUV as i32 => ColorFamily::YUV,
_ => unreachable!(),
}
}
#[inline]
pub fn sample_type(self) -> SampleType {
match self.handle.sampleType {
x if x == ffi::VSSampleType_stInteger as i32 => SampleType::Integer,
x if x == ffi::VSSampleType_stFloat as i32 => SampleType::Float,
_ => unreachable!(),
}
}
#[inline]
pub fn bits_per_sample(self) -> u8 {
let rv = self.handle.bitsPerSample;
debug_assert!(rv >= 0 && rv <= i32::from(u8::MAX));
rv as u8
}
#[inline]
pub fn bytes_per_sample(self) -> u8 {
let rv = self.handle.bytesPerSample;
debug_assert!(rv >= 0 && rv <= i32::from(u8::MAX));
rv as u8
}
#[inline]
pub fn sub_sampling_w(self) -> u8 {
let rv = self.handle.subSamplingW;
debug_assert!(rv >= 0 && rv <= i32::from(u8::MAX));
rv as u8
}
#[inline]
pub fn sub_sampling_h(self) -> u8 {
let rv = self.handle.subSamplingH;
debug_assert!(rv >= 0 && rv <= i32::from(u8::MAX));
rv as u8
}
}
impl From<PresetFormat> for FormatID {
fn from(x: PresetFormat) -> Self {
FormatID(x as i32)
}
}
#[doc(hidden)]
impl From<ColorFamily> for ffi::VSColorFamily {
#[inline]
fn from(x: ColorFamily) -> Self {
match x {
ColorFamily::Gray => ffi::VSColorFamily_cfGray,
ColorFamily::RGB => ffi::VSColorFamily_cfRGB,
ColorFamily::YUV => ffi::VSColorFamily_cfYUV,
ColorFamily::Undefined => ffi::VSColorFamily_cfUndefined,
}
}
}
#[doc(hidden)]
impl From<SampleType> for ffi::VSSampleType {
#[inline]
fn from(x: SampleType) -> Self {
match x {
SampleType::Integer => ffi::VSSampleType_stInteger,
SampleType::Float => ffi::VSSampleType_stFloat,
}
}
}
impl Display for ColorFamily {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
f,
"{}",
match *self {
ColorFamily::Gray => "Gray",
ColorFamily::RGB => "RGB",
ColorFamily::YUV => "YUV",
ColorFamily::Undefined => "Undefined",
}
)
}
}
impl Display for SampleType {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
f,
"{}",
match *self {
SampleType::Integer => "Integer",
SampleType::Float => "Float",
}
)
}
}
impl From<i32> for FormatID {
fn from(x: i32) -> Self {
FormatID(x)
}
}
impl From<FormatID> for i32 {
fn from(x: FormatID) -> Self {
x.0
}
}