Module write

Source
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§

BitCounter
For counting the number of bits written but generating no output.
BitRecorder
For recording writes in order to play them back on another writer
BitWriter
For writing bit values to an underlying stream in a given endianness.
ByteWriter
For writing aligned bytes to a stream of bytes in a given endianness.
SignedValue
A generic signed value for stream recording purposes
UnsignedValue
A generic unsigned value for stream recording purposes

Traits§

BitWrite
A trait for anything that can write a variable number of potentially un-aligned values to an output stream
ByteWrite
A trait for anything that can write aligned values to an output stream
HuffmanWrite
A trait for anything that can write Huffman codes of a given endianness to an output stream
ToBitStream
Implemented by complex types that don’t require any additional context to build themselves to a writer
ToBitStreamWith
Implemented by complex types that require additional context to build themselves to a writer
ToByteStream
Implemented by complex types that don’t require any additional context to build themselves to a writer
ToByteStreamWith
Implemented by complex types that require additional context to build themselves to a writer