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