Expand description
Traits and implementations for writing bits to a stream.
§Example
Writing the initial STREAMINFO block to a FLAC file, as documented in its specification.
use std::convert::TryInto;
use std::io::Write;
use bitstream_io::{BigEndian, BitWriter, BitWrite, ByteWriter, ByteWrite, LittleEndian, ToBitStream};
#[derive(Debug, PartialEq, Eq)]
struct BlockHeader {
last_block: bool, // 1 bit
block_type: u8, // 7 bits
block_size: u32, // 24 bits
}
impl ToBitStream for BlockHeader {
type Error = std::io::Error;
fn to_writer<W: BitWrite + ?Sized>(&self, w: &mut W) -> std::io::Result<()> {
w.write_bit(self.last_block)?;
w.write_out::<7, _>(self.block_type)?;
w.write_out::<24, _>(self.block_size)
}
}
#[derive(Debug, PartialEq, Eq)]
struct Streaminfo {
minimum_block_size: u16, // 16 bits
maximum_block_size: u16, // 16 bits
minimum_frame_size: u32, // 24 bits
maximum_frame_size: u32, // 24 bits
sample_rate: u32, // 20 bits
channels: u8, // 3 bits
bits_per_sample: u8, // 5 bits
total_samples: u64, // 36 bits
md5: [u8; 16], // 16 bytes
}
impl ToBitStream for Streaminfo {
type Error = std::io::Error;
fn to_writer<W: BitWrite + ?Sized>(&self, w: &mut W) -> std::io::Result<()> {
w.write_from(self.minimum_block_size)?;
w.write_from(self.maximum_block_size)?;
w.write_out::<24, _>(self.minimum_frame_size)?;
w.write_out::<24, _>(self.maximum_frame_size)?;
w.write_out::<20, _>(self.sample_rate)?;
w.write_out::<3, _>(self.channels - 1)?;
w.write_out::<5, _>(self.bits_per_sample - 1)?;
w.write_out::<36, _>(self.total_samples)?;
w.write_bytes(&self.md5)
}
}
#[derive(Debug, PartialEq, Eq)]
struct VorbisComment {
vendor: String,
comment: Vec<String>,
}
impl VorbisComment {
fn len(&self) -> usize {
4 + self.vendor.len() + 4 + self.comment.iter().map(|c| 4 + c.len()).sum::<usize>()
}
fn write<W: std::io::Write>(&self, w: &mut ByteWriter<W, LittleEndian>) -> std::io::Result<()> {
use std::convert::TryInto;
fn write_entry<W: std::io::Write>(
w: &mut ByteWriter<W, LittleEndian>,
s: &str,
) -> std::io::Result<()> {
w.write::<u32>(s.len().try_into().unwrap())?;
w.write_bytes(s.as_bytes())
}
write_entry(w, &self.vendor)?;
w.write::<u32>(self.comment.len().try_into().unwrap())?;
self.comment.iter().try_for_each(|s| write_entry(w, s))
}
}
let mut flac: Vec<u8> = Vec::new();
let mut writer = BitWriter::endian(&mut flac, BigEndian);
// stream marker
writer.write_bytes(b"fLaC").unwrap();
// metadata block header
writer.build(&BlockHeader { last_block: false, block_type: 0, block_size: 34 }).unwrap();
// STREAMINFO block
writer.build(&Streaminfo {
minimum_block_size: 4096,
maximum_block_size: 4096,
minimum_frame_size: 1542,
maximum_frame_size: 8546,
sample_rate: 44100,
channels: 2,
bits_per_sample: 16,
total_samples: 304844,
md5: *b"\xFA\xF2\x69\x2F\xFD\xEC\x2D\x5B\x30\x01\x76\xB4\x62\x88\x7D\x92",
}).unwrap();
let comment = VorbisComment {
vendor: "reference libFLAC 1.1.4 20070213".to_string(),
comment: vec![
"title=2ch 44100 16bit".to_string(),
"album=Test Album".to_string(),
"artist=Assorted".to_string(),
"tracknumber=1".to_string(),
],
};
// metadata block header
writer.build(
&BlockHeader {
last_block: false,
block_type: 4,
block_size: comment.len().try_into().unwrap(),
}
).unwrap();
// VORBIS_COMMENT block (little endian)
comment.write(&mut ByteWriter::new(writer.writer().unwrap())).unwrap();
assert_eq!(flac, vec![0x66,0x4c,0x61,0x43,0x00,0x00,0x00,0x22,
0x10,0x00,0x10,0x00,0x00,0x06,0x06,0x00,
0x21,0x62,0x0a,0xc4,0x42,0xf0,0x00,0x04,
0xa6,0xcc,0xfa,0xf2,0x69,0x2f,0xfd,0xec,
0x2d,0x5b,0x30,0x01,0x76,0xb4,0x62,0x88,
0x7d,0x92,0x04,0x00,0x00,0x7a,0x20,0x00,
0x00,0x00,0x72,0x65,0x66,0x65,0x72,0x65,
0x6e,0x63,0x65,0x20,0x6c,0x69,0x62,0x46,
0x4c,0x41,0x43,0x20,0x31,0x2e,0x31,0x2e,
0x34,0x20,0x32,0x30,0x30,0x37,0x30,0x32,
0x31,0x33,0x04,0x00,0x00,0x00,0x16,0x00,
0x00,0x00,0x74,0x69,0x74,0x6c,0x65,0x3d,
0x32,0x63,0x68,0x20,0x34,0x34,0x31,0x30,
0x30,0x20,0x20,0x31,0x36,0x62,0x69,0x74,
0x10,0x00,0x00,0x00,0x61,0x6c,0x62,0x75,
0x6d,0x3d,0x54,0x65,0x73,0x74,0x20,0x41,
0x6c,0x62,0x75,0x6d,0x0f,0x00,0x00,0x00,
0x61,0x72,0x74,0x69,0x73,0x74,0x3d,0x41,
0x73,0x73,0x6f,0x72,0x74,0x65,0x64,0x0d,
0x00,0x00,0x00,0x74,0x72,0x61,0x63,0x6b,
0x6e,0x75,0x6d,0x62,0x65,0x72,0x3d,0x31]);
Structs§
- For counting the number of bits written but generating no output.
- For recording writes in order to play them back on another writer
- For writing bit values to an underlying stream in a given endianness.
- For writing aligned bytes to a stream of bytes in a given endianness.
- A generic signed value for stream recording purposes
- A generic unsigned value for stream recording purposes
Traits§
- A trait for anything that can write a variable number of potentially un-aligned values to an output stream
- A trait for anything that can write aligned values to an output stream
- A trait for anything that can write Huffman codes of a given endianness to an output stream
- Implemented by complex types that don’t require any additional context to build themselves to a writer
- Implemented by complex types that require additional context to build themselves to a writer
- Implemented by complex types that don’t require any additional context to build themselves to a writer
- Implemented by complex types that require additional context to build themselves to a writer