1mod dependency;
8mod filter;
9pub(crate) mod internal;
10
11use std::ffi::{CStr, CString};
12
13use crate::{
14 AudioInfo, VideoInfo,
15 api::Api,
16 core::Core,
17 ffi,
18 frame::{AudioFrame, Frame, FrameContext, VideoFrame, internal::FrameFromPtr},
19 node::internal::FilterExtern,
20};
21
22pub use dependency::*;
23pub use filter::*;
24
25pub trait Node: Sized + crate::_private::Sealed {
26 type FrameType: Frame;
27
28 fn api(&self) -> Api;
29
30 #[must_use]
31 fn as_ptr(&self) -> *mut ffi::VSNode;
32
33 #[must_use]
34 fn get_frame_filter(&self, n: i32, ctx: &mut FrameContext) -> Self::FrameType;
35
36 fn set_linear_filter(&mut self) -> i32 {
37 unsafe { (self.api().setLinearFilter)(self.as_ptr()) }
38 }
39
40 fn set_cache_mode(&mut self, mode: CacheMode) {
41 unsafe {
42 (self.api().setCacheMode)(self.as_ptr(), mode);
43 }
44 }
45
46 fn set_cache_options(&mut self, fixed_size: i32, max_size: i32, max_history_size: i32) {
47 unsafe {
48 (self.api().setCacheOptions)(self.as_ptr(), fixed_size, max_size, max_history_size);
49 }
50 }
51
52 fn get_frame(&self, n: i32) -> Result<Self::FrameType, CString> {
56 let mut buf = vec![0; 1024];
57 let ptr = unsafe { (self.api().getFrame)(n, self.as_ptr(), buf.as_mut_ptr(), 1024) };
58
59 if ptr.is_null() {
60 let mut buf = std::mem::ManuallyDrop::new(buf);
61 Err(unsafe { CStr::from_ptr(buf.as_mut_ptr()).into() })
62 } else {
63 unsafe { Ok(Self::FrameType::from_ptr(ptr, self.api())) }
64 }
65 }
66
67 fn get_frame_async<D, F, Fr>(&self, _n: i32, _data: &mut D)
69 where
70 F: Fn(D, Fr, i32) -> Result<(), String>,
71 Fr: Frame,
72 {
73 todo!()
74 }
75}
76
77#[derive(Debug, PartialEq, Eq, Hash)]
78pub struct VideoNode {
79 handle: *const ffi::VSNode,
80 api: Api,
81}
82
83impl crate::_private::Sealed for VideoNode {}
84impl Node for VideoNode {
85 type FrameType = VideoFrame;
86
87 #[inline]
88 fn api(&self) -> Api {
89 self.api
90 }
91
92 #[must_use]
93 #[inline]
94 fn as_ptr(&self) -> *mut ffi::VSNode {
95 self.handle.cast_mut()
96 }
97
98 #[must_use]
99 fn get_frame_filter(&self, n: i32, ctx: &mut FrameContext) -> Self::FrameType {
100 unsafe {
101 VideoFrame::from_ptr(
102 (self.api.getFrameFilter)(n, self.as_ptr(), ctx.as_ptr()),
103 self.api,
104 )
105 }
106 }
107}
108
109impl VideoNode {
110 #[must_use]
114 pub unsafe fn from_ptr(ptr: *mut ffi::VSNode, api: Api) -> Self {
115 Self { handle: ptr, api }
116 }
117
118 #[must_use]
119 pub fn info(&self) -> &VideoInfo {
120 unsafe { &*(self.api.getVideoInfo)(self.as_ptr()) }
122 }
123
124 pub fn new<F: Filter>(
128 name: &str,
129 info: &VideoInfo,
130 filter: F,
131 dependencies: &[ffi::VSFilterDependency],
132 core: impl AsRef<Core>,
133 ) -> Option<Self> {
134 let filter = Box::new(filter);
135 let name = CString::new(name).ok()?;
136 let core = core.as_ref();
137 let ptr = unsafe {
138 (core.api().createVideoFilter2)(
139 name.as_ptr(),
140 info,
141 F::filter_get_frame,
142 Some(F::filter_free),
143 F::FILTER_MODE,
144 dependencies.as_ptr(),
145 dependencies.len().try_into().unwrap(),
146 Box::into_raw(filter).cast(),
147 core.as_ptr(),
148 )
149 };
150 ptr.is_null()
151 .then_some(unsafe { Self::from_ptr(ptr, core.api()) })
152 }
153}
154
155impl Clone for VideoNode {
156 fn clone(&self) -> Self {
157 unsafe { Self::from_ptr((self.api.addNodeRef)(self.as_ptr()), self.api) }
158 }
159}
160
161impl Drop for VideoNode {
162 fn drop(&mut self) {
163 unsafe { (self.api.freeNode)(self.as_ptr()) }
164 }
165}
166
167#[derive(PartialEq, Eq, Hash, Debug)]
168pub struct AudioNode {
169 handle: *const ffi::VSNode,
170 api: Api,
171}
172
173impl crate::_private::Sealed for AudioNode {}
174impl Node for AudioNode {
175 type FrameType = AudioFrame;
176
177 #[inline]
178 fn api(&self) -> Api {
179 self.api
180 }
181
182 #[must_use]
183 #[inline]
184 fn as_ptr(&self) -> *mut ffi::VSNode {
185 self.handle.cast_mut()
186 }
187
188 fn get_frame_filter(&self, n: i32, ctx: &mut FrameContext) -> Self::FrameType {
189 unsafe {
190 AudioFrame::from_ptr(
191 (self.api.getFrameFilter)(n, self.as_ptr(), ctx.as_ptr()),
192 self.api,
193 )
194 }
195 }
196}
197
198impl AudioNode {
199 #[must_use]
203 pub unsafe fn from_ptr(ptr: *mut ffi::VSNode, api: Api) -> Self {
204 Self { handle: ptr, api }
205 }
206
207 #[must_use]
208 pub fn info(&self) -> &AudioInfo {
209 unsafe { &*(self.api.getAudioInfo)(self.as_ptr()) }
211 }
212
213 pub fn new<F: Filter>(
217 name: &str,
218 info: &AudioInfo,
219 filter: F,
220 dependencies: &[ffi::VSFilterDependency],
221 core: impl AsRef<Core>,
222 ) -> Option<Self> {
223 let filter = Box::new(filter);
224 let name = CString::new(name).ok()?;
225 let core = core.as_ref();
226 let ptr = unsafe {
227 (core.api().createAudioFilter2)(
228 name.as_ptr(),
229 info,
230 F::filter_get_frame,
231 Some(F::filter_free),
232 F::FILTER_MODE,
233 dependencies.as_ptr(),
234 dependencies.len().try_into().unwrap(),
235 Box::into_raw(filter).cast(),
236 core.as_ptr(),
237 )
238 };
239 ptr.is_null()
240 .then_some(unsafe { Self::from_ptr(ptr, core.api()) })
241 }
242}
243
244impl Clone for AudioNode {
245 fn clone(&self) -> Self {
246 unsafe { Self::from_ptr((self.api.addNodeRef)(self.as_ptr()), self.api) }
247 }
248}
249
250impl Drop for AudioNode {
251 fn drop(&mut self) {
252 unsafe { (self.api.freeNode)(self.as_ptr()) }
253 }
254}
255
256pub type FilterMode = ffi::VSFilterMode;
257pub type CacheMode = ffi::VSCacheMode;