1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5pub struct Flac {
6 pub audio: Audio,
7 pub dfla: Dfla,
8}
9
10impl Atom for Flac {
11 const KIND: FourCC = FourCC::new(b"fLaC");
12
13 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
14 let audio = Audio::decode(buf)?;
15
16 let mut dfla = None;
17 while let Some(atom) = Any::decode_maybe(buf)? {
18 match atom {
19 Any::Dfla(atom) => dfla = atom.into(),
20 _ => tracing::warn!("unknown atom: {:?}", atom),
21 }
22 }
23
24 Ok(Self {
25 audio,
26 dfla: dfla.ok_or(Error::MissingBox(Dfla::KIND))?,
27 })
28 }
29
30 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
31 self.audio.encode(buf)?;
32 self.dfla.encode(buf)?;
33 Ok(())
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39pub enum FlacMetadataBlock {
40 StreamInfo {
41 minimum_block_size: u16,
42 maximum_block_size: u16,
43 minimum_frame_size: u24,
44 maximum_frame_size: u24,
45 sample_rate: u32,
46 num_channels_minus_one: u8,
47 bits_per_sample_minus_one: u8,
48 number_of_interchannel_samples: u64,
49 md5_checksum: Vec<u8>,
50 },
51 Padding,
52 Application,
53 SeekTable,
54 VorbisComment {
55 vendor_string: String,
56 comments: Vec<String>,
57 },
58 CueSheet,
59 Picture,
60 Reserved,
61 Forbidden,
62}
63
64impl FlacMetadataBlock {
65 fn encode_initial_byte<B: BufMut>(buf: &mut B, block_type: u8, is_last: bool) -> Result<()> {
66 match is_last {
67 true => (0x80 | block_type).encode(buf),
68 false => block_type.encode(buf),
69 }
70 }
71 fn encode<B: BufMut>(&self, buf: &mut B, is_last: bool) -> Result<()> {
72 match self {
73 FlacMetadataBlock::StreamInfo {
74 minimum_block_size,
75 maximum_block_size,
76 minimum_frame_size,
77 maximum_frame_size,
78 sample_rate,
79 num_channels_minus_one,
80 bits_per_sample_minus_one,
81 number_of_interchannel_samples,
82 md5_checksum,
83 } => {
84 Self::encode_initial_byte(buf, 0u8, is_last)?;
85 u24::from([0u8, 0u8, 0u8]).encode(buf)?;
87 let length_position = buf.len();
88 minimum_block_size.encode(buf)?;
89 maximum_block_size.encode(buf)?;
90 minimum_frame_size.encode(buf)?;
91 maximum_frame_size.encode(buf)?;
92 (((*sample_rate as u64) << 44)
93 | ((*num_channels_minus_one as u64) << 41)
94 | ((*bits_per_sample_minus_one as u64) << 36)
95 | number_of_interchannel_samples)
96 .encode(buf)?;
97 if md5_checksum.len() != 16 {
98 return Err(Error::MissingContent(
99 "StreamInfo.md5_checksum must be 16 bytes",
100 ));
101 }
102 md5_checksum.encode(buf)?;
103 let length: u24 = ((buf.len() - length_position) as u32)
104 .try_into()
105 .map_err(|_| Error::TooLarge(Dfla::KIND))?;
106 buf.set_slice(length_position - 3, &length.to_be_bytes());
107 }
108 FlacMetadataBlock::Padding => { }
109 FlacMetadataBlock::Application => { }
110 FlacMetadataBlock::SeekTable => { }
111 FlacMetadataBlock::VorbisComment {
112 vendor_string,
113 comments,
114 } => {
115 Self::encode_initial_byte(buf, 4u8, is_last)?;
116
117 u24::from([0u8, 0u8, 0u8]).encode(buf)?;
119 let length_position = buf.len();
120 let vendor_string_bytes = vendor_string.as_bytes();
121 let vendor_string_len: u32 = vendor_string_bytes.len() as u32;
122 vendor_string_len.to_le_bytes().encode(buf)?;
123 vendor_string_bytes.encode(buf)?;
124 let number_of_comments: u32 = comments.len() as u32;
125 number_of_comments.to_le_bytes().encode(buf)?;
126 for comment in comments {
127 let comment_bytes = comment.as_bytes();
128 let comment_len: u32 = comment_bytes.len() as u32;
129 comment_len.to_le_bytes().encode(buf)?;
130 comment_bytes.encode(buf)?;
131 }
132 let length: u24 = ((buf.len() - length_position) as u32)
133 .try_into()
134 .map_err(|_| Error::TooLarge(Dfla::KIND))?;
135 buf.set_slice(length_position - 3, &length.to_be_bytes());
136 }
137 FlacMetadataBlock::CueSheet => { }
138 FlacMetadataBlock::Picture => { }
139 FlacMetadataBlock::Reserved => { }
140 FlacMetadataBlock::Forbidden => { }
141 }
142 Ok(())
143 }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
148#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
149pub struct Dfla {
150 pub blocks: Vec<FlacMetadataBlock>,
151}
152
153fn parse_stream_info(arr: &[u8]) -> Result<FlacMetadataBlock> {
154 let buf = &mut std::io::Cursor::new(arr);
156 let minimum_block_size = u16::decode(buf)?;
157 let maximum_block_size = u16::decode(buf)?;
158 let minimum_frame_size = u24::decode(buf)?;
159 let maximum_frame_size = u24::decode(buf)?;
160 let temp64 = u64::decode(buf)?;
161 let sample_rate: u32 = (temp64 >> 44) as u32; let num_channels_minus_one: u8 = ((temp64 >> 41) & 0x07) as u8; let bits_per_sample_minus_one: u8 = ((temp64 >> 36) & 0x1F) as u8; let number_of_interchannel_samples: u64 = temp64 & 0x0000_000F_FFFF_FFFF; let md5_checksum: Vec<u8> = Vec::decode_exact(buf, 16)?;
166 Ok(FlacMetadataBlock::StreamInfo {
167 minimum_block_size,
168 maximum_block_size,
169 minimum_frame_size,
170 maximum_frame_size,
171 sample_rate,
172 num_channels_minus_one,
173 bits_per_sample_minus_one,
174 number_of_interchannel_samples,
175 md5_checksum,
176 })
177}
178
179fn parse_vorbis_comment(arr: &[u8]) -> Result<FlacMetadataBlock> {
180 let buf = &mut std::io::Cursor::new(arr);
183 let vendor_string_length = u32::from_le_bytes(<[u8; 4]>::decode(buf)?) as usize;
184 let vendor_string_bytes: Vec<u8> = Vec::decode_exact(buf, vendor_string_length)?;
185 let vendor_string = String::from_utf8_lossy(&vendor_string_bytes)
186 .trim_end_matches('\0')
187 .to_string();
188 let number_of_fields = u32::from_le_bytes(<[u8; 4]>::decode(buf)?) as usize;
189 let mut comments = Vec::with_capacity(number_of_fields);
190 for _ in 0..number_of_fields {
191 let field_length = u32::from_le_bytes(<[u8; 4]>::decode(buf)?) as usize;
192 let field_bytes: Vec<u8> = Vec::decode_exact(buf, field_length)?;
193 let comment = String::from_utf8_lossy(&field_bytes)
194 .trim_end_matches('\0')
195 .to_string();
196 comments.push(comment);
197 }
198 Ok(FlacMetadataBlock::VorbisComment {
199 vendor_string,
200 comments,
201 })
202}
203
204impl AtomExt for Dfla {
205 type Ext = ();
206
207 const KIND_EXT: FourCC = FourCC::new(b"dfLa");
208
209 fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
210 let mut is_last_block = false;
211 let mut metadata_blocks = Vec::new();
212 while buf.has_remaining() && !is_last_block {
213 let initial_bytes = u32::decode(buf)?;
214 is_last_block = (initial_bytes & 0x80_00_00_00) == 0x80_00_00_00;
215 let block_type = ((initial_bytes >> 24) & 0x7f) as u8;
216 let length = initial_bytes & 0x00_FF_FF_FF;
217 let block_data: Vec<u8> = Vec::decode_exact(buf, length as usize)?;
218 let metadata_block = match block_type {
219 0 => parse_stream_info(&block_data)?,
220 1 => FlacMetadataBlock::Padding,
221 2 => FlacMetadataBlock::Application,
222 3 => FlacMetadataBlock::SeekTable,
223 4 => parse_vorbis_comment(&block_data)?,
224 5 => FlacMetadataBlock::CueSheet,
225 6 => FlacMetadataBlock::Picture,
226 7..=126 => FlacMetadataBlock::Reserved,
227 127 => FlacMetadataBlock::Forbidden,
228 _ => unreachable!("FLAC Metadata Block type is only 7 bits"),
229 };
230 metadata_blocks.push(metadata_block);
231 }
232 Ok(Dfla {
233 blocks: metadata_blocks,
234 })
235 }
236
237 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
238 if self.blocks.is_empty() {
239 return Err(Error::MissingContent("Streaminfo"));
240 }
241 for (i, metadata_block) in self.blocks.iter().enumerate() {
242 let is_last = i + 1 == self.blocks.len();
243 metadata_block.encode(buf, is_last)?;
244 }
245 Ok(())
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 const ENCODED_DFLA: &[u8] = &[
255 0x00, 0x00, 0x00, 0x32, 0x64, 0x66, 0x4c, 0x61, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
256 0x22, 0x12, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x23, 0x8e, 0x0a, 0xc4, 0x43, 0x70,
257 0x00, 0x01, 0xd8, 0x00, 0x75, 0x30, 0x88, 0x11, 0x2d, 0xd5, 0x7a, 0x13, 0xe7, 0xf7, 0x22,
258 0xd0, 0xee, 0x56, 0xae, 0xa3,
259 ];
260
261 #[test]
262 fn test_dfla_decode() {
263 let buf: &mut std::io::Cursor<&[u8]> = &mut std::io::Cursor::new(ENCODED_DFLA);
264
265 let dfla = Dfla::decode(buf).expect("failed to decode dfLa");
266
267 assert_eq!(
268 dfla,
269 Dfla {
270 blocks: vec![FlacMetadataBlock::StreamInfo {
271 minimum_block_size: 4608,
272 maximum_block_size: 4608,
273 minimum_frame_size: 16u32.try_into().expect("should fit in u24"),
274 maximum_frame_size: 9102u32.try_into().expect("should fit in u24"),
275 sample_rate: 44100,
276 num_channels_minus_one: 1,
277 bits_per_sample_minus_one: 23,
278 number_of_interchannel_samples: 120832,
279 md5_checksum: vec![
280 117, 48, 136, 17, 45, 213, 122, 19, 231, 247, 34, 208, 238, 86, 174, 163
281 ]
282 },]
283 }
284 );
285 }
286
287 #[test]
288 fn test_dfla_encode() {
289 let dfla = Dfla {
290 blocks: vec![FlacMetadataBlock::StreamInfo {
291 minimum_block_size: 4608,
292 maximum_block_size: 4608,
293 minimum_frame_size: 16u32.try_into().expect("should fit in u24"),
294 maximum_frame_size: 9102u32.try_into().expect("should fit in u24"),
295 sample_rate: 44100,
296 num_channels_minus_one: 1,
297 bits_per_sample_minus_one: 23,
298 number_of_interchannel_samples: 120832,
299 md5_checksum: vec![
300 117, 48, 136, 17, 45, 213, 122, 19, 231, 247, 34, 208, 238, 86, 174, 163,
301 ],
302 }],
303 };
304
305 let mut buf = Vec::new();
306 dfla.encode(&mut buf).unwrap();
307
308 assert_eq!(buf.as_slice(), ENCODED_DFLA);
309 }
310
311 const ENCODED_DFLA_2: &[u8] = &[
313 0x00, 0x00, 0x00, 0x7c, 0x64, 0x66, 0x4c, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x22, 0x12, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xc4, 0x40, 0x70,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x46, 0x20, 0x00, 0x00, 0x00, 0x72, 0x65,
317 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6c, 0x69, 0x62, 0x46, 0x4c, 0x41, 0x43,
318 0x20, 0x31, 0x2e, 0x34, 0x2e, 0x33, 0x20, 0x32, 0x30, 0x32, 0x33, 0x30, 0x36, 0x32, 0x33,
319 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x44, 0x45, 0x53, 0x43, 0x52, 0x49, 0x50,
320 0x54, 0x49, 0x4f, 0x4e, 0x3d, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x74, 0x65, 0x73, 0x74, 0x20,
321 0x77, 0x61, 0x76, 0x65,
322 ];
323
324 #[test]
325 fn test_dfla2_decode() {
326 let buf: &mut std::io::Cursor<&[u8]> = &mut std::io::Cursor::new(ENCODED_DFLA_2);
327
328 let dfla = Dfla::decode(buf).expect("failed to decode dfLa");
329
330 assert_eq!(
331 dfla,
332 Dfla {
333 blocks: vec![
334 FlacMetadataBlock::StreamInfo {
335 minimum_block_size: 4608,
336 maximum_block_size: 4608,
337 minimum_frame_size: 0u32.try_into().expect("should fit in u24"),
338 maximum_frame_size: 0u32.try_into().expect("should fit in u24"),
339 sample_rate: 44100,
340 num_channels_minus_one: 0,
341 bits_per_sample_minus_one: 7,
342 number_of_interchannel_samples: 0,
343 md5_checksum: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
344 },
345 FlacMetadataBlock::VorbisComment {
346 vendor_string: "reference libFLAC 1.4.3 20230623".into(),
347 comments: vec!["DESCRIPTION=audiotest wave".into()],
348 },
349 ]
350 }
351 );
352 }
353
354 #[test]
355 fn test_dfla2_encode() {
356 let dfla = Dfla {
357 blocks: vec![
358 FlacMetadataBlock::StreamInfo {
359 minimum_block_size: 4608,
360 maximum_block_size: 4608,
361 minimum_frame_size: 0u32.try_into().expect("should fit in u24"),
362 maximum_frame_size: 0u32.try_into().expect("should fit in u24"),
363 sample_rate: 44100,
364 num_channels_minus_one: 0,
365 bits_per_sample_minus_one: 7,
366 number_of_interchannel_samples: 0,
367 md5_checksum: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
368 },
369 FlacMetadataBlock::VorbisComment {
370 vendor_string: "reference libFLAC 1.4.3 20230623".into(),
371 comments: vec!["DESCRIPTION=audiotest wave".into()],
372 },
373 ],
374 };
375
376 let mut buf = Vec::new();
377 dfla.encode(&mut buf).unwrap();
378
379 assert_eq!(buf.as_slice(), ENCODED_DFLA_2);
380 }
381}