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(&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 (*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
209impl Default for Graph {
210 fn default() -> Self {
211 Self::new()
212 }
213}
214