ffmpeg_the_third/filter/
graph.rs1use 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}