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
use bytes::{Bytes, Buf};
use super::nal;
use crate::{Error, Result};


/// AVC decoder configuration record
///
/// Bits | Name
/// ---- | ----
/// 8    | Version
/// 8    | Profile Indication
/// 8    | Profile Compatability
/// 8    | Level Indication
/// 6    | Reserved
/// 2    | NALU Length
/// 3    | Reserved
/// 5    | SPS Count
/// 16   | SPS Length
/// var  | SPS
/// 8    | PPS Count
/// 16   | PPS Length
/// var  | PPS
///
#[derive(Debug, Clone)]
pub struct DecoderConfigurationRecord {
    pub version: u8,
    pub profile_indication: u8,
    pub profile_compatability: u8,
    pub level_indication: u8,
    pub nalu_size: u8,
    pub sps: Vec<nal::Unit>,
    pub pps: Vec<nal::Unit>,
}

impl DecoderConfigurationRecord {
    pub fn try_from_buf<B>(buf: &mut B) -> Result<Self>
        where B: Buf
    {
        if buf.remaining() < 7 {
            return Err(Error::NotEnoughData)
        }

        let version = buf.get_u8();
        if version != 1 {
            return Err(Error::UnsupportedConfigurationRecordVersion(version));
        }

        let profile_indication = buf.get_u8();
        let profile_compatability = buf.get_u8();
        let level_indication = buf.get_u8();
        let nalu_size = (buf.get_u8() & 0x03) + 1;

        let sps_count = buf.get_u8() & 0x1F;
        let mut sps = Vec::new();
        for _ in 0..sps_count {
            let sps_length = buf.get_u16_be() as usize;
            let tmp: Bytes = buf.by_ref().take(sps_length).collect();
            sps.push(nal::Unit::try_from_bytes(tmp)?);
        }

        let pps_count = buf.get_u8();
        let mut pps = Vec::new();
        for _ in 0..pps_count {
            let pps_length = buf.get_u16_be() as usize;
            let tmp: Bytes = buf.by_ref().take(pps_length).collect();
            pps.push(nal::Unit::try_from_bytes(tmp)?);
        }

        Ok(Self {
            version,
            profile_indication,
            profile_compatability,
            level_indication,
            nalu_size,
            sps,
            pps,
        })
    }
}