Skip to main content

ffmpeg_next/filter/
graph.rs

1use std::ffi::{CStr, CString};
2use std::ptr;
3use std::str::from_utf8_unchecked;
4
5use super::{Context, Filter};
6use crate::Error;
7use crate::ffi::*;
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(&mut self, filter: &Filter, name: &str, args: &str) -> Result<Context, Error> {
54        unsafe {
55            let name = CString::new(name).unwrap();
56            let args = CString::new(args).unwrap();
57            let mut context = ptr::null_mut();
58
59            match avfilter_graph_create_filter(
60                &mut context as *mut *mut AVFilterContext,
61                filter.as_ptr(),
62                name.as_ptr(),
63                args.as_ptr(),
64                ptr::null_mut(),
65                self.as_mut_ptr(),
66            ) {
67                n if n >= 0 => Ok(Context::wrap(context)),
68                e => Err(Error::from(e)),
69            }
70        }
71    }
72
73    pub fn get(&mut self, name: &str) -> Option<Context> {
74        unsafe {
75            let name = CString::new(name).unwrap();
76            let ptr = avfilter_graph_get_filter(self.as_mut_ptr(), name.as_ptr());
77
78            if ptr.is_null() {
79                None
80            } else {
81                Some(Context::wrap(ptr))
82            }
83        }
84    }
85
86    pub fn dump(&self) -> String {
87        unsafe {
88            let ptr = avfilter_graph_dump(self.as_ptr() as *mut _, ptr::null());
89            let cstr = from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes());
90            let string = cstr.to_owned();
91
92            av_free(ptr as *mut _);
93
94            string
95        }
96    }
97
98    pub fn input(&mut self, name: &str, pad: usize) -> Result<Parser<'_>, Error> {
99        Parser::new(self).input(name, pad)
100    }
101
102    pub fn output(&mut self, name: &str, pad: usize) -> Result<Parser<'_>, Error> {
103        Parser::new(self).output(name, pad)
104    }
105
106    pub fn parse(&mut self, spec: &str) -> Result<(), Error> {
107        Parser::new(self).parse(spec)
108    }
109}
110
111impl Drop for Graph {
112    fn drop(&mut self) {
113        unsafe {
114            avfilter_graph_free(&mut self.as_mut_ptr());
115        }
116    }
117}
118
119pub struct Parser<'a> {
120    graph: &'a mut Graph,
121    inputs: *mut AVFilterInOut,
122    outputs: *mut AVFilterInOut,
123}
124
125impl<'a> Parser<'a> {
126    pub fn new(graph: &mut Graph) -> Parser<'_> {
127        Parser {
128            graph,
129            inputs: ptr::null_mut(),
130            outputs: ptr::null_mut(),
131        }
132    }
133
134    pub fn input(mut self, name: &str, pad: usize) -> Result<Self, Error> {
135        unsafe {
136            let mut context = self.graph.get(name).ok_or(Error::InvalidData)?;
137            let input = avfilter_inout_alloc();
138
139            if input.is_null() {
140                panic!("out of memory");
141            }
142
143            let name = CString::new(name).unwrap();
144
145            (*input).name = av_strdup(name.as_ptr());
146            (*input).filter_ctx = context.as_mut_ptr();
147            (*input).pad_idx = pad as c_int;
148            (*input).next = ptr::null_mut();
149
150            if self.inputs.is_null() {
151                self.inputs = input;
152            } else {
153                let mut prev_input = self.inputs;
154                let mut next_input = (*prev_input).next;
155                while !next_input.is_null() {
156                    prev_input = next_input;
157                    next_input = (*next_input).next;
158                }
159                (*prev_input).next = input;
160            }
161        }
162
163        Ok(self)
164    }
165
166    pub fn output(mut self, name: &str, pad: usize) -> Result<Self, Error> {
167        unsafe {
168            let mut context = self.graph.get(name).ok_or(Error::InvalidData)?;
169            let output = avfilter_inout_alloc();
170
171            if output.is_null() {
172                panic!("out of memory");
173            }
174
175            let name = CString::new(name).unwrap();
176
177            (*output).name = av_strdup(name.as_ptr());
178            (*output).filter_ctx = context.as_mut_ptr();
179            (*output).pad_idx = pad as c_int;
180            (*output).next = ptr::null_mut();
181
182            if self.outputs.is_null() {
183                self.outputs = output;
184            } else {
185                let mut prev_output = self.outputs;
186                let mut next_output = (*prev_output).next;
187                while !next_output.is_null() {
188                    prev_output = next_output;
189                    next_output = (*next_output).next;
190                }
191                (*prev_output).next = output;
192            }
193        }
194
195        Ok(self)
196    }
197
198    pub fn parse(mut self, spec: &str) -> Result<(), Error> {
199        unsafe {
200            let spec = CString::new(spec).unwrap();
201
202            let result = avfilter_graph_parse_ptr(
203                self.graph.as_mut_ptr(),
204                spec.as_ptr(),
205                &mut self.inputs,
206                &mut self.outputs,
207                ptr::null_mut(),
208            );
209
210            avfilter_inout_free(&mut self.inputs);
211            avfilter_inout_free(&mut self.outputs);
212
213            match result {
214                n if n >= 0 => Ok(()),
215                e => Err(Error::from(e)),
216            }
217        }
218    }
219}
220
221impl Default for Graph {
222    fn default() -> Self {
223        Self::new()
224    }
225}