1use anyhow::{anyhow, bail, Result};
2
3#[derive(Debug, Clone)]
4pub struct H264Config {
5 pub width: u32,
6 pub height: u32,
7
8 pub avcc: Vec<u8>,
10
11 pub nal_length_size: usize,
13
14 pub sps: Vec<Vec<u8>>,
16
17 pub pps: Vec<Vec<u8>>,
19}
20
21impl H264Config {
22 pub fn parse_from_avcc(width: u32, height: u32, avcc: &[u8]) -> Result<Self> {
23 if avcc.len() < 7 {
24 bail!("avcC too short");
25 }
26 if avcc[0] != 1 {
27 bail!("unsupported avcC version {}", avcc[0]);
28 }
29
30 let nal_length_size = ((avcc[4] & 0b11) as usize) + 1;
32 if nal_length_size < 1 || nal_length_size > 4 {
33 bail!("invalid nal_length_size={}", nal_length_size);
34 }
35
36 let mut off = 5;
37
38 if off >= avcc.len() {
40 bail!("avcC truncated");
41 }
42 let num_sps = (avcc[off] & 0b1_1111) as usize;
43 off += 1;
44
45 let mut sps = Vec::with_capacity(num_sps);
46 for _ in 0..num_sps {
47 if off + 2 > avcc.len() {
48 bail!("avcC truncated in SPS length");
49 }
50 let len = u16::from_be_bytes([avcc[off], avcc[off + 1]]) as usize;
51 off += 2;
52 if off + len > avcc.len() {
53 bail!("avcC truncated in SPS data");
54 }
55 sps.push(avcc[off..off + len].to_vec());
56 off += len;
57 }
58
59 if off >= avcc.len() {
60 bail!("avcC truncated before PPS count");
61 }
62 let num_pps = avcc[off] as usize;
63 off += 1;
64
65 let mut pps = Vec::with_capacity(num_pps);
66 for _ in 0..num_pps {
67 if off + 2 > avcc.len() {
68 bail!("avcC truncated in PPS length");
69 }
70 let len = u16::from_be_bytes([avcc[off], avcc[off + 1]]) as usize;
71 off += 2;
72 if off + len > avcc.len() {
73 bail!("avcC truncated in PPS data");
74 }
75 pps.push(avcc[off..off + len].to_vec());
76 off += len;
77 }
78
79 if sps.is_empty() || pps.is_empty() {
80 return Err(anyhow!("avcC must contain at least one SPS and PPS"));
81 }
82
83 Ok(Self {
84 width,
85 height,
86 avcc: avcc.to_vec(),
87 nal_length_size,
88 sps,
89 pps,
90 })
91 }
92
93 pub fn annexb_sequence_header(&self) -> Vec<u8> {
96 let mut out = Vec::new();
97 for ps in self.sps.iter().chain(self.pps.iter()) {
98 out.extend_from_slice(&[0, 0, 0, 1]);
99 out.extend_from_slice(ps);
100 }
101 out
102 }
103
104 pub fn avcc_sample_to_annexb(&self, sample: &[u8]) -> Result<Vec<u8>> {
106 let n = self.nal_length_size;
107 if n == 0 || n > 4 {
108 bail!("invalid nal_length_size");
109 }
110
111 let mut off = 0usize;
112 let mut out = Vec::with_capacity(sample.len() + 64);
113
114 while off + n <= sample.len() {
115 let len = match n {
116 1 => sample[off] as usize,
117 2 => u16::from_be_bytes([sample[off], sample[off + 1]]) as usize,
118 3 => ((sample[off] as usize) << 16) | ((sample[off + 1] as usize) << 8) | (sample[off + 2] as usize),
119 4 => u32::from_be_bytes([sample[off], sample[off + 1], sample[off + 2], sample[off + 3]]) as usize,
120 _ => unreachable!(),
121 };
122 off += n;
123
124 if off + len > sample.len() {
125 bail!("avcc sample truncated: off={} len={} size={}", off, len, sample.len());
126 }
127
128 out.extend_from_slice(&[0, 0, 0, 1]);
129 out.extend_from_slice(&sample[off..off + len]);
130 off += len;
131 }
132
133 if off != sample.len() {
134 bail!("avcc sample has trailing bytes: off={} size={}", off, sample.len());
135 }
136
137 Ok(out)
138 }
139}