media_codec_opus/
encoder.rs

1use std::{collections::VecDeque, os::raw::c_int, sync::Arc};
2
3use bytemuck;
4use ctor::ctor;
5use media_codec::{
6    codec::{AudioParameters, Codec, CodecBuilder, CodecID},
7    encoder::{register_encoder, AudioEncoderConfiguration, AudioEncoderParameters, Encoder, EncoderBuilder, EncoderParameters},
8    packet::Packet,
9    CodecInfomation,
10};
11use media_core::{
12    audio::SampleFormat, error::Error, frame::Frame, invalid_param_error, rational::Rational64, unsupported_error, variant::Variant, Result,
13};
14
15use crate::{opus_error_string, opus_sys};
16
17struct OpusOptions {
18    application: i32,
19    frame_duration: f32,
20    frame_size: u32,
21    packet_loss: i32,
22    fec: bool,
23    vbr: u32,
24    max_bandwidth: u32,
25    complexity: u32,
26}
27
28impl Default for OpusOptions {
29    fn default() -> Self {
30        OpusOptions {
31            application: opus_sys::OPUS_APPLICATION_AUDIO,
32            frame_duration: 20.0,
33            frame_size: 960,
34            packet_loss: 0,
35            fec: false,
36            vbr: 1,
37            max_bandwidth: 0,
38            complexity: 10,
39        }
40    }
41}
42
43impl OpusOptions {
44    fn from_variant(variant: Option<&Variant>) -> Self {
45        if let Some(variant) = variant {
46            let application = variant["application"].get_int32().unwrap_or(opus_sys::OPUS_APPLICATION_AUDIO);
47            let frame_duration = variant["frame_duration"].get_float().unwrap_or(20.0);
48            let packet_loss = variant["packet_loss"].get_int32().unwrap_or(0);
49            let fec = variant["fec"].get_bool().unwrap_or(false);
50            let vbr = variant["vbr"].get_uint32().unwrap_or(1);
51
52            OpusOptions {
53                application,
54                frame_duration,
55                frame_size: (frame_duration * 48000f32 / 1000f32) as u32,
56                packet_loss,
57                fec,
58                vbr,
59                max_bandwidth: 0,
60                complexity: 10,
61            }
62        } else {
63            Self::default()
64        }
65    }
66}
67
68struct OpusEncoder {
69    encoder: *mut opus_sys::OpusEncoder,
70    pending: VecDeque<Packet<'static>>,
71    options: OpusOptions,
72    buffer: Vec<u8>,
73}
74
75unsafe impl Send for OpusEncoder {}
76unsafe impl Sync for OpusEncoder {}
77
78impl Codec<AudioEncoderConfiguration> for OpusEncoder {
79    fn configure(&mut self, _parameters: Option<&AudioEncoderParameters>, _options: Option<&Variant>) -> Result<()> {
80        Ok(())
81    }
82
83    fn set_option(&mut self, key: &str, value: &Variant) -> Result<()> {
84        let value = value.get_int32().ok_or_else(|| invalid_param_error!(value))?;
85
86        match key {
87            "bit_rate" => self.encoder_ctl(opus_sys::OPUS_SET_BITRATE_REQUEST, value),
88            _ => Err(unsupported_error!(key)),
89        }
90    }
91}
92
93// The maximum frame size is 1275 bytes
94const MAX_FRAME_SIZE: usize = 1275;
95// 120ms packets consist of 6 frames in one packet
96const MAX_FRAMES: usize = 6;
97// The packet header size is 7 bytes
98const PACKET_HEADER_SIZE: usize = 7;
99
100impl Encoder<AudioEncoderConfiguration> for OpusEncoder {
101    fn send_frame(&mut self, _config: &AudioEncoderConfiguration, frame: &Frame) -> Result<()> {
102        let desc = frame.audio_descriptor().ok_or(Error::Unsupported("media type".to_string()))?;
103        let sample_format = desc.format;
104
105        if sample_format != SampleFormat::S16 && sample_format != SampleFormat::F32 {
106            return Err(unsupported_error!(sample_format));
107        }
108
109        let guard = frame.map().map_err(|_| Error::Invalid("not readable".into()))?;
110        let planes = guard.planes().unwrap();
111        let packet_size = PACKET_HEADER_SIZE + MAX_FRAME_SIZE * MAX_FRAMES;
112        let sample_size = desc.channels().get() as usize * sample_format.bytes() as usize;
113        let frame_data = planes.plane_data(0).unwrap();
114        let frame_data_size = desc.samples.get() as usize * sample_size;
115        let chunk_size = self.options.frame_size as usize * sample_size;
116        let mut pts = frame.pts.unwrap_or(0);
117
118        self.buffer.fill(0);
119
120        for chunk in frame_data[..frame_data_size].chunks(chunk_size) {
121            let mut packet = Packet::new(packet_size);
122            let packet_data = packet.data_mut().ok_or(Error::Invalid("packet not writable".into()))?;
123            let data = if chunk.len() < chunk_size {
124                self.buffer[..chunk.len()].copy_from_slice(chunk);
125                self.buffer.as_slice()
126            } else {
127                chunk
128            };
129
130            let ret = match desc.format {
131                SampleFormat::S16 => {
132                    let data = bytemuck::cast_slice::<u8, i16>(data);
133                    unsafe {
134                        opus_sys::opus_encode(
135                            self.encoder,
136                            data.as_ptr(),
137                            data.len() as i32 / (sample_size as i32),
138                            packet_data.as_mut_ptr(),
139                            packet_data.len() as i32,
140                        )
141                    }
142                }
143                SampleFormat::F32 => {
144                    let data = bytemuck::cast_slice::<u8, f32>(data);
145                    unsafe {
146                        opus_sys::opus_encode_float(
147                            self.encoder,
148                            data.as_ptr(),
149                            data.len() as i32 / (sample_size as i32),
150                            packet_data.as_mut_ptr(),
151                            packet_data.len() as i32,
152                        )
153                    }
154                }
155                _ => return Err(unsupported_error!(sample_format)),
156            };
157
158            if ret < 0 {
159                return Err(Error::Failed(opus_error_string(ret)));
160            }
161
162            let samples = self.options.frame_size as i64;
163            let (duration, time_base) = if let Some(time_base) = frame.time_base {
164                let duration = (Rational64::new(samples, desc.sample_rate.get() as i64) / time_base).to_integer();
165                (duration, time_base)
166            } else {
167                let time_base = Rational64::new(1, desc.sample_rate.get() as i64);
168                let duration = samples;
169                (duration, time_base)
170            };
171
172            packet.pts = Some(pts);
173            packet.duration = Some(duration);
174            packet.time_base = Some(time_base);
175            pts += duration;
176
177            packet.truncate(ret as usize)?;
178
179            self.pending.push_back(packet);
180        }
181
182        Ok(())
183    }
184
185    fn receive_packet_borrowed(&mut self, _parameters: &AudioEncoderConfiguration) -> Result<Packet<'_>> {
186        self.pending.pop_front().ok_or_else(|| Error::Again("no packet available".to_string()))
187    }
188
189    fn flush(&mut self, _config: &AudioEncoderConfiguration) -> Result<()> {
190        self.buffer.fill(0);
191
192        Ok(())
193    }
194}
195
196impl Drop for OpusEncoder {
197    fn drop(&mut self) {
198        unsafe { opus_sys::opus_encoder_destroy(self.encoder) }
199    }
200}
201
202impl OpusEncoder {
203    pub fn new(codec_id: CodecID, parameters: &AudioEncoderParameters, options: Option<&Variant>) -> Result<Self> {
204        if codec_id != CodecID::Opus {
205            return Err(unsupported_error!(codec_id));
206        }
207
208        let mut opts = OpusOptions::from_variant(options);
209
210        let audio_params = &parameters.audio;
211        let sample_format = audio_params.format.ok_or(invalid_param_error!(parameters))?;
212
213        if sample_format != SampleFormat::S16 && sample_format != SampleFormat::F32 {
214            return Err(unsupported_error!(sample_format));
215        }
216
217        let sample_rate = audio_params.sample_rate.ok_or(invalid_param_error!(parameters))?.get() as opus_sys::opus_int32;
218        let channels = audio_params.channel_layout.as_ref().ok_or(invalid_param_error!(parameters))?.channels.get() as c_int;
219
220        // Calculate frame size in samples at 48kHz to validate frame duration
221        let frame_size = (opts.frame_duration * 48000f32 / 1000f32) as u32;
222        match frame_size {
223            // 2.5ms | 5ms
224            120 | 240 => {
225                if opts.application != opus_sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY {
226                    opts.application = opus_sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY;
227                }
228            }
229            // 10ms | 20ms | 40ms | 60ms | 80ms | 100ms | 120ms
230            480 | 960 | 1920 | 2880 | 3840 | 4800 | 5760 => {}
231            _ => return Err(Error::Invalid("frame duration".into())),
232        }
233
234        opts.frame_size = frame_size;
235
236        let mut error = 0;
237        let opus_encoder = unsafe { opus_sys::opus_encoder_create(sample_rate, channels, opts.application, &mut error) };
238        if opus_encoder.is_null() || error != opus_sys::OPUS_OK {
239            return Err(Error::CreationFailed(opus_error_string(error)));
240        }
241
242        let mut encoder: OpusEncoder = OpusEncoder {
243            encoder: opus_encoder,
244            pending: VecDeque::new(),
245            options: opts,
246            buffer: vec![0u8; frame_size as usize * channels as usize * sample_format.bytes() as usize],
247        };
248
249        encoder.set_audio_parameters(audio_params)?;
250        encoder.set_encoder_parameters(&parameters.encoder)?;
251        encoder.update_options()?;
252
253        Ok(encoder)
254    }
255
256    fn encoder_ctl(&mut self, key: i32, value: i32) -> Result<()> {
257        let ret = unsafe { opus_sys::opus_encoder_ctl(self.encoder, key, value) };
258
259        if ret != opus_sys::OPUS_OK {
260            return Err(Error::SetFailed(opus_error_string(ret)));
261        }
262
263        Ok(())
264    }
265
266    fn set_audio_parameters(&mut self, _audio_params: &AudioParameters) -> Result<()> {
267        Ok(())
268    }
269
270    fn set_encoder_parameters(&mut self, encoder_params: &EncoderParameters) -> Result<()> {
271        if let Some(bit_rate) = encoder_params.bit_rate {
272            self.encoder_ctl(opus_sys::OPUS_SET_BITRATE_REQUEST, bit_rate as i32)?;
273        }
274
275        if let Some(level) = encoder_params.level {
276            self.options.complexity = if !(0..=10).contains(&level) {
277                10
278            } else {
279                level as u32
280            };
281        }
282
283        Ok(())
284    }
285
286    fn update_options(&mut self) -> Result<()> {
287        self.encoder_ctl(opus_sys::OPUS_SET_VBR_REQUEST, (self.options.vbr > 0) as i32)?;
288        self.encoder_ctl(opus_sys::OPUS_SET_VBR_CONSTRAINT_REQUEST, (self.options.vbr == 2) as i32)?;
289        self.encoder_ctl(opus_sys::OPUS_SET_PACKET_LOSS_PERC_REQUEST, self.options.packet_loss)?;
290        self.encoder_ctl(opus_sys::OPUS_SET_INBAND_FEC_REQUEST, self.options.fec as i32)?;
291
292        if self.options.complexity > 0 {
293            self.encoder_ctl(opus_sys::OPUS_SET_COMPLEXITY_REQUEST, self.options.complexity as i32)?;
294        }
295
296        if self.options.max_bandwidth > 0 {
297            self.encoder_ctl(opus_sys::OPUS_SET_MAX_BANDWIDTH_REQUEST, self.options.max_bandwidth as i32)?;
298        }
299
300        Ok(())
301    }
302}
303
304const CODEC_NAME: &str = "opus-enc";
305
306pub struct OpusEncoderBuilder;
307
308impl EncoderBuilder<AudioEncoderConfiguration> for OpusEncoderBuilder {
309    fn new_encoder(
310        &self,
311        codec_id: CodecID,
312        parameters: &AudioEncoderParameters,
313        options: Option<&Variant>,
314    ) -> Result<Box<dyn Encoder<AudioEncoderConfiguration>>> {
315        Ok(Box::new(OpusEncoder::new(codec_id, parameters, options)?))
316    }
317}
318
319impl CodecBuilder<AudioEncoderConfiguration> for OpusEncoderBuilder {
320    fn id(&self) -> CodecID {
321        CodecID::Opus
322    }
323
324    fn name(&self) -> &'static str {
325        CODEC_NAME
326    }
327}
328
329impl CodecInfomation for OpusEncoder {
330    fn id(&self) -> CodecID {
331        CodecID::Opus
332    }
333
334    fn name(&self) -> &'static str {
335        CODEC_NAME
336    }
337}
338
339#[ctor]
340fn initialize() {
341    register_encoder(Arc::new(OpusEncoderBuilder), false);
342}