File: flac-metadata-read.rs

package info (click to toggle)
rust-bitstream-io 4.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 580 kB
  • sloc: makefile: 4
file content (148 lines) | stat: -rw-r--r-- 4,287 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! Reading the initial STREAMINFO block from a FLAC file,
//! as documented in its
//! [specification](https://xiph.org/flac/format.html#stream).
//!

extern crate bitstream_io;

use bitstream_io::{BigEndian, BitRead, BitReader, FromBitStream};
use std::num::NonZero;

#[derive(Debug, PartialEq, Eq)]
struct BlockHeader {
    last_block: bool, // 1 bit
    block_type: u8,   // 7 bits
    block_size: u32,  // 24 bits
}

impl FromBitStream for BlockHeader {
    type Error = std::io::Error;

    fn from_reader<R: BitRead + ?Sized>(r: &mut R) -> std::io::Result<Self> {
        Ok(Self {
            last_block: r.read_bit()?,
            block_type: r.read::<7, _>()?,
            block_size: r.read::<24, _>()?,
        })
    }
}

#[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: NonZero<u8>,        // 3 bits
    bits_per_sample: NonZero<u8>, // 5 bits
    total_samples: u64,           // 36 bits
    md5: [u8; 16],                // 16 bytes
}

impl FromBitStream for Streaminfo {
    type Error = std::io::Error;

    fn from_reader<R: BitRead + ?Sized>(r: &mut R) -> std::io::Result<Self> {
        Ok(Self {
            minimum_block_size: r.read_to()?,
            maximum_block_size: r.read_to()?,
            minimum_frame_size: r.read::<24, _>()?,
            maximum_frame_size: r.read::<24, _>()?,
            sample_rate: r.read::<20, _>()?,
            channels: r.read::<3, _>()?,
            bits_per_sample: r.read::<5, _>()?,
            total_samples: r.read::<36, _>()?,
            md5: r.read_to()?,
        })
    }
}

#[derive(Debug, PartialEq, Eq)]
struct VorbisComment {
    vendor: String,
    comment: Vec<String>,
}

impl FromBitStream for VorbisComment {
    type Error = Box<dyn std::error::Error>;

    fn from_reader<R: BitRead + ?Sized>(r: &mut R) -> Result<Self, Self::Error> {
        use bitstream_io::LE;

        fn read_entry<R: BitRead + ?Sized>(
            r: &mut R,
        ) -> Result<String, Box<dyn std::error::Error>> {
            use std::convert::TryInto;
            let size = r.read_as_to::<LE, u32>()?.try_into()?;
            Ok(String::from_utf8(r.read_to_vec(size)?)?)
        }

        Ok(Self {
            vendor: read_entry(r)?,
            comment: (0..r.read_as_to::<LE, u32>()?)
                .map(|_| read_entry(r))
                .collect::<Result<Vec<_>, _>>()?,
        })
    }
}

fn main() {
    // test FLAC file data
    let flac = include_bytes!("data/metadata-only.flac");

    let mut reader = BitReader::endian(flac.as_slice(), BigEndian);

    // stream marker
    assert_eq!(&reader.read_to::<[u8; 4]>().unwrap(), b"fLaC");

    // metadata block header
    assert_eq!(
        reader.parse::<BlockHeader>().unwrap(),
        BlockHeader {
            last_block: false,
            block_type: 0,
            block_size: 34
        }
    );

    // STREAMINFO block
    assert_eq!(
        dbg!(reader.parse::<Streaminfo>().unwrap()),
        Streaminfo {
            minimum_block_size: 4096,
            maximum_block_size: 4096,
            minimum_frame_size: 1542,
            maximum_frame_size: 8546,
            sample_rate: 44100,
            channels: NonZero::new(2).unwrap(),
            bits_per_sample: NonZero::new(16).unwrap(),
            total_samples: 304844,
            md5: *b"\xFA\xF2\x69\x2F\xFD\xEC\x2D\x5B\x30\x01\x76\xB4\x62\x88\x7D\x92",
        }
    );

    // metadata block header
    assert_eq!(
        dbg!(reader.parse::<BlockHeader>().unwrap()),
        BlockHeader {
            last_block: false,
            block_type: 4,
            block_size: 122
        }
    );

    // VORBIS_COMMENT block
    assert_eq!(
        dbg!(reader.parse::<VorbisComment>().unwrap()),
        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(),
            ],
        }
    );
}