Skip to main content

mp3lame_encoder/
input.rs

1use super::{Encoder, ffi};
2
3use core::ptr;
4use core::ffi::{c_int, c_long};
5
6///Type of PCM input for encoder
7///
8///Please note that while you can implement your own trait, it is your responsibility to ensure
9///that `encode` function is correct and safe.
10pub trait EncoderInput {
11    ///Encodes `self` using provided encoder.
12    ///
13    ///## Arguments
14    ///
15    ///- `output_buf` - is guaranteed to never to be `null`;
16    ///- `output_len` - is guaranteed to be capacity of memory pointed by `output_buf`.
17    ///
18    ///## Returns
19    ///
20    ///Zero or positive integer to indicate success and number of bytes written.
21    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int;
22}
23
24///PCM data with only 1 channel
25///
26///In this case, number of samples is always equals to number of samples in slice.
27pub struct MonoPcm<'a, T>(pub &'a [T]);
28
29impl EncoderInput for MonoPcm<'_, u16> {
30    #[inline(always)]
31    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
32        unsafe {
33            ffi::lame_encode_buffer(encoder.ptr(), self.0.as_ptr() as _, ptr::null(), self.0.len() as _, output_buf as _, output_len as _)
34        }
35    }
36}
37
38impl EncoderInput for MonoPcm<'_, i16> {
39    #[inline(always)]
40    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
41        unsafe {
42            ffi::lame_encode_buffer(encoder.ptr(), self.0.as_ptr(), ptr::null(), self.0.len() as _, output_buf as _, output_len as _)
43        }
44    }
45}
46
47//On most platforms it should be i32
48impl EncoderInput for MonoPcm<'_, c_int> {
49    #[inline(always)]
50    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
51        unsafe {
52            ffi::lame_encode_buffer_int(encoder.ptr(), self.0.as_ptr(), ptr::null(), self.0.len() as _, output_buf as _, output_len as _)
53        }
54    }
55}
56
57#[cfg(all(unix, all(not(target_arch = "x86"), not(target_arch = "arm"))))]
58//On most unix it should be i64.
59//But unclear about other platforms, so it is only implemented there as otherwise it is i32.
60impl EncoderInput for MonoPcm<'_, c_long> {
61    #[inline(always)]
62    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
63        unsafe {
64            ffi::lame_encode_buffer_long2(encoder.ptr(), self.0.as_ptr(), ptr::null(), self.0.len() as _, output_buf as _, output_len as _)
65        }
66    }
67}
68
69impl EncoderInput for MonoPcm<'_, f32> {
70    #[inline(always)]
71    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
72        unsafe {
73            ffi::lame_encode_buffer_ieee_float(encoder.ptr(), self.0.as_ptr(), ptr::null(), self.0.len() as _, output_buf as _, output_len as _)
74        }
75    }
76}
77
78impl EncoderInput for MonoPcm<'_, f64> {
79    #[inline(always)]
80    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
81        unsafe {
82            ffi::lame_encode_buffer_ieee_double(encoder.ptr(), self.0.as_ptr(), ptr::null(), self.0.len() as _, output_buf as _, output_len as _)
83        }
84    }
85}
86
87///PCM data represented by two channels.
88///
89///Number of samples must be equal between left and right channels.
90///
91///If you want to feed encoder single PCM data, then use [MonoPcm](MonoPcm)
92///In case length of channels is not equal, it will always feed encoder minimum of both length.
93///In debug mode it will panic in this case also to warn you of error.
94pub struct DualPcm<'a, T> {
95    ///left channel PCM data
96    pub left: &'a [T],
97    ///right channel PCM data
98    pub right: &'a [T],
99}
100
101impl EncoderInput for DualPcm<'_, i16> {
102    #[inline(always)]
103    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
104        debug_assert_eq!(self.left.len(), self.right.len());
105        let samples_num = core::cmp::min(self.left.len(), self.right.len());
106        unsafe {
107            ffi::lame_encode_buffer(encoder.ptr(), self.left.as_ptr(), self.right.as_ptr(), samples_num as _, output_buf as _, output_len as _)
108        }
109    }
110}
111
112impl EncoderInput for DualPcm<'_, u16> {
113    #[inline(always)]
114    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
115        debug_assert_eq!(self.left.len(), self.right.len());
116        let samples_num = core::cmp::min(self.left.len(), self.right.len());
117        unsafe {
118            ffi::lame_encode_buffer(encoder.ptr(), self.left.as_ptr() as _, self.right.as_ptr() as _, samples_num as _, output_buf as _, output_len as _)
119        }
120    }
121}
122
123impl EncoderInput for DualPcm<'_, c_int> {
124    #[inline(always)]
125    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
126        debug_assert_eq!(self.left.len(), self.right.len());
127        let samples_num = core::cmp::min(self.left.len(), self.right.len());
128        unsafe {
129            ffi::lame_encode_buffer_int(encoder.ptr(), self.left.as_ptr(), self.right.as_ptr(), samples_num as _, output_buf as _, output_len as _)
130        }
131    }
132}
133
134impl EncoderInput for DualPcm<'_, f32> {
135    #[inline(always)]
136    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
137        debug_assert_eq!(self.left.len(), self.right.len());
138        let samples_num = core::cmp::min(self.left.len(), self.right.len());
139        unsafe {
140            ffi::lame_encode_buffer_ieee_float(encoder.ptr(), self.left.as_ptr() as _, self.right.as_ptr() as _, samples_num as _, output_buf as _, output_len as _)
141        }
142    }
143}
144
145impl EncoderInput for DualPcm<'_, f64> {
146    #[inline(always)]
147    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
148        debug_assert_eq!(self.left.len(), self.right.len());
149        let samples_num = core::cmp::min(self.left.len(), self.right.len());
150        unsafe {
151            ffi::lame_encode_buffer_ieee_double(encoder.ptr(), self.left.as_ptr() as _, self.right.as_ptr() as _, samples_num as _, output_buf as _, output_len as _)
152        }
153    }
154}
155
156///PCM data in interleaved form
157///
158///Interleaved input assumes you have two channels encoded within continuous buffer as sequence pairs: `[<left>, <right>...]`
159///Hence, number of samples is always `data.len() / 2`.
160///
161///If it is not your case, encoding will panic in debug mode, but otherwise you most likely to get incomplete output.
162pub struct InterleavedPcm<'a, T>(pub &'a [T]);
163
164impl EncoderInput for InterleavedPcm<'_, i16> {
165    #[inline(always)]
166    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
167        let samples_num = self.0.len() / 2;
168        debug_assert_eq!(self.0.len() % 2, 0);
169        //lame_encode_buffer_interleaved() signature takes mutable pointer, but all other functions const*, wtf?
170        unsafe {
171            ffi::lame_encode_buffer_interleaved(encoder.ptr(), self.0.as_ptr() as _, samples_num as _, output_buf as _, output_len as _)
172        }
173    }
174}
175
176impl EncoderInput for InterleavedPcm<'_, u16> {
177    #[inline(always)]
178    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
179        let samples_num = self.0.len() / 2;
180        debug_assert_eq!(self.0.len() % 2, 0);
181        //lame_encode_buffer_interleaved() signature takes mutable pointer, but all other functions const*, wtf?
182        unsafe {
183            ffi::lame_encode_buffer_interleaved(encoder.ptr(), self.0.as_ptr() as _, samples_num as _, output_buf as _, output_len as _)
184        }
185    }
186}
187
188impl EncoderInput for InterleavedPcm<'_, c_int> {
189    #[inline(always)]
190    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
191        let samples_num = self.0.len() / 2;
192        debug_assert_eq!(self.0.len() % 2, 0);
193        unsafe {
194            ffi::lame_encode_buffer_interleaved_int(encoder.ptr(), self.0.as_ptr(), samples_num as _, output_buf as _, output_len as _)
195        }
196    }
197}
198
199impl EncoderInput for InterleavedPcm<'_, f32> {
200    #[inline(always)]
201    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
202        let samples_num = self.0.len() / 2;
203        debug_assert_eq!(self.0.len() % 2, 0);
204        unsafe {
205            ffi::lame_encode_buffer_interleaved_ieee_float(encoder.ptr(), self.0.as_ptr(), samples_num as _, output_buf as _, output_len as _)
206        }
207    }
208}
209
210impl EncoderInput for InterleavedPcm<'_, f64> {
211    #[inline(always)]
212    fn encode(self, encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
213        let samples_num = self.0.len() / 2;
214        debug_assert_eq!(self.0.len() % 2, 0);
215        unsafe {
216            ffi::lame_encode_buffer_interleaved_ieee_double(encoder.ptr(), self.0.as_ptr(), samples_num as _, output_buf as _, output_len as _)
217        }
218    }
219}
220
221///Flush method.
222pub trait EncoderFlush {
223    ///Performs flush, returning result as signed integer.
224    ///
225    ///## Arguments
226    ///
227    ///- `output_buf` - is guaranteed to never to be `null`;
228    ///- `output_len` - is guaranteed to be capacity of memory pointed by `output_buf`.
229    ///
230    ///## Returns
231    ///
232    ///Zero or positive integer to indicate success and number of bytes written.
233    fn flush(encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int;
234}
235
236///Performs flush, padding gaps with 0
237pub struct FlushGap;
238
239impl EncoderFlush for FlushGap {
240    #[allow(clippy::not_unsafe_ptr_arg_deref)]
241    #[inline(always)]
242    fn flush(encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
243        unsafe {
244            ffi::lame_encode_flush(encoder.ptr(), output_buf, output_len as _)
245        }
246    }
247}
248
249///Performs flush, padding it with ancillary data
250pub struct FlushNoGap;
251
252impl EncoderFlush for FlushNoGap {
253    #[allow(clippy::not_unsafe_ptr_arg_deref)]
254    #[inline(always)]
255    fn flush(encoder: &mut Encoder, output_buf: *mut u8, output_len: usize) -> c_int {
256        unsafe {
257            ffi::lame_encode_flush_nogap(encoder.ptr(), output_buf, output_len as _)
258        }
259    }
260}