Skip to main content

ffmpeg_the_third/filter/
graph.rs

1use std::ffi::{CStr, CString};
2use std::ptr::{self, NonNull};
3use std::str::from_utf8_unchecked;
4
5use super::{Context, Filter};
6use crate::ffi::*;
7use crate::Error;
8use libc::c_int;
9
10pub struct Graph {
11    ptr: *mut AVFilterGraph,
12}
13
14unsafe impl Send for Graph {}
15unsafe impl Sync for Graph {}
16
17impl Graph {
18    pub unsafe fn wrap(ptr: *mut AVFilterGraph) -> Self {
19        Graph { ptr }
20    }
21
22    pub unsafe fn as_ptr(&self) -> *const AVFilterGraph {
23        self.ptr as *const _
24    }
25
26    pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFilterGraph {
27        self.ptr
28    }
29}
30
31impl Graph {
32    pub fn new() -> Self {
33        unsafe {
34            let ptr = avfilter_graph_alloc();
35
36            if ptr.is_null() {
37                panic!("out of memory");
38            }
39
40            Graph::wrap(ptr)
41        }
42    }
43
44    pub fn validate(&mut self) -> Result<(), Error> {
45        unsafe {
46            match avfilter_graph_config(self.as_mut_ptr(), ptr::null_mut()) {
47                0 => Ok(()),
48                e => Err(Error::from(e)),
49            }
50        }
51    }
52
53    pub fn add<'a, 'b>(
54        &'a mut self,
55        filter: &Filter,
56        name: &str,
57        args: &str,
58    ) -> Result<Context<'b>, Error>
59    where
60        'a: 'b,
61    {
62        unsafe {
63            let name = CString::new(name).unwrap();
64            let args = CString::new(args).unwrap();
65            let mut context = ptr::null_mut();
66
67            match avfilter_graph_create_filter(
68                &mut context as *mut *mut AVFilterContext,
69                filter.as_ptr(),
70                name.as_ptr(),
71                args.as_ptr(),
72                ptr::null_mut(),
73                self.as_mut_ptr(),
74            ) {
75                n if n >= 0 => Ok(Context::wrap(context)),
76                e => Err(Error::from(e)),
77            }
78        }
79    }
80
81    pub fn get<'a, 'b>(&'b mut self, name: &str) -> Option<Context<'b>>
82    where
83        'a: 'b,
84    {
85        unsafe {
86            let name = CString::new(name).unwrap();
87            let ptr = avfilter_graph_get_filter(self.as_mut_ptr(), name.as_ptr());
88
89            if ptr.is_null() {
90                None
91            } else {
92                Some(Context::wrap(ptr))
93            }
94        }
95    }
96
97    pub fn dump(&self) -> String {
98        unsafe {
99            let ptr = avfilter_graph_dump(self.as_ptr() as *mut _, ptr::null());
100            let cstr = from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes());
101            let string = cstr.to_owned();
102
103            av_free(ptr as *mut _);
104
105            string
106        }
107    }
108
109    pub fn input(&mut self, name: &str, pad: usize) -> Result<Parser<'_>, Error> {
110        Parser::new(self).input(name, pad)
111    }
112
113    pub fn output(&mut self, name: &str, pad: usize) -> Result<Parser<'_>, Error> {
114        Parser::new(self).output(name, pad)
115    }
116
117    pub fn parse(&mut self, spec: &str) -> Result<(), Error> {
118        Parser::new(self).parse(spec)
119    }
120}
121
122impl Drop for Graph {
123    fn drop(&mut self) {
124        unsafe {
125            avfilter_graph_free(&mut self.as_mut_ptr());
126        }
127    }
128}
129
130pub struct Parser<'a> {
131    graph: &'a mut Graph,
132    inputs: *mut AVFilterInOut,
133    outputs: *mut AVFilterInOut,
134}
135
136impl<'a> Parser<'a> {
137    pub fn new(graph: &mut Graph) -> Parser<'_> {
138        Parser {
139            graph,
140            inputs: ptr::null_mut(),
141            outputs: ptr::null_mut(),
142        }
143    }
144
145    pub fn input(mut self, name: &str, pad: usize) -> Result<Self, Error> {
146        unsafe {
147            let mut context = self.graph.get(name).ok_or(Error::InvalidData)?;
148            let mut input = NonNull::new(avfilter_inout_alloc()).expect("out of memory");
149
150            let name = CString::new(name).unwrap();
151
152            input.as_mut().name = av_strdup(name.as_ptr());
153            input.as_mut().filter_ctx = context.as_mut_ptr();
154            input.as_mut().pad_idx = pad as c_int;
155            input.as_mut().next = ptr::null_mut();
156
157            append_inout(&mut self.inputs, input);
158        }
159
160        Ok(self)
161    }
162
163    pub fn output(mut self, name: &str, pad: usize) -> Result<Self, Error> {
164        unsafe {
165            let mut context = self.graph.get(name).ok_or(Error::InvalidData)?;
166            let mut output = NonNull::new(avfilter_inout_alloc()).expect("out of memory");
167
168            let name = CString::new(name).unwrap();
169
170            output.as_mut().name = av_strdup(name.as_ptr());
171            output.as_mut().filter_ctx = context.as_mut_ptr();
172            output.as_mut().pad_idx = pad as c_int;
173            output.as_mut().next = ptr::null_mut();
174
175            append_inout(&mut self.outputs, output);
176        }
177
178        Ok(self)
179    }
180
181    pub fn parse(mut self, spec: &str) -> Result<(), Error> {
182        unsafe {
183            let spec = CString::new(spec).unwrap();
184
185            let result = avfilter_graph_parse_ptr(
186                self.graph.as_mut_ptr(),
187                spec.as_ptr(),
188                &mut self.inputs,
189                &mut self.outputs,
190                ptr::null_mut(),
191            );
192
193            avfilter_inout_free(&mut self.inputs);
194            avfilter_inout_free(&mut self.outputs);
195
196            match result {
197                n if n >= 0 => Ok(()),
198                e => Err(Error::from(e)),
199            }
200        }
201    }
202}
203
204fn append_inout(list: &mut *mut AVFilterInOut, element: NonNull<AVFilterInOut>) {
205    unsafe {
206        if list.is_null() {
207            *list = element.as_ptr();
208            return;
209        }
210
211        let mut curr = *list;
212        while !(*curr).next.is_null() {
213            curr = (*curr).next;
214        }
215
216        (*curr).next = element.as_ptr();
217    }
218}
219
220impl<'a> Drop for Parser<'a> {
221    fn drop(&mut self) {
222        unsafe {
223            avfilter_inout_free(&mut self.inputs);
224            avfilter_inout_free(&mut self.outputs);
225        }
226    }
227}
228
229impl Default for Graph {
230    fn default() -> Self {
231        Self::new()
232    }
233}