1use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5use std::ptr::{self, NonNull};
6use std::slice;
7use vapoursynth_sys as ffi;
8
9use thiserror::Error;
10
11use crate::api::API;
12use crate::component::Component;
13use crate::core::CoreRef;
14use crate::format::Format;
15use crate::map::{MapRef, MapRefMut};
16use crate::video_info::Resolution;
17
18#[derive(Error, Debug, Clone, Copy, Eq, PartialEq)]
20#[error("Frame data has non-zero padding: {}", _0)]
21pub struct NonZeroPadding(usize);
22
23#[derive(Debug)]
26pub struct Frame<'core> {
27 handle: NonNull<ffi::VSFrame>,
29 format: Format<'core>,
31 _owner: PhantomData<&'core ()>,
32}
33
34#[derive(Debug)]
36pub struct FrameRef<'core> {
37 frame: Frame<'core>,
39}
40
41#[derive(Debug)]
43pub struct FrameRefMut<'core> {
44 frame: Frame<'core>,
46}
47
48unsafe impl<'core> Send for Frame<'core> {}
49unsafe impl<'core> Sync for Frame<'core> {}
50
51#[doc(hidden)]
52impl<'core> Deref for Frame<'core> {
53 type Target = ffi::VSFrame;
54
55 #[inline]
57 fn deref(&self) -> &Self::Target {
58 unsafe { self.handle.as_ref() }
59 }
60}
61
62#[doc(hidden)]
63impl<'core> DerefMut for Frame<'core> {
64 #[inline]
66 fn deref_mut(&mut self) -> &mut Self::Target {
67 unsafe { self.handle.as_mut() }
68 }
69}
70
71impl<'core> Drop for Frame<'core> {
72 #[inline]
73 fn drop(&mut self) {
74 unsafe {
75 API::get_cached().free_frame(self);
76 }
77 }
78}
79
80impl<'core> Clone for FrameRef<'core> {
81 #[inline]
82 fn clone(&self) -> Self {
83 unsafe {
84 let handle = API::get_cached().clone_frame(self);
85 Self {
86 frame: Frame::from_ptr(handle),
87 }
88 }
89 }
90}
91
92impl<'core> Deref for FrameRef<'core> {
93 type Target = Frame<'core>;
94
95 #[inline]
96 fn deref(&self) -> &Self::Target {
97 &self.frame
98 }
99}
100
101impl<'core> Deref for FrameRefMut<'core> {
102 type Target = Frame<'core>;
103
104 #[inline]
105 fn deref(&self) -> &Self::Target {
106 &self.frame
107 }
108}
109
110impl<'core> DerefMut for FrameRefMut<'core> {
111 #[inline]
112 fn deref_mut(&mut self) -> &mut Self::Target {
113 &mut self.frame
114 }
115}
116
117impl<'core> FrameRef<'core> {
118 #[inline]
123 pub(crate) unsafe fn from_ptr(handle: *const ffi::VSFrame) -> Self {
124 Self {
125 frame: Frame::from_ptr(handle),
126 }
127 }
128}
129
130impl<'core> FrameRefMut<'core> {
131 #[inline]
136 #[expect(dead_code)]
137 pub(crate) unsafe fn from_ptr(handle: *mut ffi::VSFrame) -> Self {
138 Self {
139 frame: Frame::from_ptr(handle),
140 }
141 }
142
143 #[inline]
149 pub fn copy_of(core: CoreRef, frame: &Frame<'core>) -> Self {
150 Self {
151 frame: unsafe { Frame::from_ptr(API::get_cached().copy_frame(frame, core.ptr())) },
152 }
153 }
154
155 #[inline]
166 pub unsafe fn new_uninitialized(
167 core: CoreRef<'core>,
168 prop_src: Option<&Frame<'core>>,
169 format: Format<'core>,
170 resolution: Resolution,
171 ) -> Self {
172 assert!(resolution.width <= i32::MAX as usize);
173 assert!(resolution.height <= i32::MAX as usize);
174
175 Self {
176 frame: unsafe {
177 Frame::from_ptr(API::get_cached().new_video_frame(
178 &format,
179 resolution.width as i32,
180 resolution.height as i32,
181 prop_src.map(|f| f.deref() as _).unwrap_or(ptr::null()),
182 core.ptr(),
183 ))
184 },
185 }
186 }
187}
188
189impl<'core> From<FrameRefMut<'core>> for FrameRef<'core> {
190 #[inline]
191 fn from(x: FrameRefMut<'core>) -> Self {
192 Self { frame: x.frame }
193 }
194}
195
196impl<'core> Frame<'core> {
197 #[inline]
204 pub(crate) unsafe fn from_ptr(handle: *const ffi::VSFrame) -> Self {
205 Self {
206 handle: NonNull::new_unchecked(handle as *mut ffi::VSFrame),
207 format: unsafe {
208 let ptr = API::get_cached().get_frame_format(&*handle);
209 Format::from_ptr(ptr)
210 },
211 _owner: PhantomData,
212 }
213 }
214
215 #[inline]
217 pub fn format(&self) -> Format<'core> {
218 self.format
219 }
220
221 #[inline]
228 pub fn width(&self, plane: usize) -> usize {
229 assert!(plane < self.format().plane_count());
230
231 unsafe { API::get_cached().get_frame_width(self, plane as i32) as usize }
232 }
233
234 #[inline]
241 pub fn height(&self, plane: usize) -> usize {
242 assert!(plane < self.format().plane_count());
243
244 unsafe { API::get_cached().get_frame_height(self, plane as i32) as usize }
245 }
246
247 #[inline]
254 pub fn resolution(&self, plane: usize) -> Resolution {
255 assert!(plane < self.format().plane_count());
256
257 Resolution {
258 width: self.width(plane),
259 height: self.height(plane),
260 }
261 }
262
263 #[inline]
268 pub fn stride(&self, plane: usize) -> usize {
269 assert!(plane < self.format().plane_count());
270
271 unsafe { API::get_cached().get_frame_stride(self, plane as i32) as usize }
272 }
273
274 #[inline]
279 pub fn plane_row<T: Component>(&self, plane: usize, row: usize) -> &[T] {
280 assert!(plane < self.format().plane_count());
281 assert!(row < self.height(plane));
282 assert!(T::is_valid(self.format()));
283
284 let stride = self.stride(plane);
285 let ptr = self.data_ptr(plane);
286
287 let offset = stride * row;
288 assert!(offset <= isize::MAX as usize);
289 let offset = offset as isize;
290
291 let row_ptr = unsafe { ptr.offset(offset) };
292 let width = self.width(plane);
293
294 unsafe { slice::from_raw_parts(row_ptr as *const T, width) }
295 }
296
297 #[inline]
302 pub fn plane_row_mut<T: Component>(&mut self, plane: usize, row: usize) -> &mut [T] {
303 assert!(plane < self.format().plane_count());
304 assert!(row < self.height(plane));
305 assert!(T::is_valid(self.format()));
306
307 let stride = self.stride(plane);
308 let ptr = self.data_ptr_mut(plane);
309
310 let offset = stride * row;
311 assert!(offset <= isize::MAX as usize);
312 let offset = offset as isize;
313
314 let row_ptr = unsafe { ptr.offset(offset) };
315 let width = self.width(plane);
316
317 unsafe { slice::from_raw_parts_mut(row_ptr as *mut T, width) }
318 }
319
320 pub fn plane<T: Component>(&self, plane: usize) -> Result<&[T], NonZeroPadding> {
329 assert!(plane < self.format().plane_count());
330 assert!(T::is_valid(self.format()));
331
332 let stride = self.stride(plane);
333 let width_in_bytes = self.width(plane) * usize::from(self.format().bytes_per_sample());
334 if stride != width_in_bytes {
335 return Err(NonZeroPadding(stride - width_in_bytes));
336 }
337
338 let height = self.height(plane);
339 let length = height * self.width(plane);
340 let ptr = self.data_ptr(plane);
341
342 Ok(unsafe { slice::from_raw_parts(ptr as *const T, length) })
343 }
344
345 pub fn plane_mut<T: Component>(&mut self, plane: usize) -> Result<&mut [T], NonZeroPadding> {
354 assert!(plane < self.format().plane_count());
355 assert!(T::is_valid(self.format()));
356
357 let stride = self.stride(plane);
358 let width_in_bytes = self.width(plane) * usize::from(self.format().bytes_per_sample());
359 if stride != width_in_bytes {
360 return Err(NonZeroPadding(stride - width_in_bytes));
361 }
362
363 let height = self.height(plane);
364 let length = height * self.width(plane);
365 let ptr = self.data_ptr_mut(plane);
366
367 Ok(unsafe { slice::from_raw_parts_mut(ptr as *mut T, length) })
368 }
369
370 #[inline]
378 pub fn data_ptr(&self, plane: usize) -> *const u8 {
379 assert!(plane < self.format().plane_count());
380
381 unsafe { API::get_cached().get_frame_read_ptr(self, plane as i32) }
382 }
383
384 #[inline]
392 pub fn data_ptr_mut(&mut self, plane: usize) -> *mut u8 {
393 assert!(plane < self.format().plane_count());
394
395 unsafe { API::get_cached().get_frame_write_ptr(self, plane as i32) }
396 }
397
398 pub fn data_row(&self, plane: usize, row: usize) -> &[u8] {
405 assert!(plane < self.format().plane_count());
406 assert!(row < self.height(plane));
407
408 let stride = self.stride(plane);
409 let ptr = self.data_ptr(plane);
410
411 let offset = stride * row;
412 assert!(offset <= isize::MAX as usize);
413 let offset = offset as isize;
414
415 let row_ptr = unsafe { ptr.offset(offset) };
416 let width = self.width(plane) * usize::from(self.format().bytes_per_sample());
417
418 unsafe { slice::from_raw_parts(row_ptr, width) }
419 }
420
421 pub fn data_row_mut(&mut self, plane: usize, row: usize) -> &mut [u8] {
428 assert!(plane < self.format().plane_count());
429 assert!(row < self.height(plane));
430
431 let stride = self.stride(plane);
432 let ptr = self.data_ptr_mut(plane);
433
434 let offset = stride * row;
435 assert!(offset <= isize::MAX as usize);
436 let offset = offset as isize;
437
438 let row_ptr = unsafe { ptr.offset(offset) };
439 let width = self.width(plane) * usize::from(self.format().bytes_per_sample());
440
441 unsafe { slice::from_raw_parts_mut(row_ptr, width) }
442 }
443
444 pub fn data(&self, plane: usize) -> Result<&[u8], NonZeroPadding> {
453 assert!(plane < self.format().plane_count());
454
455 let stride = self.stride(plane);
456 let width = self.width(plane) * usize::from(self.format().bytes_per_sample());
457 if stride != width {
458 return Err(NonZeroPadding(stride - width));
459 }
460
461 let height = self.height(plane);
462 let length = height * stride;
463 let ptr = self.data_ptr(plane);
464
465 Ok(unsafe { slice::from_raw_parts(ptr, length) })
466 }
467
468 pub fn data_mut(&mut self, plane: usize) -> Result<&mut [u8], NonZeroPadding> {
477 assert!(plane < self.format().plane_count());
478
479 let stride = self.stride(plane);
480 let width = self.width(plane) * usize::from(self.format().bytes_per_sample());
481 if stride != width {
482 return Err(NonZeroPadding(stride - width));
483 }
484
485 let height = self.height(plane);
486 let length = height * stride;
487 let ptr = self.data_ptr_mut(plane);
488
489 Ok(unsafe { slice::from_raw_parts_mut(ptr, length) })
490 }
491
492 #[inline]
494 pub fn props(&self) -> MapRef<'_, '_> {
495 unsafe { MapRef::from_ptr(API::get_cached().get_frame_props_ro(self)) }
496 }
497
498 #[inline]
500 pub fn props_mut(&mut self) -> MapRefMut<'_, '_> {
501 unsafe { MapRefMut::from_ptr(API::get_cached().get_frame_props_rw(self)) }
502 }
503}