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(&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 | |
111 | impl Drop for Graph { |
112 | fn drop(&mut self) { |
113 | unsafe { |
114 | avfilter_graph_free(&mut self.as_mut_ptr()); |
115 | } |
116 | } |
117 | } |
118 | |
119 | pub struct Parser<'a> { |
120 | graph: &'a mut Graph, |
121 | inputs: *mut AVFilterInOut, |
122 | outputs: *mut AVFilterInOut, |
123 | } |
124 | |
125 | impl<'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 | (*self.inputs).next = input; |
154 | } |
155 | } |
156 | |
157 | Ok(self) |
158 | } |
159 | |
160 | pub fn output(mut self, name: &str, pad: usize) -> Result<Self, Error> { |
161 | unsafe { |
162 | let mut context = self.graph.get(name).ok_or(Error::InvalidData)?; |
163 | let output = avfilter_inout_alloc(); |
164 | |
165 | if output.is_null() { |
166 | panic!("out of memory" ); |
167 | } |
168 | |
169 | let name = CString::new(name).unwrap(); |
170 | |
171 | (*output).name = av_strdup(name.as_ptr()); |
172 | (*output).filter_ctx = context.as_mut_ptr(); |
173 | (*output).pad_idx = pad as c_int; |
174 | (*output).next = ptr::null_mut(); |
175 | |
176 | if self.outputs.is_null() { |
177 | self.outputs = output; |
178 | } else { |
179 | (*self.outputs).next = output; |
180 | } |
181 | } |
182 | |
183 | Ok(self) |
184 | } |
185 | |
186 | pub fn parse(mut self, spec: &str) -> Result<(), Error> { |
187 | unsafe { |
188 | let spec = CString::new(spec).unwrap(); |
189 | |
190 | let result = avfilter_graph_parse_ptr( |
191 | self.graph.as_mut_ptr(), |
192 | spec.as_ptr(), |
193 | &mut self.inputs, |
194 | &mut self.outputs, |
195 | ptr::null_mut(), |
196 | ); |
197 | |
198 | avfilter_inout_free(&mut self.inputs); |
199 | avfilter_inout_free(&mut self.outputs); |
200 | |
201 | match result { |
202 | n if n >= 0 => Ok(()), |
203 | e => Err(Error::from(e)), |
204 | } |
205 | } |
206 | } |
207 | } |
208 | |
209 | impl Default for Graph { |
210 | fn default() -> Self { |
211 | Self::new() |
212 | } |
213 | } |
214 | |