vapoursynth4_rs/node/
internal.rs

1use std::{
2    ffi::{c_int, c_void},
3    mem::ManuallyDrop,
4    panic::AssertUnwindSafe,
5    ptr::null,
6};
7
8use crate::{
9    api::Api,
10    core::CoreRef,
11    frame::{Frame, FrameContext},
12    map::MapRef,
13    utils::ToCString,
14};
15
16use super::{Filter, ffi};
17
18pub trait FilterExtern: Filter {
19    unsafe extern "system-unwind" fn filter_create(
20        in_: *const ffi::VSMap,
21        out: *mut ffi::VSMap,
22        user_data: *mut c_void,
23        core: *mut ffi::VSCore,
24        vsapi: *const ffi::VSAPI,
25    ) {
26        unsafe {
27            let api = Api::from_ptr(vsapi);
28
29            let input = MapRef::from_ptr(in_, api);
30            let mut output = MapRef::from_ptr(out, api);
31            let core = CoreRef::from_ptr(core, api);
32            let data = if user_data.is_null() {
33                None
34            } else {
35                Some(Box::from_raw(user_data.cast()))
36            };
37
38            match std::panic::catch_unwind(AssertUnwindSafe(|| {
39                Self::create(input, output, data, core)
40            })) {
41                Ok(Err(e)) => {
42                    output.set_error(e.as_ref());
43                }
44                Err(p) => {
45                    let e = p.downcast::<&str>().unwrap_unchecked();
46                    output.set_error(&e.into_cstring_lossy());
47                }
48                _ => {}
49            }
50        }
51    }
52
53    unsafe extern "system-unwind" fn filter_get_frame(
54        n: c_int,
55        activation_reason: ffi::VSActivationReason,
56        instance_data: *mut c_void,
57        frame_data: *mut *mut c_void,
58        frame_ctx: *mut ffi::VSFrameContext,
59        core: *mut ffi::VSCore,
60        vsapi: *const ffi::VSAPI,
61    ) -> *const ffi::VSFrame {
62        unsafe {
63            let api = Api::from_ptr(vsapi);
64            let filter = instance_data.cast::<Self>().as_mut().unwrap_unchecked();
65            let mut ctx = AssertUnwindSafe(FrameContext::from_ptr(frame_ctx, api));
66            let core = CoreRef::from_ptr(core, api);
67
68            let frame = std::panic::catch_unwind(|| {
69                filter.get_frame(n, activation_reason, frame_data, *ctx, core)
70            });
71            match frame {
72                Ok(Ok(Some(frame))) => {
73                    // Transfer the ownership to VapourSynth
74                    let frame = ManuallyDrop::new(frame);
75                    return frame.as_ptr();
76                }
77                Ok(Err(e)) => {
78                    ctx.set_filter_error(e.as_ref());
79                }
80                Err(p) => {
81                    let e = p.downcast::<&str>().unwrap_unchecked();
82                    ctx.set_filter_error(&e.into_cstring_lossy());
83                }
84                _ => {}
85            }
86        }
87
88        null()
89    }
90
91    unsafe extern "system-unwind" fn filter_free(
92        instance_data: *mut c_void,
93        core: *mut ffi::VSCore,
94        vsapi: *const ffi::VSAPI,
95    ) {
96        unsafe {
97            let api = Api::from_ptr(vsapi);
98            let filter = Box::from_raw(instance_data.cast::<Self>());
99            let core = CoreRef::from_ptr(core, api);
100
101            filter.free(core);
102        }
103    }
104}
105
106impl<F> FilterExtern for F where F: Filter {}