1pub(crate) mod celt;
2pub(crate) mod silk;
3
4use std::io::Write;
5use std::panic::{AssertUnwindSafe, catch_unwind};
6
7use crate::media::{AudioBuffer, Error, Packet, Result};
8use crate::opus::OpusHead;
9use crate::opus::ogg;
10use crate::opus::packet::Bandwidth;
11use crate::opus::range::RangeEncoder;
12
13use celt::{CeltEncoder, FrameParams};
14use silk::SilkEncoder;
15
16pub const FRAME: usize = 960;
17const DELAY: usize = 192;
18const CELT_DELAY: usize = 120;
19const MAX_PACKET: usize = 1276;
20const CHUNK: usize = 256;
21const HISTORY: usize = 1032;
22const SILK_DELAY: usize = 131;
23const SILK_PAD: usize = DELAY + CELT_DELAY - SILK_DELAY;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum Application {
27 Audio,
28 Voip,
29 LowDelay,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct EncoderConfig {
34 pub rate: u32,
35 pub channels: u16,
36 pub bitrate: u32,
37 pub application: Application,
38 pub vbr: bool,
39}
40
41impl EncoderConfig {
42 pub fn new(channels: u16, bitrate: u32) -> EncoderConfig {
43 EncoderConfig {
44 rate: 48000,
45 channels,
46 bitrate,
47 application: Application::Audio,
48 vbr: true,
49 }
50 }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54enum Mode {
55 Silk,
56 Celt,
57}
58
59fn mode_for(cfg: &EncoderConfig) -> Mode {
60 match cfg.application {
61 Application::LowDelay => Mode::Celt,
62 Application::Voip if cfg.bitrate <= 40_000 => Mode::Silk,
63 _ if cfg.bitrate < 16_000 => Mode::Silk,
64 _ => Mode::Celt,
65 }
66}
67
68fn silk_bandwidth(bitrate: u32) -> Bandwidth {
69 match bitrate {
70 0..8_000 => Bandwidth::Narrowband,
71 8_000..11_000 => Bandwidth::Mediumband,
72 _ => Bandwidth::Wideband,
73 }
74}
75
76impl Mode {
77 fn pad(self) -> usize {
78 match self {
79 Mode::Silk => SILK_PAD,
80 Mode::Celt => DELAY,
81 }
82 }
83}
84
85pub struct Encoder {
86 cfg: EncoderConfig,
87 mode: Mode,
88 silk: Option<Box<SilkEncoder>>,
89 scratch: Vec<f32>,
90 celt: CeltEncoder,
91 rc: RangeEncoder,
92 pending: Vec<f32>,
93 consumed: usize,
94 frames: u64,
95 input: u64,
96 final_range: u32,
97}
98
99impl Encoder {
100 pub fn new(cfg: EncoderConfig) -> Result<Encoder> {
101 if cfg.rate != 48000 {
102 return Err(Error::Unsupported(format!(
103 "Opus encoder input at {} Hz; resample to 48000 first",
104 cfg.rate
105 )));
106 }
107 if !(1..=2).contains(&cfg.channels) {
108 return Err(Error::Unsupported(format!(
109 "Opus encoder with {} channels",
110 cfg.channels
111 )));
112 }
113 if !(6_000..=510_000).contains(&cfg.bitrate) {
114 return Err(Error::Invalid(format!(
115 "Opus bitrate {} outside 6000..=510000",
116 cfg.bitrate
117 )));
118 }
119 let c = cfg.channels as usize;
120 let mode = mode_for(&cfg);
121 Ok(Encoder {
122 cfg,
123 mode,
124 silk: (mode == Mode::Silk).then(|| Box::new(SilkEncoder::new(c))),
125 scratch: Vec::new(),
126 celt: CeltEncoder::new(c),
127 rc: RangeEncoder::new(MAX_PACKET),
128 pending: vec![0.0; mode.pad() * c],
129 consumed: 0,
130 frames: 0,
131 input: 0,
132 final_range: 0,
133 })
134 }
135
136 pub fn config(&self) -> &EncoderConfig {
137 &self.cfg
138 }
139
140 pub fn pre_skip(&self) -> u16 {
141 (DELAY + CELT_DELAY) as u16
142 }
143
144 pub fn head(&self) -> OpusHead {
145 OpusHead {
146 channels: self.cfg.channels as usize,
147 pre_skip: self.pre_skip(),
148 input_sample_rate: self.cfg.rate,
149 output_gain: 0,
150 mapping_family: 0,
151 streams: 1,
152 coupled_streams: self.cfg.channels as usize - 1,
153 mapping: (0..self.cfg.channels as u8).collect(),
154 }
155 }
156
157 pub fn codec_private(&self) -> Vec<u8> {
158 self.head().to_bytes()
159 }
160
161 pub fn reset(&mut self) {
162 let c = self.cfg.channels as usize;
163 self.celt.reset();
164 if let Some(silk) = self.silk.as_mut() {
165 silk.reset();
166 }
167 self.pending.clear();
168 self.pending.resize(self.mode.pad() * c, 0.0);
169 self.consumed = 0;
170 self.frames = 0;
171 self.input = 0;
172 }
173
174 pub fn final_range(&self) -> u32 {
175 self.final_range
176 }
177
178 pub fn frame_samples(&self) -> usize {
179 FRAME
180 }
181
182 pub fn encode(&mut self, audio: &AudioBuffer) -> Result<Vec<Packet>> {
183 if audio.rate != self.cfg.rate || audio.channels != self.cfg.channels {
184 return Err(Error::Invalid(format!(
185 "audio is {} Hz x{}, encoder expects {} Hz x{}",
186 audio.rate, audio.channels, self.cfg.rate, self.cfg.channels
187 )));
188 }
189 if !audio
190 .samples
191 .len()
192 .is_multiple_of(self.cfg.channels as usize)
193 {
194 return Err(Error::Invalid(format!(
195 "{} samples do not split into {} channels",
196 audio.samples.len(),
197 self.cfg.channels
198 )));
199 }
200 self.input += audio.frames() as u64;
201 self.pending.extend_from_slice(&audio.samples);
202 let mut out = Vec::new();
203 self.drain(&mut out)?;
204 Ok(out)
205 }
206
207 pub fn flush(&mut self) -> Result<Vec<Packet>> {
208 let c = self.cfg.channels as usize;
209 let need = self.input + self.pre_skip() as u64;
210 let mut out = Vec::new();
211 while self.frames * (FRAME as u64) < need {
212 let have = self.pending.len() / c - self.consumed / c;
213 if have < FRAME {
214 self.pending
215 .resize(self.pending.len() + (FRAME - have) * c, 0.0);
216 }
217 self.drain(&mut out)?;
218 }
219 Ok(out)
220 }
221
222 fn drain(&mut self, out: &mut Vec<Packet>) -> Result<()> {
223 let c = self.cfg.channels as usize;
224 let step = FRAME * c;
225 loop {
226 let avail = (self.pending.len() - self.consumed) / step;
227 if avail == 0 {
228 break;
229 }
230 let at_chunk = self.frames.is_multiple_of(CHUNK as u64);
231 let celt = self.mode == Mode::Celt;
232 if celt && at_chunk && avail >= 2 * CHUNK && rayon::current_num_threads() > 1 {
233 self.encode_chunks(avail / CHUNK, out)?;
234 continue;
235 }
236 if celt && at_chunk && self.frames > 0 {
237 let h = self.consumed.saturating_sub(HISTORY * c);
238 self.celt.prime(&self.pending[h..self.consumed]);
239 }
240 let start = self.consumed;
241 self.consumed += step;
242 let pcm = &self.pending[start..start + step];
243 let (cfg, rc, index) = (&self.cfg, &mut self.rc, self.frames);
244 let (pkt, rng) = match self.silk.as_deref_mut() {
245 Some(silk) => {
246 let scratch = &mut self.scratch;
247 catch_unwind(AssertUnwindSafe(|| {
248 encode_silk(cfg, silk, rc, pcm, index, scratch)
249 }))
250 }
251 None => {
252 let celt = &mut self.celt;
253 catch_unwind(AssertUnwindSafe(|| {
254 encode_packet(cfg, celt, rc, pcm, index)
255 }))
256 }
257 }
258 .map_err(|_| crashed())?;
259 self.final_range = rng;
260 self.frames += 1;
261 out.push(pkt);
262 }
263 let keep = HISTORY * c;
264 if self.consumed > keep && (self.consumed - keep) * 2 >= self.pending.len() {
265 self.pending.drain(..self.consumed - keep);
266 self.consumed = keep;
267 }
268 Ok(())
269 }
270
271 fn encode_chunks(&mut self, chunks: usize, out: &mut Vec<Packet>) -> Result<()> {
272 use rayon::prelude::*;
273 let c = self.cfg.channels as usize;
274 let step = FRAME * c;
275 let cfg = self.cfg;
276 let base = self.consumed;
277 let first = self.frames;
278 let pending = &self.pending;
279 let done: Vec<Option<(Vec<Packet>, CeltEncoder, u32)>> = (0..chunks)
280 .into_par_iter()
281 .map(|k| {
282 catch_unwind(|| {
283 let mut celt = CeltEncoder::new(c);
284 let mut rc = RangeEncoder::new(MAX_PACKET);
285 let start = base + k * CHUNK * step;
286 let f0 = first + (k * CHUNK) as u64;
287 if f0 > 0 {
288 celt.prime(&pending[start.saturating_sub(HISTORY * c)..start]);
289 }
290 let mut packets = Vec::with_capacity(CHUNK);
291 let mut rng = 0;
292 for i in 0..CHUNK {
293 let s = start + i * step;
294 let (p, r) = encode_packet(
295 &cfg,
296 &mut celt,
297 &mut rc,
298 &pending[s..s + step],
299 f0 + i as u64,
300 );
301 packets.push(p);
302 rng = r;
303 }
304 (packets, celt, rng)
305 })
306 .ok()
307 })
308 .collect();
309 if done.iter().any(Option::is_none) {
310 return Err(crashed());
311 }
312 let mut last = None;
313 for (packets, celt, rng) in done.into_iter().flatten() {
314 out.extend(packets);
315 last = Some((celt, rng));
316 }
317 if let Some((celt, rng)) = last {
318 self.celt = celt;
319 self.final_range = rng;
320 }
321 self.frames += (chunks * CHUNK) as u64;
322 self.consumed += chunks * CHUNK * step;
323 Ok(())
324 }
325}
326
327fn crashed() -> Error {
328 Error::Backend("Opus encoder failed on this input".into())
329}
330
331fn encode_silk(
332 cfg: &EncoderConfig,
333 silk: &mut SilkEncoder,
334 rc: &mut RangeEncoder,
335 pcm: &[f32],
336 index: u64,
337 scratch: &mut Vec<f32>,
338) -> (Packet, u32) {
339 let c = cfg.channels as usize;
340 let bw = silk_bandwidth(cfg.bitrate);
341 scratch.clear();
342 scratch.extend(pcm.iter().map(|&v| {
343 if v.is_finite() {
344 v.clamp(-1.0, 1.0)
345 } else {
346 0.0
347 }
348 }));
349 let bytes = ((cfg.bitrate as usize * FRAME) / (48000 * 8)).clamp(3, MAX_PACKET);
350 rc.reset(MAX_PACKET - 1);
351 silk.encode(rc, scratch, bw, ((bytes - 1) * 8) as u32);
352 let used = (((rc.tell() + 7) >> 3).max(1) as usize).min(MAX_PACKET - 1);
353 let config: u8 = match bw {
354 Bandwidth::Narrowband => 1,
355 Bandwidth::Mediumband => 5,
356 _ => 9,
357 };
358 let toc = (config << 3) | (((c == 2) as u8) << 2);
359 let frame = &rc.finish()[..used];
360 let mut data = Vec::with_capacity(bytes.max(used + 1));
361 if !cfg.vbr && used + 3 <= bytes {
362 let rem = bytes - 2 - used;
363 data.push(toc | 3);
364 data.push(0x41);
365 data.extend(std::iter::repeat_n(255u8, (rem - 1) / 255));
366 data.push(((rem - 1) % 255) as u8);
367 data.extend_from_slice(frame);
368 data.resize(bytes, 0);
369 } else {
370 data.push(toc);
371 data.extend_from_slice(frame);
372 }
373 let pts = index as i64 * FRAME as i64;
374 (
375 Packet {
376 data,
377 pts,
378 dts: pts,
379 keyframe: true,
380 },
381 rc.rng(),
382 )
383}
384
385fn encode_packet(
386 cfg: &EncoderConfig,
387 celt: &mut CeltEncoder,
388 rc: &mut RangeEncoder,
389 pcm: &[f32],
390 index: u64,
391) -> (Packet, u32) {
392 let c = cfg.channels as usize;
393 let end = Bandwidth::Fullband.celt_end_band();
394 let allow_pf = index % CHUNK as u64 != CHUNK as u64 - 1;
395 let a = celt.analyse(pcm, FRAME, end, allow_pf);
396 let base = (cfg.bitrate as usize * FRAME) as f32 / (48000.0 * 8.0);
397 let total = if cfg.vbr {
398 celt.vbr.bytes(base, MAX_PACKET, &a)
399 } else {
400 (base as usize).clamp(3, MAX_PACKET)
401 };
402 let nbytes = total - 1;
403 let params = FrameParams {
404 start: 0,
405 end,
406 nbytes,
407 intensity: intensity_band(cfg.bitrate, c, end),
408 };
409 rc.reset(nbytes);
410 celt.encode_frame(FRAME, ¶ms, &a, rc);
411 let toc = (31u8 << 3) | (((c == 2) as u8) << 2);
412 let mut data = Vec::with_capacity(total);
413 data.push(toc);
414 data.extend_from_slice(rc.finish());
415 let pts = index as i64 * FRAME as i64;
416 (
417 Packet {
418 data,
419 pts,
420 dts: pts,
421 keyframe: true,
422 },
423 rc.rng(),
424 )
425}
426
427pub struct OggWriter<W: Write> {
428 enc: Encoder,
429 out: ogg::Writer<W>,
430}
431
432impl<W: Write> OggWriter<W> {
433 pub fn new(cfg: EncoderConfig, w: W) -> Result<OggWriter<W>> {
434 let enc = Encoder::new(cfg)?;
435 let out = ogg::Writer::new(w, 0x5049_544f, &enc.head(), "PITO MD codecs")?;
436 Ok(OggWriter { enc, out })
437 }
438
439 pub fn write(&mut self, audio: &AudioBuffer) -> Result<()> {
440 for p in self.enc.encode(audio)? {
441 self.out.push(&p.data, p.pts + FRAME as i64)?;
442 }
443 Ok(())
444 }
445
446 pub fn finish(mut self) -> Result<W> {
447 let end = (self.enc.input + self.enc.pre_skip() as u64) as i64;
448 for p in self.enc.flush()? {
449 self.out.push(&p.data, (p.pts + FRAME as i64).min(end))?;
450 }
451 self.out.finish()
452 }
453}
454
455pub fn encode_ogg(cfg: EncoderConfig, audio: &AudioBuffer) -> Result<Vec<u8>> {
456 let mut w = OggWriter::new(cfg, Vec::new())?;
457 w.write(audio)?;
458 w.finish()
459}
460
461fn intensity_band(bitrate: u32, channels: usize, end: usize) -> usize {
462 if channels == 1 {
463 return end;
464 }
465 let kbps = bitrate / 1000;
466 let band = match kbps {
467 0..=31 => 4,
468 32..=47 => 8,
469 48..=63 => 11,
470 64..=79 => 13,
471 80..=95 => 15,
472 96..=111 => 17,
473 112..=127 => 19,
474 128..=143 => 20,
475 _ => 21,
476 };
477 band.min(end)
478}
479
480#[cfg(test)]
481mod tests;