vapoursynth/
core.rs

1//! VapourSynth cores.
2
3use std::ffi::{CStr, CString, NulError};
4use std::fmt;
5use std::marker::PhantomData;
6use std::ptr::NonNull;
7use vapoursynth_sys as ffi;
8
9use crate::api::API;
10use crate::format::{ColorFamily, Format, FormatID, SampleType};
11use crate::plugin::Plugin;
12
13/// Contains information about a VapourSynth core.
14#[derive(Debug, Clone, Copy, Hash)]
15pub struct Info {
16    /// String containing the name of the library, copyright notice, core and API versions.
17    pub version_string: &'static str,
18
19    /// Version of the core.
20    pub core_version: i32,
21
22    /// Version of the API.
23    pub api_version: i32,
24
25    /// Number of worker threads.
26    pub num_threads: usize,
27
28    /// The framebuffer cache will be allowed to grow up to this size (bytes) before memory is
29    /// aggressively reclaimed.
30    pub max_framebuffer_size: u64,
31
32    /// Current size of the framebuffer cache, in bytes.
33    pub used_framebuffer_size: u64,
34}
35
36/// A reference to a VapourSynth core.
37#[derive(Debug, Clone, Copy)]
38pub struct CoreRef<'core> {
39    handle: NonNull<ffi::VSCore>,
40    _owner: PhantomData<&'core ()>,
41}
42
43unsafe impl<'core> Send for CoreRef<'core> {}
44unsafe impl<'core> Sync for CoreRef<'core> {}
45
46impl<'core> CoreRef<'core> {
47    /// Wraps `handle` in a `CoreRef`.
48    ///
49    /// # Safety
50    /// The caller must ensure `handle` is valid and API is cached.
51    #[inline]
52    pub(crate) unsafe fn from_ptr(handle: *mut ffi::VSCore) -> Self {
53        Self {
54            handle: NonNull::new_unchecked(handle),
55            _owner: PhantomData,
56        }
57    }
58
59    /// Returns the underlying pointer.
60    #[inline]
61    pub(crate) fn ptr(&self) -> *mut ffi::VSCore {
62        self.handle.as_ptr()
63    }
64
65    /// Returns information about the VapourSynth core.
66    pub fn info(self) -> Info {
67        let raw_info = unsafe { &API::get_cached().get_core_info(self.handle.as_ptr()) };
68
69        let version_string = unsafe { CStr::from_ptr(raw_info.versionString).to_str().unwrap() };
70        debug_assert!(raw_info.numThreads >= 0);
71        debug_assert!(raw_info.maxFramebufferSize >= 0);
72        debug_assert!(raw_info.usedFramebufferSize >= 0);
73
74        Info {
75            version_string,
76            core_version: raw_info.core,
77            api_version: raw_info.api,
78            num_threads: raw_info.numThreads as usize,
79            max_framebuffer_size: raw_info.maxFramebufferSize as u64,
80            used_framebuffer_size: raw_info.usedFramebufferSize as u64,
81        }
82    }
83
84    /// Retrieves a registered or preset `Format` by its id. The id can be of a previously
85    /// registered format, or one of the `PresetFormat`.
86    #[inline]
87    pub fn get_format(&self, id: FormatID) -> Option<Format<'core>> {
88        let ptr = unsafe { API::get_cached().get_format_preset(id.0, self.handle.as_ptr()) };
89        unsafe { ptr.as_ref().map(|p| Format::from_ptr(p)) }
90    }
91
92    /// Registers a custom video format.
93    ///
94    /// Returns `None` if an invalid format is described.
95    ///
96    /// Registering compat formats is not allowed. Only certain privileged built-in filters are
97    /// allowed to handle compat formats.
98    ///
99    /// RGB formats are not allowed to be subsampled.
100    #[inline]
101    pub fn register_format(
102        &self,
103        color_family: ColorFamily,
104        sample_type: SampleType,
105        bits_per_sample: u8,
106        sub_sampling_w: u8,
107        sub_sampling_h: u8,
108    ) -> Option<Format<'core>> {
109        unsafe {
110            API::get_cached()
111                .register_format(
112                    color_family.into(),
113                    sample_type.into(),
114                    i32::from(bits_per_sample),
115                    i32::from(sub_sampling_w),
116                    i32::from(sub_sampling_h),
117                    self.handle.as_ptr(),
118                )
119                .as_ref()
120                .map(|p| Format::from_ptr(p))
121        }
122    }
123
124    /// Returns a plugin with the given identifier.
125    #[inline]
126    pub fn get_plugin_by_id(&self, id: &str) -> Result<Option<Plugin<'core>>, NulError> {
127        let id = CString::new(id)?;
128        let ptr = unsafe { API::get_cached().get_plugin_by_id(id.as_ptr(), self.handle.as_ptr()) };
129        if ptr.is_null() {
130            Ok(None)
131        } else {
132            Ok(Some(unsafe { Plugin::from_ptr(ptr) }))
133        }
134    }
135
136    /// Returns a plugin with the given namespace.
137    ///
138    /// `get_plugin_by_id()` should be used instead.
139    #[inline]
140    pub fn get_plugin_by_namespace(
141        &self,
142        namespace: &str,
143    ) -> Result<Option<Plugin<'core>>, NulError> {
144        let namespace = CString::new(namespace)?;
145        let ptr =
146            unsafe { API::get_cached().get_plugin_by_ns(namespace.as_ptr(), self.handle.as_ptr()) };
147        if ptr.is_null() {
148            Ok(None)
149        } else {
150            Ok(Some(unsafe { Plugin::from_ptr(ptr) }))
151        }
152    }
153
154    /// Sets the maximum size of the framebuffer cache. Returns the new maximum size.
155    #[inline]
156    pub fn set_max_cache_size(&self, bytes: i64) -> i64 {
157        unsafe { API::get_cached().set_max_cache_size(bytes, self.handle.as_ptr()) }
158    }
159
160    /// Sets the number of worker threads for the given core.
161    ///
162    /// If the requested number of threads is zero or lower, the number of hardware threads will be
163    /// detected and used.
164    ///
165    /// Returns the new thread count.
166    #[inline]
167    pub fn set_thread_count(&self, threads: i32) -> i32 {
168        unsafe { API::get_cached().set_thread_count(threads, self.handle.as_ptr()) }
169    }
170}
171
172impl fmt::Display for Info {
173    #[inline]
174    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175        write!(f, "{}", self.version_string)?;
176        writeln!(f, "Worker threads: {}", self.num_threads)?;
177        writeln!(
178            f,
179            "Max framebuffer cache size: {}",
180            self.max_framebuffer_size
181        )?;
182        writeln!(
183            f,
184            "Current framebuffer cache size: {}",
185            self.used_framebuffer_size
186        )
187    }
188}