flac_metadata_write/
flac-metadata-write.rs1extern crate bitstream_io;
2
3use bitstream_io::{
8 BigEndian, BitWrite, BitWriter, ByteWrite, ByteWriter, LittleEndian, ToBitStream,
9};
10use std::convert::TryInto;
11use std::num::NonZero;
12
13#[derive(Debug, PartialEq, Eq)]
14struct BlockHeader {
15 last_block: bool, block_type: u8, block_size: u32, }
19
20impl ToBitStream for BlockHeader {
21 type Error = std::io::Error;
22
23 fn to_writer<W: BitWrite + ?Sized>(&self, w: &mut W) -> std::io::Result<()> {
24 w.write_bit(self.last_block)?;
25 w.write::<7, _>(self.block_type)?;
26 w.write::<24, _>(self.block_size)
27 }
28}
29
30#[derive(Debug, PartialEq, Eq)]
31struct Streaminfo {
32 minimum_block_size: u16, maximum_block_size: u16, minimum_frame_size: u32, maximum_frame_size: u32, sample_rate: u32, channels: NonZero<u8>, bits_per_sample: NonZero<u8>, total_samples: u64, md5: [u8; 16], }
42
43impl ToBitStream for Streaminfo {
44 type Error = std::io::Error;
45
46 fn to_writer<W: BitWrite + ?Sized>(&self, w: &mut W) -> std::io::Result<()> {
47 w.write_from(self.minimum_block_size)?;
48 w.write_from(self.maximum_block_size)?;
49 w.write::<24, _>(self.minimum_frame_size)?;
50 w.write::<24, _>(self.maximum_frame_size)?;
51 w.write::<20, _>(self.sample_rate)?;
52 w.write::<3, _>(self.channels)?;
53 w.write::<5, _>(self.bits_per_sample)?;
54 w.write::<36, _>(self.total_samples)?;
55 w.write_bytes(&self.md5)
56 }
57}
58
59#[derive(Debug, PartialEq, Eq)]
60struct VorbisComment {
61 vendor: String,
62 comment: Vec<String>,
63}
64
65impl VorbisComment {
66 fn len(&self) -> usize {
67 4 + self.vendor.len() + 4 + self.comment.iter().map(|c| 4 + c.len()).sum::<usize>()
68 }
69
70 fn write<W: std::io::Write>(&self, w: &mut ByteWriter<W, LittleEndian>) -> std::io::Result<()> {
71 use std::convert::TryInto;
72
73 fn write_entry<W: std::io::Write>(
74 w: &mut ByteWriter<W, LittleEndian>,
75 s: &str,
76 ) -> std::io::Result<()> {
77 w.write::<u32>(s.len().try_into().unwrap())?;
78 w.write_bytes(s.as_bytes())
79 }
80
81 write_entry(w, &self.vendor)?;
82 w.write::<u32>(self.comment.len().try_into().unwrap())?;
83 self.comment.iter().try_for_each(|s| write_entry(w, s))
84 }
85}
86
87fn main() {
88 let mut flac: Vec<u8> = Vec::new();
89
90 let mut writer = BitWriter::endian(&mut flac, BigEndian);
91
92 writer.write_bytes(b"fLaC").unwrap();
94
95 writer
97 .build(&BlockHeader {
98 last_block: false,
99 block_type: 0,
100 block_size: 34,
101 })
102 .unwrap();
103
104 writer
106 .build(&Streaminfo {
107 minimum_block_size: 4096,
108 maximum_block_size: 4096,
109 minimum_frame_size: 1542,
110 maximum_frame_size: 8546,
111 sample_rate: 44100,
112 channels: NonZero::new(2).unwrap(),
113 bits_per_sample: NonZero::new(16).unwrap(),
114 total_samples: 304844,
115 md5: *b"\xFA\xF2\x69\x2F\xFD\xEC\x2D\x5B\x30\x01\x76\xB4\x62\x88\x7D\x92",
116 })
117 .unwrap();
118
119 let comment = VorbisComment {
120 vendor: "reference libFLAC 1.1.4 20070213".to_string(),
121 comment: vec![
122 "title=2ch 44100 16bit".to_string(),
123 "album=Test Album".to_string(),
124 "artist=Assorted".to_string(),
125 "tracknumber=1".to_string(),
126 ],
127 };
128
129 writer
131 .build(&BlockHeader {
132 last_block: false,
133 block_type: 4,
134 block_size: comment.len().try_into().unwrap(),
135 })
136 .unwrap();
137
138 comment
140 .write(&mut ByteWriter::new(writer.writer().unwrap()))
141 .unwrap();
142
143 assert_eq!(flac, include_bytes!("data/metadata-only.flac"));
144}