1use std::io::Cursor;
14
15use claxon::FlacReader;
16use rff_codec::{Codec, CodecRegistry, Decoder};
17use rff_core::{AudioFrame, Error, Frame, MediaType, Packet, Result, SampleFormat};
18
19mod encode;
20mod md5;
21
22pub fn register(registry: &mut CodecRegistry) {
24 registry.register(Codec {
25 id: rff_core::CodecId::Flac,
26 name: "flac",
27 long_name: "FLAC (Free Lossless Audio Codec)",
28 media_type: MediaType::Audio,
29 decoder: Some(|| Box::new(FlacDecoder::default())),
30 encoder: Some(|| Box::new(encode::FlacEncoder::new())),
31 });
32}
33
34#[derive(Default)]
35struct FlacDecoder {
36 frame: Option<Frame>,
37 eof: bool,
38}
39
40impl Decoder for FlacDecoder {
41 fn send_packet(&mut self, packet: &Packet) -> Result<()> {
42 let mut reader = FlacReader::new(Cursor::new(&packet.data))
43 .map_err(|e| Error::invalid(format!("flac decode: {e}")))?;
44 let info = reader.streaminfo();
45 let channels = info.channels.max(1) as usize;
46 let scale = (1u64 << info.bits_per_sample.saturating_sub(1).max(1)) as f32;
48
49 let mut floats = Vec::new();
50 for sample in reader.samples() {
51 let v = sample.map_err(|e| Error::invalid(format!("flac decode: {e}")))?;
52 floats.push(v as f32 / scale);
53 }
54 let total = floats.len();
55 let bytes: Vec<u8> = floats.iter().flat_map(|s| s.to_le_bytes()).collect();
56
57 self.frame = Some(Frame::Audio(AudioFrame {
58 sample_rate: info.sample_rate,
59 channels: channels as u16,
60 format: SampleFormat::F32,
61 planes: vec![bytes],
62 samples: total / channels,
63 pts: packet.pts,
64 }));
65 Ok(())
66 }
67
68 fn receive_frame(&mut self) -> Result<Frame> {
69 if let Some(frame) = self.frame.take() {
70 return Ok(frame);
71 }
72 if self.eof {
73 Err(Error::Eof)
74 } else {
75 Err(Error::Again)
76 }
77 }
78
79 fn flush(&mut self) {
80 self.eof = true;
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn decode_rejects_non_flac() {
90 let mut dec = FlacDecoder::default();
91 assert!(dec
92 .send_packet(&Packet::from_data(0, b"not flac".to_vec()))
93 .is_err());
94 }
95}