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
46pub const VAPOURSYNTH_API_VERSION: i32 =
47    version!(VAPOURSYNTH_API_MAJOR as i32, VAPOURSYNTH_API_MINOR as i32);
48pub const VSSCRIPT_API_VERSION: i32 =
49    version!(VSSCRIPT_API_MAJOR as i32, VSSCRIPT_API_MINOR as i32);
50
51// VSHelper4 function implementations
52// These are static inline functions in VSHelper4.h that bindgen cannot generate bindings for
53
54/// Convenience function for checking if the format never changes between frames
55#[inline]
56pub const unsafe fn isConstantVideoFormat(vi: *const VSVideoInfo) -> i32 {
57    let vi = &*vi;
58    (vi.height > 0 && vi.width > 0 && vi.format.colorFamily != VSColorFamily::cfUndefined as i32)
59        as i32
60}
61
62/// Convenience function to check if two clips have the same format
63#[inline]
64pub const unsafe fn isSameVideoFormat(v1: *const VSVideoFormat, v2: *const VSVideoFormat) -> i32 {
65    let v1 = &*v1;
66    let v2 = &*v2;
67    (v1.colorFamily == v2.colorFamily
68        && v1.sampleType == v2.sampleType
69        && v1.bitsPerSample == v2.bitsPerSample
70        && v1.subSamplingW == v2.subSamplingW
71        && v1.subSamplingH == v2.subSamplingH) as i32
72}
73
74/// Convenience function to check if a clip has the same format as a format id
75#[inline]
76pub unsafe fn isSameVideoPresetFormat(
77    preset_format: u32,
78    v: *const VSVideoFormat,
79    core: *mut VSCore,
80    vsapi: *const VSAPI,
81) -> i32 {
82    let v = &*v;
83    let vsapi = &*vsapi;
84    let query_fn = vsapi.queryVideoFormatID.unwrap();
85    (query_fn(
86        v.colorFamily,
87        v.sampleType,
88        v.bitsPerSample,
89        v.subSamplingW,
90        v.subSamplingH,
91        core,
92    ) == preset_format) as i32
93}
94
95/// Convenience function to check if two clips have the same format while also including width and height
96#[inline]
97pub const unsafe fn isSameVideoInfo(v1: *const VSVideoInfo, v2: *const VSVideoInfo) -> i32 {
98    let v1 = &*v1;
99    let v2 = &*v2;
100    (v1.height == v2.height
101        && v1.width == v2.width
102        && isSameVideoFormat(&v1.format, &v2.format) != 0) as i32
103}
104
105/// Convenience function to check if two clips have the same audio format
106#[inline]
107pub const unsafe fn isSameAudioFormat(a1: *const VSAudioFormat, a2: *const VSAudioFormat) -> i32 {
108    let a1 = &*a1;
109    let a2 = &*a2;
110    (a1.bitsPerSample == a2.bitsPerSample
111        && a1.sampleType == a2.sampleType
112        && a1.channelLayout == a2.channelLayout) as i32
113}
114
115/// Convenience function to check if two clips have the same audio info
116#[inline]
117pub const unsafe fn isSameAudioInfo(a1: *const VSAudioInfo, a2: *const VSAudioInfo) -> i32 {
118    let a1 = &*a1;
119    let a2 = &*a2;
120    (a1.sampleRate == a2.sampleRate && isSameAudioFormat(&a1.format, &a2.format) != 0) as i32
121}
122
123/// Multiplies and divides a rational number and reduces the result
124#[inline]
125pub const unsafe fn muldivRational(num: *mut i64, den: *mut i64, mul: i64, div: i64) {
126    if *den == 0 {
127        return;
128    }
129    assert!(div != 0);
130
131    *num *= mul;
132    *den *= div;
133    let mut a = *num;
134    let mut b = *den;
135    while b != 0 {
136        let t = a;
137        a = b;
138        b = t % b;
139    }
140    if a < 0 {
141        a = -a;
142    }
143    *num /= a;
144    *den /= a;
145}
146
147/// Reduces a rational number
148#[inline]
149pub const unsafe fn reduceRational(num: *mut i64, den: *mut i64) {
150    muldivRational(num, den, 1, 1);
151}
152
153/// Add two rational numbers and reduces the result
154#[inline]
155pub const unsafe fn addRational(num: *mut i64, den: *mut i64, addnum: i64, addden: i64) {
156    if *den == 0 {
157        return;
158    }
159    assert!(addden != 0);
160
161    if *den == addden {
162        *num += addnum;
163    } else {
164        let original_den = *den;
165        let scaled_addnum = addnum * original_den;
166        let scaled_num = *num * addden;
167
168        *num = scaled_num + scaled_addnum;
169        *den = original_den * addden;
170        reduceRational(num, den);
171    }
172}
173
174/// Converts an int64 to int with saturation
175#[inline]
176pub const fn int64ToIntS(i: i64) -> i32 {
177    if i > i32::MAX as i64 {
178        i32::MAX
179    } else if i < i32::MIN as i64 {
180        i32::MIN
181    } else {
182        i as i32
183    }
184}
185
186/// Converts a double to float with saturation
187#[inline]
188pub const fn doubleToFloatS(d: f64) -> f32 {
189    d as f32
190}
191
192/// Bitblt function for copying image data
193#[inline]
194pub unsafe fn bitblt(
195    dstp: *mut std::ffi::c_void,
196    dst_stride: isize,
197    srcp: *const std::ffi::c_void,
198    src_stride: isize,
199    row_size: usize,
200    height: usize,
201) {
202    if height == 0 {
203        return;
204    }
205
206    if src_stride == dst_stride && src_stride == row_size as isize {
207        std::ptr::copy_nonoverlapping(srcp as *const u8, dstp as *mut u8, row_size * height);
208    } else {
209        let mut srcp8 = srcp as *const u8;
210        let mut dstp8 = dstp as *mut u8;
211        for _ in 0..height {
212            std::ptr::copy_nonoverlapping(srcp8, dstp8, row_size);
213            srcp8 = srcp8.offset(src_stride);
214            dstp8 = dstp8.offset(dst_stride);
215        }
216    }
217}
218
219/// Check if the frame dimensions are valid for a given format
220#[inline]
221pub const unsafe fn areValidDimensions(fi: *const VSVideoFormat, width: i32, height: i32) -> i32 {
222    let fi = &*fi;
223    (width % (1 << fi.subSamplingW) == 0 && height % (1 << fi.subSamplingH) == 0) as i32
224}