1use std::collections::VecDeque;
17
18use rff_codec::{Codec, CodecParams, CodecRegistry, Decoder, Encoder};
19use rff_core::{AudioFrame, Dictionary, Error, Frame, MediaType, Packet, Result, SampleFormat};
20
21pub fn register(registry: &mut CodecRegistry) {
23 registry.register(Codec {
24 id: rff_core::CodecId::Flac,
25 name: "flac",
26 long_name: "FLAC (Free Lossless Audio Codec)",
27 media_type: MediaType::Audio,
28 decoder: Some(|| Box::new(FlacDecoder::default())),
29 encoder: Some(|| Box::new(FlacEncoder::new())),
30 });
31}
32
33#[derive(Default)]
38struct FlacDecoder {
39 frames: VecDeque<Frame>,
40 eof: bool,
41 core: Option<rusty_flac::FrameDecoder>,
44 s16: Vec<i16>,
46 f32: Vec<f32>,
47}
48
49fn streaminfo_block(extradata: &[u8]) -> Option<&[u8]> {
52 if extradata.len() == 34 {
53 return Some(extradata);
54 }
55 let mut rest = extradata.strip_prefix(b"fLaC")?;
56 while rest.len() >= 4 {
57 let (hdr, body) = rest.split_at(4);
58 let len = ((hdr[1] as usize) << 16) | ((hdr[2] as usize) << 8) | hdr[3] as usize;
59 if hdr[0] & 0x7F == 0 && len >= 34 && body.len() >= 34 {
60 return Some(&body[..34]);
61 }
62 if hdr[0] & 0x80 != 0 || body.len() < len {
63 return None;
64 }
65 rest = &body[len..];
66 }
67 None
68}
69
70enum Pcm<'a> {
74 S16(&'a [i16]),
75 F32(&'a [f32]),
76}
77
78fn audio_frame(info: &rusty_flac::StreamInfo, pcm: Pcm<'_>, pts: Option<i64>) -> AudioFrame {
81 let channels = info.channels.max(1) as usize;
82 let (format, plane, n) = match pcm {
83 Pcm::S16(v) => {
84 let mut b = vec![0u8; v.len() * 2];
85 for (d, s) in b.chunks_exact_mut(2).zip(v) {
86 d.copy_from_slice(&s.to_le_bytes());
87 }
88 (SampleFormat::S16, b, v.len())
89 }
90 Pcm::F32(v) => {
91 let mut b = vec![0u8; v.len() * 4];
92 for (d, s) in b.chunks_exact_mut(4).zip(v) {
93 d.copy_from_slice(&s.to_le_bytes());
94 }
95 (SampleFormat::F32, b, v.len())
96 }
97 };
98 AudioFrame {
99 sample_rate: info.sample_rate,
100 channels: channels as u16,
101 format,
102 planes: vec![plane],
103 samples: n / channels,
104 pts,
105 }
106}
107
108fn map_err(e: rusty_flac::DecodeError) -> Error {
109 Error::invalid(format!("flac decode: {e}"))
110}
111
112impl FlacDecoder {
113 fn decode_stream(&mut self, data: &[u8], pts: Option<i64>) -> Result<()> {
115 let mut dec = rusty_flac::Decoder::new(data).map_err(map_err)?;
116 let info = dec.streaminfo().clone();
117 let frame = if info.bits_per_sample <= 16 {
118 self.s16.clear();
119 while dec
120 .next_frame_interleaved(&mut self.s16)
121 .map_err(map_err)?
122 .is_some()
123 {}
124 audio_frame(&info, Pcm::S16(&self.s16), pts)
125 } else {
126 self.f32.clear();
127 while dec
128 .next_frame_interleaved(&mut self.f32)
129 .map_err(map_err)?
130 .is_some()
131 {}
132 audio_frame(&info, Pcm::F32(&self.f32), pts)
133 };
134 self.frames.push_back(Frame::Audio(frame));
135 Ok(())
136 }
137
138 fn decode_frames(&mut self, data: &[u8], pts: Option<i64>) -> Result<()> {
143 let Some(core) = self.core.as_mut() else {
144 return Err(Error::invalid(
145 "flac decode: frame packet without STREAMINFO (extradata)",
146 ));
147 };
148 if data.is_empty() {
149 return Ok(());
150 }
151 let info = core.streaminfo().clone();
152 fn run<S: rusty_flac::Sample>(
153 core: &mut rusty_flac::FrameDecoder,
154 data: &[u8],
155 out: &mut Vec<S>,
156 ) -> Result<()> {
157 out.clear();
158 let mut at = 0;
159 while at < data.len() {
160 match core.decode_frame_interleaved(&data[at..], out) {
161 Ok((_, used)) => at += used,
162 Err(e) if at == 0 => return Err(map_err(e)),
163 Err(_) => break,
164 }
165 }
166 Ok(())
167 }
168 let frame = if info.bits_per_sample <= 16 {
169 run(core, data, &mut self.s16)?;
170 audio_frame(&info, Pcm::S16(&self.s16), pts)
171 } else {
172 run(core, data, &mut self.f32)?;
173 audio_frame(&info, Pcm::F32(&self.f32), pts)
174 };
175 self.frames.push_back(Frame::Audio(frame));
176 Ok(())
177 }
178}
179
180impl Decoder for FlacDecoder {
181 fn configure(&mut self, params: &CodecParams) -> Result<()> {
182 if let Some(si) = streaminfo_block(¶ms.extradata) {
183 self.core = rusty_flac::StreamInfo::parse(si)
186 .and_then(rusty_flac::FrameDecoder::new)
187 .ok();
188 }
189 Ok(())
190 }
191
192 fn send_packet(&mut self, packet: &Packet) -> Result<()> {
193 if packet.data.starts_with(b"fLaC") {
194 self.decode_stream(&packet.data, packet.pts)
195 } else {
196 self.decode_frames(&packet.data, packet.pts)
197 }
198 }
199
200 fn receive_frame(&mut self) -> Result<Frame> {
201 if let Some(frame) = self.frames.pop_front() {
202 return Ok(frame);
203 }
204 if self.eof {
205 Err(Error::Eof)
206 } else {
207 Err(Error::Again)
208 }
209 }
210
211 fn flush(&mut self) {
212 self.eof = true;
213 }
214}
215
216struct FlacEncoder {
221 enc: Option<rusty_flac::Encoder>,
222 level: Option<u32>,
224 channels: usize,
225 scratch: Vec<i32>,
227 out: Option<Vec<u8>>,
228 flushed: bool,
229}
230
231impl FlacEncoder {
232 fn new() -> Self {
233 FlacEncoder {
234 enc: None,
235 level: None,
236 channels: 0,
237 scratch: Vec::new(),
238 out: None,
239 flushed: false,
240 }
241 }
242}
243
244#[inline]
246fn quantize(s: f32, scale: f32) -> i32 {
247 (s * scale).round().clamp(-scale, scale - 1.0) as i32
248}
249
250impl Encoder for FlacEncoder {
251 fn configure(&mut self, options: &Dictionary) -> Result<()> {
252 if let Some(level) = options.get_int("compression_level") {
253 self.level = Some(level.clamp(0, 8) as u32);
254 }
255 Ok(())
256 }
257
258 fn send_frame(&mut self, frame: &Frame) -> Result<()> {
259 let Frame::Audio(a) = frame else {
260 return Err(Error::invalid("flac encode: expected an audio frame"));
261 };
262 if self.enc.is_none() {
263 let bps = match a.format {
266 SampleFormat::S16 => 16,
267 _ => 24,
268 };
269 let channels = a.channels.max(1) as u32;
270 let mut enc = rusty_flac::Encoder::new(a.sample_rate, channels, bps)
271 .map_err(|e| Error::invalid(format!("flac encode: {e}")))?;
272 if let Some(level) = self.level {
273 enc.set_compression_level(level);
274 }
275 self.enc = Some(enc);
276 self.channels = channels as usize;
277 } else if a.channels.max(1) as usize != self.channels {
278 return Err(Error::invalid(
279 "flac encode: channel count changed mid-stream",
280 ));
281 }
282
283 let ch = self.channels;
284 let n = a.samples;
285 let enc = self.enc.as_mut().expect("encoder initialized above");
286 let map_err = |e: rusty_flac::EncodeError| Error::invalid(format!("flac encode: {e}"));
287 match a.format {
288 SampleFormat::S16 => enc
290 .push_s16le_bytes(&a.planes[0][..n * ch * 2])
291 .map_err(map_err),
292 SampleFormat::F32 => enc
293 .push_f32le_bytes(&a.planes[0][..n * ch * 4])
294 .map_err(map_err),
295 SampleFormat::F32Planar => {
296 let scale = (1i64 << 23) as f32;
297 let scratch = &mut self.scratch;
298 scratch.clear();
299 scratch.reserve(n * ch);
300 for i in 0..n {
301 for c in 0..ch {
302 let d = &a.planes[c];
303 let o = i * 4;
304 let s = f32::from_le_bytes([d[o], d[o + 1], d[o + 2], d[o + 3]]);
305 scratch.push(quantize(s, scale));
306 }
307 }
308 enc.push_interleaved(scratch).map_err(map_err)
309 }
310 _ => Err(Error::invalid(
311 "flac encode: unsupported sample format (need S16/F32/F32Planar)",
312 )),
313 }
314 }
315
316 fn receive_packet(&mut self) -> Result<Packet> {
317 if let Some(data) = self.out.take() {
318 let mut p = Packet::from_data(0, data);
319 p.pts = Some(0);
320 return Ok(p);
321 }
322 if self.flushed {
323 Err(Error::Eof)
324 } else {
325 Err(Error::Again)
326 }
327 }
328
329 fn flush(&mut self) {
330 if self.flushed {
331 return;
332 }
333 self.flushed = true;
334 if let Some(enc) = self.enc.take() {
335 self.out = Some(enc.finish());
336 }
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn decode_rejects_non_flac() {
346 let mut dec = FlacDecoder::default();
347 assert!(dec
348 .send_packet(&Packet::from_data(0, b"not flac".to_vec()))
349 .is_err());
350 }
351
352 #[test]
354 fn adapter_roundtrip_s16() {
355 let n = 6000usize;
356 let mut interleaved = Vec::with_capacity(n * 2 * 2);
357 for i in 0..n {
358 let l = ((i as f64 * 0.07).sin() * 15000.0) as i16;
359 let r = (i as i16).wrapping_mul(31);
360 interleaved.extend_from_slice(&l.to_le_bytes());
361 interleaved.extend_from_slice(&r.to_le_bytes());
362 }
363 let frame = Frame::Audio(AudioFrame {
364 sample_rate: 44100,
365 channels: 2,
366 format: SampleFormat::S16,
367 planes: vec![interleaved.clone()],
368 samples: n,
369 pts: Some(0),
370 });
371
372 let mut enc = FlacEncoder::new();
373 enc.send_frame(&frame).unwrap();
374 enc.flush();
375 let packet = enc.receive_packet().unwrap();
376
377 let (info, chans) = rusty_flac::decode(&packet.data).unwrap();
378 assert_eq!(info.bits_per_sample, 16);
379 assert_eq!(info.channels, 2);
380 for i in 0..n {
381 let l = i16::from_le_bytes([interleaved[i * 4], interleaved[i * 4 + 1]]) as i32;
382 let r = i16::from_le_bytes([interleaved[i * 4 + 2], interleaved[i * 4 + 3]]) as i32;
383 assert_eq!(chans[0][i], l);
384 assert_eq!(chans[1][i], r);
385 }
386 }
387
388 fn split_frames(stream: &[u8]) -> (Vec<u8>, Vec<Vec<u8>>) {
392 let mut pos = 4;
393 loop {
394 let last = stream[pos] & 0x80 != 0;
395 let len = u32::from_be_bytes([0, stream[pos + 1], stream[pos + 2], stream[pos + 3]]);
396 pos += 4 + len as usize;
397 if last {
398 break;
399 }
400 }
401 let header = stream[..pos].to_vec();
402 let crc16 = |data: &[u8]| {
403 data.iter().fold(0u16, |mut c, &b| {
404 c ^= (b as u16) << 8;
405 for _ in 0..8 {
406 c = if c & 0x8000 != 0 {
407 (c << 1) ^ 0x8005
408 } else {
409 c << 1
410 };
411 }
412 c
413 })
414 };
415 let mut frames = Vec::new();
416 let mut start = pos;
417 for p in pos + 10..stream.len() {
418 if stream[p] == 0xFF
419 && stream.get(p + 1).is_some_and(|&b| b & 0xFE == 0xF8)
420 && crc16(&stream[start..p]) == 0
421 {
422 frames.push(stream[start..p].to_vec());
423 start = p;
424 }
425 }
426 frames.push(stream[start..].to_vec());
427 (header, frames)
428 }
429
430 fn params(extradata: Vec<u8>) -> CodecParams {
431 CodecParams {
432 codec_id: rff_core::CodecId::Flac,
433 width: 0,
434 height: 0,
435 pixel_format: None,
436 sample_rate: 0,
437 channels: 0,
438 sample_format: None,
439 extradata,
440 }
441 }
442
443 fn audio(frame: Frame) -> AudioFrame {
444 match frame {
445 Frame::Audio(a) => a,
446 Frame::Video(_) => panic!("expected audio"),
447 }
448 }
449
450 #[test]
452 fn frame_packets_decode_identically_to_the_whole_stream() {
453 let n = 23_456usize;
454 let sig = |i: usize, k: i64| ((i as f64 * 0.031 * k as f64).sin() * 30000.0) as i64;
455 for (rate, channels, bps) in [(44_100, 2u32, 16u32), (48_000, 1, 24), (22_050, 3, 8)] {
456 let planes: Vec<Vec<i32>> = (0..channels as i64)
457 .map(|c| {
458 (0..n)
459 .map(|i| {
460 (sig(i, c + 1) >> (16 - bps.min(16))) as i32 * (1 << (bps.max(16) - 16))
461 })
462 .collect()
463 })
464 .collect();
465 let refs: Vec<&[i32]> = planes.iter().map(|p| p.as_slice()).collect();
466 let mut enc = rusty_flac::Encoder::new(rate, channels, bps).unwrap();
467 enc.push_planar(&refs).unwrap();
468 let stream = enc.finish();
469
470 let mut whole = FlacDecoder::default();
471 whole
472 .send_packet(&Packet::from_data(0, stream.clone()))
473 .unwrap();
474 let want = audio(whole.receive_frame().unwrap());
475
476 let (header, frames) = split_frames(&stream);
477 assert!(frames.len() > 3);
478 for extradata in [header.clone(), header[8..42].to_vec()] {
479 let mut dec = FlacDecoder::default();
480 dec.configure(¶ms(extradata)).unwrap();
481 let mut got = Vec::new();
482 let mut samples = 0;
483 for (i, f) in frames.iter().enumerate() {
484 let mut p = Packet::from_data(0, f.clone());
485 p.pts = Some(i as i64);
486 dec.send_packet(&p).unwrap();
487 let a = audio(dec.receive_frame().unwrap());
488 assert_eq!(a.pts, Some(i as i64));
489 assert_eq!(
490 (a.format, a.sample_rate, a.channels),
491 (want.format, want.sample_rate, want.channels)
492 );
493 samples += a.samples;
494 got.extend_from_slice(&a.planes[0]);
495 assert!(matches!(dec.receive_frame(), Err(Error::Again)));
496 }
497 assert_eq!(samples, want.samples);
498 assert_eq!(got, want.planes[0], "{rate} Hz {channels} ch {bps}-bit");
499 }
500 }
501 }
502
503 #[test]
504 fn frame_packets_need_streaminfo_and_reject_corruption() {
505 let mut enc = rusty_flac::Encoder::new(44_100, 1, 16).unwrap();
506 enc.push_planar(&[&(0..9000)
507 .map(|i| (i * 37 % 2001) - 1000)
508 .collect::<Vec<i32>>()])
509 .unwrap();
510 let stream = enc.finish();
511 let (header, frames) = split_frames(&stream);
512 let mut dec = FlacDecoder::default();
513 assert!(dec
514 .send_packet(&Packet::from_data(0, frames[0].clone()))
515 .is_err());
516 dec.configure(¶ms(header)).unwrap();
517 let mut bad = frames[0].clone();
518 let mid = bad.len() / 2;
519 bad[mid] ^= 0x40;
520 assert!(dec.send_packet(&Packet::from_data(0, bad)).is_err());
521 assert!(dec
522 .send_packet(&Packet::from_data(0, b"junk".to_vec()))
523 .is_err());
524 dec.send_packet(&Packet::new(0)).unwrap();
526 assert!(matches!(dec.receive_frame(), Err(Error::Again)));
527 let mut tagged = frames.last().unwrap().clone();
528 tagged.extend_from_slice(b"TAG trailing id3v1-ish bytes");
529 dec.send_packet(&Packet::from_data(0, tagged)).unwrap();
530 assert!(dec.receive_frame().is_ok());
531 let mut dec = FlacDecoder::default();
533 dec.configure(¶ms(b"fLaC\x01\xff\xff\xff".to_vec()))
534 .unwrap();
535 assert!(dec
536 .send_packet(&Packet::from_data(0, frames[0].clone()))
537 .is_err());
538 }
539}