ffmpeg_the_third/software/resampling/
context.rs1use std::ptr;
2
3use super::Delay;
4use crate::ffi::*;
5use crate::util::format;
6use crate::Dictionary;
7use crate::{frame, ChannelLayoutMask, Error};
8use libc::c_int;
9use std::ffi::c_void;
10
11#[cfg(feature = "ffmpeg_5_1")]
12use crate::ChannelLayout;
13
14#[derive(Eq, PartialEq, Copy, Clone)]
15pub struct Definition {
16 pub format: format::Sample,
17 pub channel_layout: ChannelLayoutMask,
18 pub rate: u32,
19}
20
21pub struct Context {
22 ptr: *mut SwrContext,
23
24 input: Definition,
25 output: Definition,
26}
27
28unsafe impl Send for Context {}
29
30impl Context {
31 #[doc(hidden)]
32 pub unsafe fn as_ptr(&self) -> *const SwrContext {
33 self.ptr as *const _
34 }
35
36 #[doc(hidden)]
37 pub unsafe fn as_mut_ptr(&mut self) -> *mut SwrContext {
38 self.ptr
39 }
40}
41
42impl Context {
43 #[cfg(not(feature = "ffmpeg_7_0"))]
45 pub fn get(
46 src_format: format::Sample,
47 src_channel_layout: ChannelLayoutMask,
48 src_rate: u32,
49 dst_format: format::Sample,
50 dst_channel_layout: ChannelLayoutMask,
51 dst_rate: u32,
52 ) -> Result<Self, Error> {
53 Self::get_with(
54 src_format,
55 src_channel_layout,
56 src_rate,
57 dst_format,
58 dst_channel_layout,
59 dst_rate,
60 Dictionary::new(),
61 )
62 }
63
64 #[cfg(not(feature = "ffmpeg_7_0"))]
66 pub fn get_with(
67 src_format: format::Sample,
68 src_channel_layout: ChannelLayoutMask,
69 src_rate: u32,
70 dst_format: format::Sample,
71 dst_channel_layout: ChannelLayoutMask,
72 dst_rate: u32,
73 options: Dictionary,
74 ) -> Result<Self, Error> {
75 unsafe {
76 let 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 let mut opts = options.disown();
89 let res = av_opt_set_dict(ptr as *mut c_void, &mut opts);
90 Dictionary::own(opts);
91
92 if res != 0 {
93 return Err(Error::from(res));
94 }
95
96 if !ptr.is_null() {
97 match swr_init(ptr) {
98 e if e < 0 => Err(Error::from(e)),
99
100 _ => Ok(Context {
101 ptr,
102
103 input: Definition {
104 format: src_format,
105 channel_layout: src_channel_layout,
106 rate: src_rate,
107 },
108
109 output: Definition {
110 format: dst_format,
111 channel_layout: dst_channel_layout,
112 rate: dst_rate,
113 },
114 }),
115 }
116 } else {
117 Err(Error::InvalidData)
118 }
119 }
120 }
121
122 #[cfg(feature = "ffmpeg_5_1")]
124 pub fn get2(
125 src_format: format::Sample,
126 src_channel_layout: ChannelLayout,
127 src_rate: u32,
128 dst_format: format::Sample,
129 dst_channel_layout: ChannelLayout,
130 dst_rate: u32,
131 ) -> Result<Self, Error> {
132 Self::get_with2(
133 src_format,
134 src_channel_layout,
135 src_rate,
136 dst_format,
137 dst_channel_layout,
138 dst_rate,
139 Dictionary::new(),
140 )
141 }
142
143 #[cfg(feature = "ffmpeg_5_1")]
145 pub fn get_with2(
146 src_format: format::Sample,
147 src_channel_layout: ChannelLayout,
148 src_rate: u32,
149 dst_format: format::Sample,
150 dst_channel_layout: ChannelLayout,
151 dst_rate: u32,
152 options: Dictionary,
153 ) -> Result<Self, Error> {
154 unsafe {
155 let mut context_ptr = ptr::null_mut();
156 let res = swr_alloc_set_opts2(
157 ptr::addr_of_mut!(context_ptr),
158 dst_channel_layout.as_ptr() as _,
159 dst_format.into(),
160 dst_rate as c_int,
161 src_channel_layout.as_ptr() as _,
162 src_format.into(),
163 src_rate as c_int,
164 0,
165 ptr::null_mut(),
166 );
167
168 if res < 0 {
169 return Err(Error::from(res));
170 }
171
172 let mut opts = options.disown();
173 let res = av_opt_set_dict(context_ptr as *mut c_void, &mut opts);
174 Dictionary::own(opts);
175
176 if res != 0 {
177 return Err(Error::from(res));
178 }
179
180 if !context_ptr.is_null() {
181 match swr_init(context_ptr) {
182 e if e < 0 => Err(Error::from(e)),
183
184 _ => Ok(Context {
185 ptr: context_ptr,
186
187 input: Definition {
188 format: src_format,
189 channel_layout: src_channel_layout.mask().unwrap(),
190 rate: src_rate,
191 },
192
193 output: Definition {
194 format: dst_format,
195 channel_layout: dst_channel_layout.mask().unwrap(),
196 rate: dst_rate,
197 },
198 }),
199 }
200 } else {
201 Err(Error::InvalidData)
202 }
203 }
204 }
205
206 pub fn input(&self) -> &Definition {
208 &self.input
209 }
210
211 pub fn output(&self) -> &Definition {
213 &self.output
214 }
215
216 pub fn delay(&self) -> Option<Delay> {
218 unsafe {
219 match swr_get_delay(self.as_ptr() as *mut _, 1) {
220 0 => None,
221 _ => Some(Delay::from(self)),
222 }
223 }
224 }
225
226 pub fn run(
230 &mut self,
231 input: &frame::Audio,
232 output: &mut frame::Audio,
233 ) -> Result<Option<Delay>, Error> {
234 unsafe {
235 (*output.as_mut_ptr()).sample_rate = self.output.rate as i32;
236 }
237
238 unsafe {
239 if output.is_empty() {
240 output.alloc(
241 self.output.format,
242 input.samples(),
243 self.output.channel_layout,
244 );
245 }
246
247 match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), input.as_ptr()) {
248 0 => Ok(self.delay()),
249
250 e => Err(Error::from(e)),
251 }
252 }
253 }
254
255 pub fn flush(&mut self, output: &mut frame::Audio) -> Result<Option<Delay>, Error> {
259 unsafe {
260 (*output.as_mut_ptr()).sample_rate = self.output.rate as i32;
261 }
262
263 unsafe {
264 match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), ptr::null()) {
265 0 => Ok(self.delay()),
266
267 e => Err(Error::from(e)),
268 }
269 }
270 }
271}
272
273impl Drop for Context {
274 fn drop(&mut self) {
275 unsafe {
276 swr_free(&mut self.as_mut_ptr());
277 }
278 }
279}