adaptivegrain/vapoursynth/src/format.rs
2019-05-30 11:06:53 +00:00

257 lines
7.0 KiB
Rust

//! VapourSynth frame formats.
use std::ffi::CStr;
use std::fmt::{self, Display};
use std::marker::PhantomData;
use std::ops::Deref;
use vapoursynth_sys as ffi;
/// Contains information about a video format.
#[derive(Debug, Clone, Copy)]
pub struct Format<'core> {
handle: &'core ffi::VSFormat,
}
/// Preset VapourSynth formats.
///
/// The presets suffixed with H and S have floating point sample type. The H and S suffixes stand
/// for half precision and single precision, respectively.
///
/// The compat formats are the only packed formats in VapourSynth. Everything else is planar. They
/// exist for compatibility with Avisynth plugins. They are not to be implemented in native
/// VapourSynth plugins.
#[cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum PresetFormat {
Gray8 = 1000010,
Gray16 = 1000011,
GrayH = 1000012,
GrayS = 1000013,
YUV420P8 = 3000010,
YUV422P8 = 3000011,
YUV444P8 = 3000012,
YUV410P8 = 3000013,
YUV411P8 = 3000014,
YUV440P8 = 3000015,
YUV420P9 = 3000016,
YUV422P9 = 3000017,
YUV444P9 = 3000018,
YUV420P10 = 3000019,
YUV422P10 = 3000020,
YUV444P10 = 3000021,
YUV420P16 = 3000022,
YUV422P16 = 3000023,
YUV444P16 = 3000024,
YUV444PH = 3000025,
YUV444PS = 3000026,
YUV420P12 = 3000027,
YUV422P12 = 3000028,
YUV444P12 = 3000029,
YUV420P14 = 3000030,
YUV422P14 = 3000031,
YUV444P14 = 3000032,
RGB24 = 2000010,
RGB27 = 2000011,
RGB30 = 2000012,
RGB48 = 2000013,
RGBH = 2000014,
RGBS = 2000015,
CompatBGR32 = 9000010,
CompatYUY2 = 9000011,
}
/// Format color families.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ColorFamily {
Gray,
RGB,
YUV,
YCoCg,
Compat,
}
/// Format sample types.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum SampleType {
Integer,
Float,
}
/// A unique format identifier.
#[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::VSFormat;
// Technically this should return `&'core`.
#[inline]
fn deref(&self) -> &Self::Target {
self.handle
}
}
impl<'core> Format<'core> {
/// Wraps a raw pointer in a `Format`.
///
/// # Safety
/// The caller must ensure `ptr` and the lifetime is valid.
#[inline]
pub(crate) unsafe fn from_ptr(ptr: *const ffi::VSFormat) -> Self {
Self { handle: &*ptr }
}
/// Gets the unique identifier of this format.
#[inline]
pub fn id(self) -> FormatID {
FormatID(self.handle.id)
}
/// Gets the printable name of this format.
#[inline]
pub fn name(self) -> &'core str {
unsafe { CStr::from_ptr(&self.handle.name as _).to_str().unwrap() }
}
/// Gets the number of planes of this format.
#[inline]
pub fn plane_count(self) -> usize {
let plane_count = self.handle.numPlanes;
debug_assert!(plane_count >= 0);
plane_count as usize
}
/// Gets the color family of this format.
#[inline]
pub fn color_family(self) -> ColorFamily {
match self.handle.colorFamily {
x if x == ffi::VSColorFamily::cmGray as i32 => ColorFamily::Gray,
x if x == ffi::VSColorFamily::cmRGB as i32 => ColorFamily::RGB,
x if x == ffi::VSColorFamily::cmYUV as i32 => ColorFamily::YUV,
x if x == ffi::VSColorFamily::cmYCoCg as i32 => ColorFamily::YCoCg,
x if x == ffi::VSColorFamily::cmCompat as i32 => ColorFamily::Compat,
_ => unreachable!(),
}
}
/// Gets the sample type of this format.
#[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!(),
}
}
/// Gets the number of significant bits per sample.
#[inline]
pub fn bits_per_sample(self) -> u8 {
let rv = self.handle.bitsPerSample;
debug_assert!(rv >= 0 && rv <= i32::from(u8::max_value()));
rv as u8
}
/// Gets the number of bytes needed for a sample. This is always a power of 2 and the smallest
/// possible that can fit the number of bits used per sample.
#[inline]
pub fn bytes_per_sample(self) -> u8 {
let rv = self.handle.bytesPerSample;
debug_assert!(rv >= 0 && rv <= i32::from(u8::max_value()));
rv as u8
}
/// log2 subsampling factor, applied to second and third plane.
#[inline]
pub fn sub_sampling_w(self) -> u8 {
let rv = self.handle.subSamplingW;
debug_assert!(rv >= 0 && rv <= i32::from(u8::max_value()));
rv as u8
}
/// log2 subsampling factor, applied to second and third plane.
#[inline]
pub fn sub_sampling_h(self) -> u8 {
let rv = self.handle.subSamplingH;
debug_assert!(rv >= 0 && rv <= i32::from(u8::max_value()));
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::cmGray,
ColorFamily::RGB => ffi::VSColorFamily::cmRGB,
ColorFamily::YUV => ffi::VSColorFamily::cmYUV,
ColorFamily::YCoCg => ffi::VSColorFamily::cmYCoCg,
ColorFamily::Compat => ffi::VSColorFamily::cmCompat,
}
}
}
#[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::YCoCg => "YCoCg",
ColorFamily::Compat => "Compat",
}
)
}
}
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)
}
}