1use std::ffi::{CStr, CString};
2use std::ptr;
3use std::str::from_utf8_unchecked;
4
5use super::{Context, Filter};
6use ffi::*;
7use libc::c_int;
8use Error;
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 input = avfilter_inout_alloc();
149
150 if input.is_null() {
151 panic!("out of memory");
152 }
153
154 let name = CString::new(name).unwrap();
155
156 (*input).name = av_strdup(name.as_ptr());
157 (*input).filter_ctx = context.as_mut_ptr();
158 (*input).pad_idx = pad as c_int;
159 (*input).next = ptr::null_mut();
160
161 if self.inputs.is_null() {
162 self.inputs = input;
163 } else {
164 (*self.inputs).next = input;
165 }
166 }
167
168 Ok(self)
169 }
170
171 pub fn output(mut self, name: &str, pad: usize) -> Result<Self, Error> {
172 unsafe {
173 let mut context = self.graph.get(name).ok_or(Error::InvalidData)?;
174 let output = avfilter_inout_alloc();
175
176 if output.is_null() {
177 panic!("out of memory");
178 }
179
180 let name = CString::new(name).unwrap();
181
182 (*output).name = av_strdup(name.as_ptr());
183 (*output).filter_ctx = context.as_mut_ptr();
184 (*output).pad_idx = pad as c_int;
185 (*output).next = ptr::null_mut();
186
187 if self.outputs.is_null() {
188 self.outputs = output;
189 } else {
190 (*self.outputs).next = output;
191 }
192 }
193
194 Ok(self)
195 }
196
197 pub fn parse(mut self, spec: &str) -> Result<(), Error> {
198 unsafe {
199 let spec = CString::new(spec).unwrap();
200
201 let result = avfilter_graph_parse_ptr(
202 self.graph.as_mut_ptr(),
203 spec.as_ptr(),
204 &mut self.inputs,
205 &mut self.outputs,
206 ptr::null_mut(),
207 );
208
209 avfilter_inout_free(&mut self.inputs);
210 avfilter_inout_free(&mut self.outputs);
211
212 match result {
213 n if n >= 0 => Ok(()),
214 e => Err(Error::from(e)),
215 }
216 }
217 }
218}
219
220impl Default for Graph {
221 fn default() -> Self {
222 Self::new()
223 }
224}
225