1 | use std::ffi::{CStr, CString}; |
2 | use std::ptr; |
3 | use std::str::from_utf8_unchecked; |
4 | |
5 | use super::{Context, Filter}; |
6 | use ffi::*; |
7 | use libc::c_int; |
8 | use Error; |
9 | |
10 | pub struct Graph { |
11 | ptr: *mut AVFilterGraph, |
12 | } |
13 | |
14 | unsafe impl Send for Graph {} |
15 | unsafe impl Sync for Graph {} |
16 | |
17 | impl 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 | |
31 | impl 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 | |
122 | impl Drop for Graph { |
123 | fn drop(&mut self) { |
124 | unsafe { |
125 | avfilter_graph_free(&mut self.as_mut_ptr()); |
126 | } |
127 | } |
128 | } |
129 | |
130 | pub struct Parser<'a> { |
131 | graph: &'a mut Graph, |
132 | inputs: *mut AVFilterInOut, |
133 | outputs: *mut AVFilterInOut, |
134 | } |
135 | |
136 | impl<'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 | |
220 | impl Default for Graph { |
221 | fn default() -> Self { |
222 | Self::new() |
223 | } |
224 | } |
225 | |