1use std::ffi::{CStr, c_char};
4use std::fmt::{self, Display};
5use std::ops::Deref;
6use std::ptr;
7use vapoursynth_sys as ffi;
8
9#[derive(Debug, Clone, Copy)]
11pub struct Format<'core> {
12 handle: &'core ffi::VSVideoFormat,
13}
14
15#[repr(i32)]
23#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
24pub enum PresetFormat {
25 None = 0,
26
27 Gray8 = make_video_id(ColorFamily::Gray, SampleType::Integer, 8, 0, 0),
28 Gray9 = make_video_id(ColorFamily::Gray, SampleType::Integer, 9, 0, 0),
29 Gray10 = make_video_id(ColorFamily::Gray, SampleType::Integer, 10, 0, 0),
30 Gray12 = make_video_id(ColorFamily::Gray, SampleType::Integer, 12, 0, 0),
31 Gray14 = make_video_id(ColorFamily::Gray, SampleType::Integer, 14, 0, 0),
32 Gray16 = make_video_id(ColorFamily::Gray, SampleType::Integer, 16, 0, 0),
33 Gray32 = make_video_id(ColorFamily::Gray, SampleType::Integer, 32, 0, 0),
34
35 GrayH = make_video_id(ColorFamily::Gray, SampleType::Float, 16, 0, 0),
36 GrayS = make_video_id(ColorFamily::Gray, SampleType::Float, 32, 0, 0),
37
38 YUV410P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 2, 2),
39 YUV411P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 2, 0),
40 YUV440P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 0, 1),
41
42 YUV420P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 1, 1),
43 YUV422P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 1, 0),
44 YUV444P8 = make_video_id(ColorFamily::YUV, SampleType::Integer, 8, 0, 0),
45
46 YUV420P9 = make_video_id(ColorFamily::YUV, SampleType::Integer, 9, 1, 1),
47 YUV422P9 = make_video_id(ColorFamily::YUV, SampleType::Integer, 9, 1, 0),
48 YUV444P9 = make_video_id(ColorFamily::YUV, SampleType::Integer, 9, 0, 0),
49
50 YUV420P10 = make_video_id(ColorFamily::YUV, SampleType::Integer, 10, 1, 1),
51 YUV422P10 = make_video_id(ColorFamily::YUV, SampleType::Integer, 10, 1, 0),
52 YUV444P10 = make_video_id(ColorFamily::YUV, SampleType::Integer, 10, 0, 0),
53
54 YUV420P12 = make_video_id(ColorFamily::YUV, SampleType::Integer, 12, 1, 1),
55 YUV422P12 = make_video_id(ColorFamily::YUV, SampleType::Integer, 12, 1, 0),
56 YUV444P12 = make_video_id(ColorFamily::YUV, SampleType::Integer, 12, 0, 0),
57
58 YUV420P14 = make_video_id(ColorFamily::YUV, SampleType::Integer, 14, 1, 1),
59 YUV422P14 = make_video_id(ColorFamily::YUV, SampleType::Integer, 14, 1, 0),
60 YUV444P14 = make_video_id(ColorFamily::YUV, SampleType::Integer, 14, 0, 0),
61
62 YUV420P16 = make_video_id(ColorFamily::YUV, SampleType::Integer, 16, 1, 1),
63 YUV422P16 = make_video_id(ColorFamily::YUV, SampleType::Integer, 16, 1, 0),
64 YUV444P16 = make_video_id(ColorFamily::YUV, SampleType::Integer, 16, 0, 0),
65
66 YUV420PH = make_video_id(ColorFamily::YUV, SampleType::Float, 16, 1, 1),
67 YUV420PS = make_video_id(ColorFamily::YUV, SampleType::Float, 32, 1, 1),
68 YUV422PH = make_video_id(ColorFamily::YUV, SampleType::Float, 16, 1, 0),
69 YUV422PS = make_video_id(ColorFamily::YUV, SampleType::Float, 32, 1, 0),
70 YUV444PH = make_video_id(ColorFamily::YUV, SampleType::Float, 16, 0, 0),
71 YUV444PS = make_video_id(ColorFamily::YUV, SampleType::Float, 32, 0, 0),
72
73 RGB24 = make_video_id(ColorFamily::RGB, SampleType::Integer, 8, 0, 0),
74 RGB27 = make_video_id(ColorFamily::RGB, SampleType::Integer, 9, 0, 0),
75 RGB30 = make_video_id(ColorFamily::RGB, SampleType::Integer, 10, 0, 0),
76 RGB36 = make_video_id(ColorFamily::RGB, SampleType::Integer, 12, 0, 0),
77 RGB42 = make_video_id(ColorFamily::RGB, SampleType::Integer, 14, 0, 0),
78 RGB48 = make_video_id(ColorFamily::RGB, SampleType::Integer, 16, 0, 0),
79
80 RGBH = make_video_id(ColorFamily::RGB, SampleType::Float, 16, 0, 0),
81 RGBS = make_video_id(ColorFamily::RGB, SampleType::Float, 32, 0, 0),
82}
83
84#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
86pub enum ColorFamily {
87 Undefined = 0,
88 Gray = 1,
89 RGB = 2,
90 YUV = 3,
91}
92
93#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
95pub enum SampleType {
96 Integer = 0,
97 Float = 1,
98}
99
100const fn make_video_id(
105 color_family: ColorFamily,
106 sample_type: SampleType,
107 bits_per_sample: i32,
108 sub_sampling_w: i32,
109 sub_sampling_h: i32,
110) -> i32 {
111 ((color_family as i32) << 28)
112 | ((sample_type as i32) << 24)
113 | (bits_per_sample << 16)
114 | (sub_sampling_w << 8)
115 | sub_sampling_h
116}
117
118#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
120pub struct FormatID(pub(crate) i32);
121
122impl<'core> PartialEq for Format<'core> {
123 #[inline]
124 fn eq(&self, other: &Format<'core>) -> bool {
125 self.id() == other.id()
126 }
127}
128
129impl<'core> Eq for Format<'core> {}
130
131#[doc(hidden)]
132impl<'core> Deref for Format<'core> {
133 type Target = ffi::VSVideoFormat;
134
135 #[inline]
137 fn deref(&self) -> &Self::Target {
138 self.handle
139 }
140}
141
142impl<'core> Format<'core> {
143 #[inline]
148 pub(crate) unsafe fn from_ptr(ptr: *const ffi::VSVideoFormat) -> Self {
149 Self { handle: &*ptr }
150 }
151
152 #[inline]
156 pub fn id(self) -> FormatID {
157 use crate::api::API;
158
159 unsafe {
161 let api = API::get_cached();
162 let id = api.query_video_format_id(
163 self.handle.colorFamily,
164 self.handle.sampleType,
165 self.handle.bitsPerSample,
166 self.handle.subSamplingW,
167 self.handle.subSamplingH,
168 ptr::null_mut(), );
170 FormatID(id as i32)
171 }
172 }
173
174 #[inline]
178 pub fn name(self) -> &'core str {
179 use crate::api::API;
180
181 const NAME_BUF_SIZE: usize = 64;
184 let mut buf = [0 as c_char; NAME_BUF_SIZE];
185
186 unsafe {
187 let api = API::get_cached();
188 api.get_video_format_name(self.handle as *const _, buf.as_mut_ptr());
189
190 let cstr = CStr::from_ptr(buf.as_ptr());
195 let string = cstr.to_str().unwrap().to_owned();
196 Box::leak(string.into_boxed_str())
197 }
198 }
199
200 #[inline]
202 pub fn plane_count(self) -> usize {
203 let plane_count = self.handle.numPlanes;
204 debug_assert!(plane_count >= 0);
205 plane_count as usize
206 }
207
208 #[inline]
210 pub fn color_family(self) -> ColorFamily {
211 match self.handle.colorFamily {
212 x if x == ffi::VSColorFamily_cfGray as i32 => ColorFamily::Gray,
213 x if x == ffi::VSColorFamily_cfRGB as i32 => ColorFamily::RGB,
214 x if x == ffi::VSColorFamily_cfYUV as i32 => ColorFamily::YUV,
215 _ => unreachable!(),
216 }
217 }
218
219 #[inline]
221 pub fn sample_type(self) -> SampleType {
222 match self.handle.sampleType {
223 x if x == ffi::VSSampleType_stInteger as i32 => SampleType::Integer,
224 x if x == ffi::VSSampleType_stFloat as i32 => SampleType::Float,
225 _ => unreachable!(),
226 }
227 }
228
229 #[inline]
231 pub fn bits_per_sample(self) -> u8 {
232 let rv = self.handle.bitsPerSample;
233 debug_assert!(rv >= 0 && rv <= i32::from(u8::MAX));
234 rv as u8
235 }
236
237 #[inline]
240 pub fn bytes_per_sample(self) -> u8 {
241 let rv = self.handle.bytesPerSample;
242 debug_assert!(rv >= 0 && rv <= i32::from(u8::MAX));
243 rv as u8
244 }
245
246 #[inline]
248 pub fn sub_sampling_w(self) -> u8 {
249 let rv = self.handle.subSamplingW;
250 debug_assert!(rv >= 0 && rv <= i32::from(u8::MAX));
251 rv as u8
252 }
253
254 #[inline]
256 pub fn sub_sampling_h(self) -> u8 {
257 let rv = self.handle.subSamplingH;
258 debug_assert!(rv >= 0 && rv <= i32::from(u8::MAX));
259 rv as u8
260 }
261}
262
263impl From<PresetFormat> for FormatID {
264 fn from(x: PresetFormat) -> Self {
265 FormatID(x as i32)
266 }
267}
268
269#[doc(hidden)]
270impl From<ColorFamily> for ffi::VSColorFamily {
271 #[inline]
272 fn from(x: ColorFamily) -> Self {
273 match x {
274 ColorFamily::Gray => ffi::VSColorFamily_cfGray,
275 ColorFamily::RGB => ffi::VSColorFamily_cfRGB,
276 ColorFamily::YUV => ffi::VSColorFamily_cfYUV,
277 ColorFamily::Undefined => ffi::VSColorFamily_cfUndefined,
278 }
279 }
280}
281
282#[doc(hidden)]
283impl From<SampleType> for ffi::VSSampleType {
284 #[inline]
285 fn from(x: SampleType) -> Self {
286 match x {
287 SampleType::Integer => ffi::VSSampleType_stInteger,
288 SampleType::Float => ffi::VSSampleType_stFloat,
289 }
290 }
291}
292
293impl Display for ColorFamily {
294 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
295 write!(
296 f,
297 "{}",
298 match *self {
299 ColorFamily::Gray => "Gray",
300 ColorFamily::RGB => "RGB",
301 ColorFamily::YUV => "YUV",
302 ColorFamily::Undefined => "Undefined",
303 }
304 )
305 }
306}
307
308impl Display for SampleType {
309 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
310 write!(
311 f,
312 "{}",
313 match *self {
314 SampleType::Integer => "Integer",
315 SampleType::Float => "Float",
316 }
317 )
318 }
319}
320
321impl From<i32> for FormatID {
322 fn from(x: i32) -> Self {
323 FormatID(x)
324 }
325}
326
327impl From<FormatID> for i32 {
328 fn from(x: FormatID) -> Self {
329 x.0
330 }
331}