vapoursynth4_rs/
sciprt.rs1use std::{
2 ffi::{CStr, c_int},
3 ptr::{NonNull, null_mut},
4};
5
6use thiserror::Error;
7
8use crate::{
9 api::{Api, VssApi},
10 core::{Core, CoreRef},
11 node::{AudioNode, VideoNode},
12};
13
14use super::ffi;
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct Script {
18 handle: NonNull<ffi::VSScript>,
19 vssapi: VssApi,
20 api: Api,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub enum OutputNode {
25 Audio(AudioNode),
26 Video(VideoNode),
27}
28
29impl Script {
30 pub fn new(core: Option<&Core>, vssapi: VssApi, api: Api) -> Self {
36 unsafe {
37 let handle = NonNull::new((vssapi.createScript)(core.map_or(null_mut(), Core::as_ptr)))
38 .expect("Failed to create script");
39 Self {
40 handle,
41 vssapi,
42 api,
43 }
44 }
45 }
46
47 #[must_use]
48 pub fn get_api(&self) -> Api {
49 self.api
50 }
51
52 pub fn core(&self) -> Result<CoreRef, ScriptError> {
58 unsafe {
59 let core = (self.vssapi.getCore)(self.handle.as_ptr());
60 self.get_ptr_error(core)
61 .map(|core| CoreRef::from_ptr(core, self.api))
62 }
63 }
64
65 pub fn evaluate(&self, buffer: &CStr, filename: &CStr) -> Result<(), ScriptError> {
71 unsafe {
72 let result = (self.vssapi.evaluateBuffer)(
73 self.handle.as_ptr(),
74 buffer.as_ptr(),
75 filename.as_ptr(),
76 );
77 self.get_error(result)
78 }
79 }
80
81 pub fn evaluate_file(&self, filename: &CStr) -> Result<(), ScriptError> {
87 unsafe {
88 let result = (self.vssapi.evaluateFile)(self.handle.as_ptr(), filename.as_ptr());
89 self.get_error(result)
90 }
91 }
92
93 pub fn get_output(&self, index: c_int) -> Result<OutputNode, ScriptError> {
99 unsafe {
100 let ptr =
101 self.get_ptr_error((self.vssapi.getOutputNode)(self.handle.as_ptr(), index))?;
102 match (self.api.getNodeType)(ptr) {
103 ffi::VSMediaType::Audio => {
104 Ok(OutputNode::Audio(AudioNode::from_ptr(ptr, self.api)))
105 }
106 ffi::VSMediaType::Video => {
107 Ok(OutputNode::Video(VideoNode::from_ptr(ptr, self.api)))
108 }
109 }
110 }
111 }
112}
113
114impl Script {
116 fn get_error(&self, ret: c_int) -> Result<(), ScriptError> {
117 if ret == 0 {
118 Ok(())
119 } else {
120 Err(unsafe { ScriptError::from_vss(self) })
121 }
122 }
123
124 fn get_ptr_error<T>(&self, ptr: *mut T) -> Result<*mut T, ScriptError> {
125 if ptr.is_null() {
126 Err(unsafe { ScriptError::from_vss(self) })
127 } else {
128 Ok(ptr)
129 }
130 }
131}
132
133impl Drop for Script {
134 fn drop(&mut self) {
135 unsafe { (self.vssapi.freeScript)(self.handle.as_ptr()) };
136 }
137}
138
139#[cfg(feature = "link-library")]
140impl Default for Script {
141 fn default() -> Self {
142 Self::new(None, VssApi::default(), Api::default())
143 }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, Hash, Error)]
149#[error("VSScript error: {0}")]
150pub struct ScriptError(String);
151
152impl ScriptError {
153 unsafe fn from_vss(vss: &Script) -> Self {
154 unsafe {
155 Self(
156 CStr::from_ptr((vss.vssapi.getError)(vss.handle.as_ptr()))
157 .to_string_lossy()
158 .into_owned(),
159 )
160 }
161 }
162}