rustsynth_sys/
lib.rs

1//! Low level VapourSynth bindings to Rust
2//!
3//! This crate provides raw unsafe FFI bindings to the VapourSynth API.
4//! For a safe wrapper, see [rustsynth](https://crates.io/crates/rustsynth).
5//!
6//! ## Feature Flags
7//!
8//! The bindings are conditionally compiled based on feature flags:
9//!
10//! - **`api-41`** - Enables VapourSynth API version 4.1 headers (`VS_USE_API_41`)
11//! - **`vs-graph-api`** - Enables the experimental graph API (`VS_GRAPH_API`)
12//! - **`script-api-42`** - Enables VSScript API 4.2 headers (`VSSCRIPT_USE_API_42`)
13//! - **`vapoursynth-functions`** - Links to the main VapourSynth functions library
14//! - **`vsscript-functions`** - Links to the VSScript functions library
15//!
16//! Different feature combinations will expose different functions and types in the generated bindings.
17
18#![allow(non_upper_case_globals)]
19#![allow(non_camel_case_types)]
20#![allow(non_snake_case)]
21#![allow(clippy::approx_constant)]
22#![allow(clippy::missing_safety_doc)]
23#![allow(clippy::redundant_static_lifetimes)]
24#![allow(clippy::too_many_arguments)]
25#![allow(clippy::type_complexity)]
26#![allow(deref_nullptr)]
27
28include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
29
30/// Makes a VS compatible version integer
31///
32/// # Example
33/// If wanting to represent the version with major 2 and minor 1
34/// ```
35/// use rustsynth_sys::version;
36/// let v = version!(2,1);
37/// assert!(v == 0x20001);
38/// ```
39#[macro_export]
40macro_rules! version {
41    ($major:expr, $minor:expr) => {
42        (($major) << 16) | ($minor)
43    };
44}
45
46
47pub const VAPOURSYNTH_API_VERSION: i32 =
48    version!(VAPOURSYNTH_API_MAJOR as i32, VAPOURSYNTH_API_MINOR as i32);
49pub const VSSCRIPT_API_VERSION: i32 =
50    version!(VSSCRIPT_API_MAJOR as i32, VSSCRIPT_API_MINOR as i32);
51
52// VSHelper4 function implementations
53// These are static inline functions in VSHelper4.h that bindgen cannot generate bindings for
54
55/// Convenience function for checking if the format never changes between frames
56#[inline]
57pub unsafe fn isConstantVideoFormat(vi: *const VSVideoInfo) -> i32 {
58    let vi = &*vi;
59    (vi.height > 0 && vi.width > 0 && vi.format.colorFamily != VSColorFamily::cfUndefined as i32)
60        as i32
61}
62
63/// Convenience function to check if two clips have the same format
64#[inline]
65pub unsafe fn isSameVideoFormat(v1: *const VSVideoFormat, v2: *const VSVideoFormat) -> i32 {
66    let v1 = &*v1;
67    let v2 = &*v2;
68    (v1.colorFamily == v2.colorFamily
69        && v1.sampleType == v2.sampleType
70        && v1.bitsPerSample == v2.bitsPerSample
71        && v1.subSamplingW == v2.subSamplingW
72        && v1.subSamplingH == v2.subSamplingH) as i32
73}
74
75/// Convenience function to check if a clip has the same format as a format id
76#[inline]
77pub unsafe fn isSameVideoPresetFormat(
78    preset_format: u32,
79    v: *const VSVideoFormat,
80    core: *mut VSCore,
81    vsapi: *const VSAPI,
82) -> i32 {
83    let v = &*v;
84    let vsapi = &*vsapi;
85    let query_fn = vsapi.queryVideoFormatID.unwrap();
86    (query_fn(
87        v.colorFamily,
88        v.sampleType,
89        v.bitsPerSample,
90        v.subSamplingW,
91        v.subSamplingH,
92        core,
93    ) == preset_format) as i32
94}
95
96/// Convenience function to check if two clips have the same format while also including width and height
97#[inline]
98pub unsafe fn isSameVideoInfo(v1: *const VSVideoInfo, v2: *const VSVideoInfo) -> i32 {
99    let v1 = &*v1;
100    let v2 = &*v2;
101    (v1.height == v2.height
102        && v1.width == v2.width
103        && isSameVideoFormat(&v1.format, &v2.format) != 0) as i32
104}
105
106/// Convenience function to check if two clips have the same audio format
107#[inline]
108pub unsafe fn isSameAudioFormat(a1: *const VSAudioFormat, a2: *const VSAudioFormat) -> i32 {
109    let a1 = &*a1;
110    let a2 = &*a2;
111    (a1.bitsPerSample == a2.bitsPerSample
112        && a1.sampleType == a2.sampleType
113        && a1.channelLayout == a2.channelLayout) as i32
114}
115
116/// Convenience function to check if two clips have the same audio info
117#[inline]
118pub unsafe fn isSameAudioInfo(a1: *const VSAudioInfo, a2: *const VSAudioInfo) -> i32 {
119    let a1 = &*a1;
120    let a2 = &*a2;
121    (a1.sampleRate == a2.sampleRate && isSameAudioFormat(&a1.format, &a2.format) != 0) as i32
122}
123
124/// Multiplies and divides a rational number and reduces the result
125#[inline]
126pub unsafe fn muldivRational(num: *mut i64, den: *mut i64, mul: i64, div: i64) {
127    if *den == 0 {
128        return;
129    }
130    assert!(div != 0);
131
132    *num *= mul;
133    *den *= div;
134    let mut a = *num;
135    let mut b = *den;
136    while b != 0 {
137        let t = a;
138        a = b;
139        b = t % b;
140    }
141    if a < 0 {
142        a = -a;
143    }
144    *num /= a;
145    *den /= a;
146}
147
148/// Reduces a rational number
149#[inline]
150pub unsafe fn reduceRational(num: *mut i64, den: *mut i64) {
151    muldivRational(num, den, 1, 1);
152}
153
154/// Add two rational numbers and reduces the result
155#[inline]
156pub unsafe fn addRational(num: *mut i64, den: *mut i64, addnum: i64, addden: i64) {
157    if *den == 0 {
158        return;
159    }
160    assert!(addden != 0);
161
162    if *den == addden {
163        *num += addnum;
164    } else {
165        let original_den = *den;
166        let scaled_addnum = addnum * original_den;
167        let scaled_num = *num * addden;
168
169        *num = scaled_num + scaled_addnum;
170        *den = original_den * addden;
171        reduceRational(num, den);
172    }
173}
174
175/// Converts an int64 to int with saturation
176#[inline]
177pub fn int64ToIntS(i: i64) -> i32 {
178    if i > i32::MAX as i64 {
179        i32::MAX
180    } else if i < i32::MIN as i64 {
181        i32::MIN
182    } else {
183        i as i32
184    }
185}
186
187/// Converts a double to float with saturation
188#[inline]
189pub fn doubleToFloatS(d: f64) -> f32 {
190    d as f32
191}
192
193/// Bitblt function for copying image data
194#[inline]
195pub unsafe fn bitblt(
196    dstp: *mut std::ffi::c_void,
197    dst_stride: isize,
198    srcp: *const std::ffi::c_void,
199    src_stride: isize,
200    row_size: usize,
201    height: usize,
202) {
203    if height == 0 {
204        return;
205    }
206
207    if src_stride == dst_stride && src_stride == row_size as isize {
208        std::ptr::copy_nonoverlapping(srcp as *const u8, dstp as *mut u8, row_size * height);
209    } else {
210        let mut srcp8 = srcp as *const u8;
211        let mut dstp8 = dstp as *mut u8;
212        for _ in 0..height {
213            std::ptr::copy_nonoverlapping(srcp8, dstp8, row_size);
214            srcp8 = srcp8.offset(src_stride);
215            dstp8 = dstp8.offset(dst_stride);
216        }
217    }
218}
219
220/// Check if the frame dimensions are valid for a given format
221#[inline]
222pub unsafe fn areValidDimensions(fi: *const VSVideoFormat, width: i32, height: i32) -> i32 {
223    let fi = &*fi;
224    (width % (1 << fi.subSamplingW) == 0 && height % (1 << fi.subSamplingH) == 0) as i32
225}