playa_ffmpeg/filter/
graph.rs1use std::{
2 ffi::{CStr, CString},
3 ptr,
4 str::from_utf8_unchecked,
5};
6
7use super::{Context, Filter};
8use crate::{Error, ffi::*};
9use libc::c_int;
10
11pub struct Graph {
12 ptr: *mut AVFilterGraph,
13}
14
15unsafe impl Send for Graph {}
16unsafe impl Sync for Graph {}
17
18impl Graph {
19 pub unsafe fn wrap(ptr: *mut AVFilterGraph) -> Self {
20 Graph { ptr }
21 }
22
23 pub unsafe fn as_ptr(&self) -> *const AVFilterGraph {
24 self.ptr as *const _
25 }
26
27 pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFilterGraph {
28 self.ptr
29 }
30}
31
32impl Graph {
33 pub fn new() -> Self {
34 unsafe {
35 let ptr = avfilter_graph_alloc();
36
37 if ptr.is_null() {
38 panic!("out of memory");
39 }
40
41 Graph::wrap(ptr)
42 }
43 }
44
45 pub fn validate(&mut self) -> Result<(), Error> {
46 unsafe {
47 match avfilter_graph_config(self.as_mut_ptr(), ptr::null_mut()) {
48 0 => Ok(()),
49 e => Err(Error::from(e)),
50 }
51 }
52 }
53
54 pub fn add(&mut self, filter: &Filter, name: &str, args: &str) -> Result<Context, Error> {
55 unsafe {
56 let name = CString::new(name).unwrap();
57 let args = CString::new(args).unwrap();
58 let mut context = ptr::null_mut();
59
60 match avfilter_graph_create_filter(&mut context as *mut *mut AVFilterContext, filter.as_ptr(), name.as_ptr(), args.as_ptr(), ptr::null_mut(), self.as_mut_ptr()) {
61 n if n >= 0 => Ok(Context::wrap(context)),
62 e => Err(Error::from(e)),
63 }
64 }
65 }
66
67 pub fn get(&mut self, name: &str) -> Option<Context> {
68 unsafe {
69 let name = CString::new(name).unwrap();
70 let ptr = avfilter_graph_get_filter(self.as_mut_ptr(), name.as_ptr());
71
72 if ptr.is_null() { None } else { Some(Context::wrap(ptr)) }
73 }
74 }
75
76 pub fn dump(&self) -> String {
77 unsafe {
78 let ptr = avfilter_graph_dump(self.as_ptr() as *mut _, ptr::null());
79 let cstr = from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes());
80 let string = cstr.to_owned();
81
82 av_free(ptr as *mut _);
83
84 string
85 }
86 }
87
88 pub fn input(&mut self, name: &str, pad: usize) -> Result<Parser<'_>, Error> {
89 Parser::new(self).input(name, pad)
90 }
91
92 pub fn output(&mut self, name: &str, pad: usize) -> Result<Parser<'_>, Error> {
93 Parser::new(self).output(name, pad)
94 }
95
96 pub fn parse(&mut self, spec: &str) -> Result<(), Error> {
97 Parser::new(self).parse(spec)
98 }
99}
100
101impl Drop for Graph {
102 fn drop(&mut self) {
103 unsafe {
104 avfilter_graph_free(&mut self.as_mut_ptr());
105 }
106 }
107}
108
109pub struct Parser<'a> {
110 graph: &'a mut Graph,
111 inputs: *mut AVFilterInOut,
112 outputs: *mut AVFilterInOut,
113}
114
115impl<'a> Parser<'a> {
116 pub fn new(graph: &mut Graph) -> Parser<'_> {
117 Parser { graph, inputs: ptr::null_mut(), outputs: ptr::null_mut() }
118 }
119
120 pub fn input(mut self, name: &str, pad: usize) -> Result<Self, Error> {
121 unsafe {
122 let mut context = self.graph.get(name).ok_or(Error::InvalidData)?;
123 let input = avfilter_inout_alloc();
124
125 if input.is_null() {
126 panic!("out of memory");
127 }
128
129 let name = CString::new(name).unwrap();
130
131 (*input).name = av_strdup(name.as_ptr());
132 (*input).filter_ctx = context.as_mut_ptr();
133 (*input).pad_idx = pad as c_int;
134 (*input).next = ptr::null_mut();
135
136 if self.inputs.is_null() {
137 self.inputs = input;
138 } else {
139 (*self.inputs).next = input;
140 }
141 }
142
143 Ok(self)
144 }
145
146 pub fn output(mut self, name: &str, pad: usize) -> Result<Self, Error> {
147 unsafe {
148 let mut context = self.graph.get(name).ok_or(Error::InvalidData)?;
149 let output = avfilter_inout_alloc();
150
151 if output.is_null() {
152 panic!("out of memory");
153 }
154
155 let name = CString::new(name).unwrap();
156
157 (*output).name = av_strdup(name.as_ptr());
158 (*output).filter_ctx = context.as_mut_ptr();
159 (*output).pad_idx = pad as c_int;
160 (*output).next = ptr::null_mut();
161
162 if self.outputs.is_null() {
163 self.outputs = output;
164 } else {
165 (*self.outputs).next = output;
166 }
167 }
168
169 Ok(self)
170 }
171
172 pub fn parse(mut self, spec: &str) -> Result<(), Error> {
173 unsafe {
174 let spec = CString::new(spec).unwrap();
175
176 let result = avfilter_graph_parse_ptr(self.graph.as_mut_ptr(), spec.as_ptr(), &mut self.inputs, &mut self.outputs, ptr::null_mut());
177
178 avfilter_inout_free(&mut self.inputs);
179 avfilter_inout_free(&mut self.outputs);
180
181 match result {
182 n if n >= 0 => Ok(()),
183 e => Err(Error::from(e)),
184 }
185 }
186 }
187}
188
189impl Default for Graph {
190 fn default() -> Self {
191 Self::new()
192 }
193}