Skip to main content

ffmpeg_next/software/resampling/
context.rs

1use std::ptr;
2
3use super::Delay;
4use crate::Dictionary;
5use crate::ffi::*;
6use crate::util::format;
7use crate::{ChannelLayout, Error, frame};
8use libc::c_int;
9use std::ffi::c_void;
10
11#[derive(Eq, PartialEq, Copy, Clone)]
12pub struct Definition {
13    pub format: format::Sample,
14    pub channel_layout: ChannelLayout,
15    pub rate: u32,
16}
17
18pub struct Context {
19    ptr: *mut SwrContext,
20
21    input: Definition,
22    output: Definition,
23}
24
25unsafe impl Send for Context {}
26
27impl 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
39impl 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        Some(Delay::from(self)).filter(|d| d.output > 0)
153    }
154
155    /// Run the resampler from the given input to the given output.
156    ///
157    /// When there are internal frames to process it will return `Ok(Some(Delay { .. }))`.
158    pub fn run(
159        &mut self,
160        input: &frame::Audio,
161        output: &mut frame::Audio,
162    ) -> Result<Option<Delay>, Error> {
163        unsafe {
164            (*output.as_mut_ptr()).sample_rate = self.output.rate as i32;
165        }
166
167        unsafe {
168            if output.is_empty() {
169                output.alloc(
170                    self.output.format,
171                    input.samples(),
172                    self.output.channel_layout,
173                );
174            }
175
176            match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), input.as_ptr()) {
177                0 => Ok(self.delay()),
178
179                e => Err(Error::from(e)),
180            }
181        }
182    }
183
184    /// Convert one of the remaining internal frames.
185    ///
186    /// When there are no more internal frames `Ok(None)` will be returned.
187    pub fn flush(&mut self, output: &mut frame::Audio) -> Result<Option<Delay>, Error> {
188        unsafe {
189            (*output.as_mut_ptr()).sample_rate = self.output.rate as i32;
190        }
191
192        unsafe {
193            match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), ptr::null()) {
194                0 => Ok(self.delay()),
195
196                e => Err(Error::from(e)),
197            }
198        }
199    }
200}
201
202impl Drop for Context {
203    fn drop(&mut self) {
204        unsafe {
205            swr_free(&mut self.as_mut_ptr());
206        }
207    }
208}