1 | use std::ptr; |
2 | |
3 | use super::Delay; |
4 | use ffi::*; |
5 | use libc::c_int; |
6 | use std::ffi::c_void; |
7 | use util::format; |
8 | use Dictionary; |
9 | use {frame, ChannelLayout, Error}; |
10 | |
11 | #[derive (Eq, PartialEq, Copy, Clone)] |
12 | pub struct Definition { |
13 | pub format: format::Sample, |
14 | pub channel_layout: ChannelLayout, |
15 | pub rate: u32, |
16 | } |
17 | |
18 | pub struct Context { |
19 | ptr: *mut SwrContext, |
20 | |
21 | input: Definition, |
22 | output: Definition, |
23 | } |
24 | |
25 | unsafe impl Send for Context {} |
26 | |
27 | impl Context { |
28 | #[doc (hidden)] |
29 | pub unsafe fn as_ptr(&self) -> *const SwrContext { |
30 | self.ptr as *const _ |
31 | } |
32 | |
33 | #[doc (hidden)] |
34 | pub unsafe fn as_mut_ptr(&mut self) -> *mut SwrContext { |
35 | self.ptr |
36 | } |
37 | } |
38 | |
39 | impl Context { |
40 | /// Create a resampler with the given definitions. |
41 | pub fn get( |
42 | src_format: format::Sample, |
43 | src_channel_layout: ChannelLayout, |
44 | src_rate: u32, |
45 | dst_format: format::Sample, |
46 | dst_channel_layout: ChannelLayout, |
47 | dst_rate: u32, |
48 | ) -> Result<Self, Error> { |
49 | Self::get_with( |
50 | src_format, |
51 | src_channel_layout, |
52 | src_rate, |
53 | dst_format, |
54 | dst_channel_layout, |
55 | dst_rate, |
56 | Dictionary::new(), |
57 | ) |
58 | } |
59 | |
60 | /// Create a resampler with the given definitions and custom options dictionary. |
61 | pub fn get_with( |
62 | src_format: format::Sample, |
63 | src_channel_layout: ChannelLayout, |
64 | src_rate: u32, |
65 | dst_format: format::Sample, |
66 | dst_channel_layout: ChannelLayout, |
67 | dst_rate: u32, |
68 | options: Dictionary, |
69 | ) -> Result<Self, Error> { |
70 | unsafe { |
71 | #[allow (unused_assignments)] |
72 | let mut ptr = std::ptr::null_mut(); |
73 | |
74 | #[cfg (not(feature = "ffmpeg_7_0" ))] |
75 | { |
76 | ptr = swr_alloc_set_opts( |
77 | ptr::null_mut(), |
78 | dst_channel_layout.bits() as i64, |
79 | dst_format.into(), |
80 | dst_rate as c_int, |
81 | src_channel_layout.bits() as i64, |
82 | src_format.into(), |
83 | src_rate as c_int, |
84 | 0, |
85 | ptr::null_mut(), |
86 | ); |
87 | } |
88 | #[cfg (feature = "ffmpeg_7_0" )] |
89 | { |
90 | let e = swr_alloc_set_opts2( |
91 | &mut ptr, |
92 | &dst_channel_layout.into(), |
93 | dst_format.into(), |
94 | dst_rate as c_int, |
95 | &src_channel_layout.into(), |
96 | src_format.into(), |
97 | src_rate as c_int, |
98 | 0, |
99 | ptr::null_mut(), |
100 | ); |
101 | if e != 0 { |
102 | return Err(Error::from(e)); |
103 | } |
104 | } |
105 | |
106 | let mut opts = options.disown(); |
107 | let res = av_opt_set_dict(ptr as *mut c_void, &mut opts); |
108 | Dictionary::own(opts); |
109 | |
110 | if res != 0 { |
111 | return Err(Error::from(res)); |
112 | } |
113 | |
114 | if !ptr.is_null() { |
115 | match swr_init(ptr) { |
116 | e if e < 0 => Err(Error::from(e)), |
117 | |
118 | _ => Ok(Context { |
119 | ptr, |
120 | |
121 | input: Definition { |
122 | format: src_format, |
123 | channel_layout: src_channel_layout, |
124 | rate: src_rate, |
125 | }, |
126 | |
127 | output: Definition { |
128 | format: dst_format, |
129 | channel_layout: dst_channel_layout, |
130 | rate: dst_rate, |
131 | }, |
132 | }), |
133 | } |
134 | } else { |
135 | Err(Error::InvalidData) |
136 | } |
137 | } |
138 | } |
139 | |
140 | /// Get the input definition. |
141 | pub fn input(&self) -> &Definition { |
142 | &self.input |
143 | } |
144 | |
145 | /// Get the output definition. |
146 | pub fn output(&self) -> &Definition { |
147 | &self.output |
148 | } |
149 | |
150 | /// Get the remaining delay. |
151 | pub fn delay(&self) -> Option<Delay> { |
152 | unsafe { |
153 | match swr_get_delay(self.as_ptr() as *mut _, 1) { |
154 | 0 => None, |
155 | _ => Some(Delay::from(self)), |
156 | } |
157 | } |
158 | } |
159 | |
160 | /// Run the resampler from the given input to the given output. |
161 | /// |
162 | /// When there are internal frames to process it will return `Ok(Some(Delay { .. }))`. |
163 | pub fn run( |
164 | &mut self, |
165 | input: &frame::Audio, |
166 | output: &mut frame::Audio, |
167 | ) -> Result<Option<Delay>, Error> { |
168 | unsafe { |
169 | (*output.as_mut_ptr()).sample_rate = self.output.rate as i32; |
170 | } |
171 | |
172 | unsafe { |
173 | if output.is_empty() { |
174 | output.alloc( |
175 | self.output.format, |
176 | input.samples(), |
177 | self.output.channel_layout, |
178 | ); |
179 | } |
180 | |
181 | match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), input.as_ptr()) { |
182 | 0 => Ok(self.delay()), |
183 | |
184 | e => Err(Error::from(e)), |
185 | } |
186 | } |
187 | } |
188 | |
189 | /// Convert one of the remaining internal frames. |
190 | /// |
191 | /// When there are no more internal frames `Ok(None)` will be returned. |
192 | pub fn flush(&mut self, output: &mut frame::Audio) -> Result<Option<Delay>, Error> { |
193 | unsafe { |
194 | (*output.as_mut_ptr()).sample_rate = self.output.rate as i32; |
195 | } |
196 | |
197 | unsafe { |
198 | match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), ptr::null()) { |
199 | 0 => Ok(self.delay()), |
200 | |
201 | e => Err(Error::from(e)), |
202 | } |
203 | } |
204 | } |
205 | } |
206 | |
207 | impl Drop for Context { |
208 | fn drop(&mut self) { |
209 | unsafe { |
210 | swr_free(&mut self.as_mut_ptr()); |
211 | } |
212 | } |
213 | } |
214 | |