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, AudioEncoder, 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<AudioEncoder> 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
93const MAX_FRAME_SIZE: usize = 1275;
95const MAX_FRAMES: usize = 6;
97const PACKET_HEADER_SIZE: usize = 7;
99
100impl Encoder<AudioEncoder> for OpusEncoder {
101 fn send_frame(&mut self, _config: &AudioEncoder, 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 channels = desc.channels().get() as usize;
113 let sample_size = channels * sample_format.bytes() as usize;
114 let frame_data = planes.plane_data(0).unwrap();
115 let frame_data_size = desc.samples.get() as usize * sample_size;
116 let chunk_size = self.options.frame_size as usize * sample_size;
117 let mut pts = frame.pts.unwrap_or(0);
118
119 self.buffer.fill(0);
120
121 for chunk in frame_data[..frame_data_size].chunks(chunk_size) {
122 let mut packet = Packet::new(packet_size);
123 let packet_data = packet.data_mut().ok_or(Error::Invalid("packet not writable".into()))?;
124 let data = if chunk.len() < chunk_size {
125 self.buffer[..chunk.len()].copy_from_slice(chunk);
126 self.buffer.as_slice()
127 } else {
128 chunk
129 };
130
131 let ret = match desc.format {
132 SampleFormat::S16 => {
133 let data = bytemuck::cast_slice::<u8, i16>(data);
134 unsafe {
135 opus_sys::opus_encode(
136 self.encoder,
137 data.as_ptr(),
138 (data.len() / channels) as i32,
139 packet_data.as_mut_ptr(),
140 packet_data.len() as i32,
141 )
142 }
143 }
144 SampleFormat::F32 => {
145 let data = bytemuck::cast_slice::<u8, f32>(data);
146 unsafe {
147 opus_sys::opus_encode_float(
148 self.encoder,
149 data.as_ptr(),
150 (data.len() / channels) as i32,
151 packet_data.as_mut_ptr(),
152 packet_data.len() as i32,
153 )
154 }
155 }
156 _ => return Err(unsupported_error!(sample_format)),
157 };
158
159 if ret < 0 {
160 return Err(Error::Failed(opus_error_string(ret)));
161 }
162
163 let samples = self.options.frame_size as i64;
164 let (duration, time_base) = if let Some(time_base) = frame.time_base {
165 let duration = (Rational64::new(samples, desc.sample_rate.get() as i64) / time_base).to_integer();
166 (duration, time_base)
167 } else {
168 let time_base = Rational64::new(1, desc.sample_rate.get() as i64);
169 let duration = samples;
170 (duration, time_base)
171 };
172
173 packet.pts = Some(pts);
174 packet.duration = Some(duration);
175 packet.time_base = Some(time_base);
176 pts += duration;
177
178 packet.truncate(ret as usize)?;
179
180 self.pending.push_back(packet);
181 }
182
183 Ok(())
184 }
185
186 fn receive_packet_borrowed(&mut self, _parameters: &AudioEncoder) -> Result<Packet<'_>> {
187 self.pending.pop_front().ok_or_else(|| Error::Again("no packet available".to_string()))
188 }
189
190 fn flush(&mut self, _config: &AudioEncoder) -> Result<()> {
191 self.buffer.fill(0);
192
193 Ok(())
194 }
195}
196
197impl Drop for OpusEncoder {
198 fn drop(&mut self) {
199 unsafe { opus_sys::opus_encoder_destroy(self.encoder) }
200 }
201}
202
203impl OpusEncoder {
204 pub fn new(codec_id: CodecID, parameters: &AudioEncoderParameters, options: Option<&Variant>) -> Result<Self> {
205 if codec_id != CodecID::Opus {
206 return Err(unsupported_error!(codec_id));
207 }
208
209 let mut opts = OpusOptions::from_variant(options);
210
211 let audio_params = ¶meters.audio;
212 let sample_format = audio_params.format.ok_or(invalid_param_error!(parameters))?;
213
214 if sample_format != SampleFormat::S16 && sample_format != SampleFormat::F32 {
215 return Err(unsupported_error!(sample_format));
216 }
217
218 let sample_rate = audio_params.sample_rate.ok_or(invalid_param_error!(parameters))?.get() as opus_sys::opus_int32;
219 let channels = audio_params.channel_layout.as_ref().ok_or(invalid_param_error!(parameters))?.channels.get() as c_int;
220
221 let frame_size = (opts.frame_duration * 48000f32 / 1000f32) as u32;
223 match frame_size {
224 120 | 240 => {
226 if opts.application != opus_sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY {
227 opts.application = opus_sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY;
228 }
229 }
230 480 | 960 | 1920 | 2880 | 3840 | 4800 | 5760 => {}
232 _ => return Err(Error::Invalid("frame duration".into())),
233 }
234
235 opts.frame_size = frame_size * sample_rate as u32 / 48000;
236
237 let mut error = 0;
238 let opus_encoder = unsafe { opus_sys::opus_encoder_create(sample_rate, channels, opts.application, &mut error) };
239 if opus_encoder.is_null() || error != opus_sys::OPUS_OK {
240 return Err(Error::CreationFailed(opus_error_string(error)));
241 }
242
243 let mut encoder: OpusEncoder = OpusEncoder {
244 encoder: opus_encoder,
245 pending: VecDeque::new(),
246 options: opts,
247 buffer: vec![0u8; frame_size as usize * channels as usize * sample_format.bytes() as usize],
248 };
249
250 encoder.set_audio_parameters(audio_params)?;
251 encoder.set_encoder_parameters(¶meters.encoder)?;
252 encoder.update_options()?;
253
254 Ok(encoder)
255 }
256
257 fn encoder_ctl(&mut self, key: i32, value: i32) -> Result<()> {
258 let ret = unsafe { opus_sys::opus_encoder_ctl(self.encoder, key, value) };
259
260 if ret != opus_sys::OPUS_OK {
261 return Err(Error::SetFailed(opus_error_string(ret)));
262 }
263
264 Ok(())
265 }
266
267 fn set_audio_parameters(&mut self, _audio_params: &AudioParameters) -> Result<()> {
268 Ok(())
269 }
270
271 fn set_encoder_parameters(&mut self, encoder_params: &EncoderParameters) -> Result<()> {
272 if let Some(bit_rate) = encoder_params.bit_rate {
273 self.encoder_ctl(opus_sys::OPUS_SET_BITRATE_REQUEST, bit_rate as i32)?;
274 }
275
276 if let Some(level) = encoder_params.level {
277 self.options.complexity = if !(0..=10).contains(&level) {
278 10
279 } else {
280 level as u32
281 };
282 }
283
284 Ok(())
285 }
286
287 fn update_options(&mut self) -> Result<()> {
288 self.encoder_ctl(opus_sys::OPUS_SET_VBR_REQUEST, (self.options.vbr > 0) as i32)?;
289 self.encoder_ctl(opus_sys::OPUS_SET_VBR_CONSTRAINT_REQUEST, (self.options.vbr == 2) as i32)?;
290 self.encoder_ctl(opus_sys::OPUS_SET_PACKET_LOSS_PERC_REQUEST, self.options.packet_loss)?;
291 self.encoder_ctl(opus_sys::OPUS_SET_INBAND_FEC_REQUEST, self.options.fec as i32)?;
292
293 if self.options.complexity > 0 {
294 self.encoder_ctl(opus_sys::OPUS_SET_COMPLEXITY_REQUEST, self.options.complexity as i32)?;
295 }
296
297 if self.options.max_bandwidth > 0 {
298 self.encoder_ctl(opus_sys::OPUS_SET_MAX_BANDWIDTH_REQUEST, self.options.max_bandwidth as i32)?;
299 }
300
301 Ok(())
302 }
303}
304
305const CODEC_NAME: &str = "opus-enc";
306
307pub struct OpusEncoderBuilder;
308
309impl EncoderBuilder<AudioEncoder> for OpusEncoderBuilder {
310 fn new_encoder(
311 &self,
312 codec_id: CodecID,
313 parameters: &AudioEncoderParameters,
314 options: Option<&Variant>,
315 ) -> Result<Box<dyn Encoder<AudioEncoder>>> {
316 Ok(Box::new(OpusEncoder::new(codec_id, parameters, options)?))
317 }
318}
319
320impl CodecBuilder<AudioEncoder> for OpusEncoderBuilder {
321 fn id(&self) -> CodecID {
322 CodecID::Opus
323 }
324
325 fn name(&self) -> &'static str {
326 CODEC_NAME
327 }
328}
329
330impl CodecInfomation for OpusEncoder {
331 fn id(&self) -> CodecID {
332 CodecID::Opus
333 }
334
335 fn name(&self) -> &'static str {
336 CODEC_NAME
337 }
338}
339
340#[ctor]
341pub fn initialize() {
342 register_encoder(Arc::new(OpusEncoderBuilder), false);
343}