1use crate::avc::AvcConfig;
13
14pub fn parse_hvcc(hvcc: &[u8]) -> Option<AvcConfig> {
17 if hvcc.len() < 23 || hvcc[0] != 1 {
18 return None;
19 }
20 let nal_len = (hvcc[21] & 0x03) as usize + 1;
21 let num_arrays = hvcc[22] as usize;
22 let mut headers = Vec::new();
23 let mut i = 23;
24 for _ in 0..num_arrays {
25 let nal_type = *hvcc.get(i)? & 0x3f;
26 i += 1;
27 let count = be16(hvcc, i)? as usize;
28 i += 2;
29 for _ in 0..count {
30 let len = be16(hvcc, i)? as usize;
31 i += 2;
32 let nal = hvcc.get(i..i + len)?;
33 if matches!(nal_type, 32 | 33 | 34) {
36 headers.extend_from_slice(&[0, 0, 0, 1]);
37 headers.extend_from_slice(nal);
38 }
39 i += len;
40 }
41 }
42 if headers.is_empty() {
43 return None;
44 }
45 Some(AvcConfig {
46 nal_len,
47 headers_annexb: headers,
48 })
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct SpsInfo {
54 pub profile_space: u8,
55 pub tier_flag: bool,
56 pub profile_idc: u8,
57 pub profile_compatibility_flags: u32,
58 pub constraint_flags: [u8; 6],
59 pub level_idc: u8,
60 pub chroma_format_idc: u8,
61 pub bit_depth_luma: u8,
62 pub bit_depth_chroma: u8,
63 pub max_sub_layers: u8,
64 pub temporal_id_nesting: bool,
65 pub width: u32,
66 pub height: u32,
67}
68
69pub fn sps_info(nal: &[u8]) -> Option<SpsInfo> {
72 let payload = if !nal.is_empty() && (nal[0] >> 1) & 0x3f == 33 {
74 nal.get(2..)?
75 } else {
76 nal
77 };
78 let rbsp = unescape(payload);
79 let mut r = Bits::new(&rbsp);
80 r.bits(4)?; let max_sub_layers_minus1 = r.bits(3)? as u8;
82 let temporal_id_nesting = r.bit()?;
83 let profile_space = r.bits(2)? as u8;
85 let tier_flag = r.bit()?;
86 let profile_idc = r.bits(5)? as u8;
87 let profile_compatibility_flags = r.bits(32)?;
88 let mut constraint_flags = [0u8; 6];
89 for c in constraint_flags.iter_mut() {
90 *c = r.bits(8)? as u8;
91 }
92 let level_idc = r.bits(8)? as u8;
93 let mut sub_profile = [false; 8];
94 let mut sub_level = [false; 8];
95 for i in 0..max_sub_layers_minus1 as usize {
96 sub_profile[i] = r.bit()?;
97 sub_level[i] = r.bit()?;
98 }
99 if max_sub_layers_minus1 > 0 {
100 for _ in max_sub_layers_minus1 as usize..8 {
101 r.bits(2)?;
102 }
103 }
104 for i in 0..max_sub_layers_minus1 as usize {
105 if sub_profile[i] {
106 r.bits(32)?;
107 r.bits(32)?;
108 r.bits(24)?;
109 }
110 if sub_level[i] {
111 r.bits(8)?;
112 }
113 }
114 r.ue()?; let chroma_format_idc = r.ue()? as u8;
116 if chroma_format_idc == 3 {
117 r.bit()?; }
119 let width = r.ue()?;
120 let height = r.ue()?;
121 let (mut cl, mut cr, mut ct, mut cb) = (0, 0, 0, 0);
122 if r.bit()? {
123 cl = r.ue()?;
124 cr = r.ue()?;
125 ct = r.ue()?;
126 cb = r.ue()?;
127 }
128 let bit_depth_luma = r.ue()? as u8 + 8;
129 let bit_depth_chroma = r.ue()? as u8 + 8;
130 let (sw, sh) = match chroma_format_idc {
131 1 => (2, 2),
132 2 => (2, 1),
133 _ => (1, 1),
134 };
135 Some(SpsInfo {
136 profile_space,
137 tier_flag,
138 profile_idc,
139 profile_compatibility_flags,
140 constraint_flags,
141 level_idc,
142 chroma_format_idc,
143 bit_depth_luma,
144 bit_depth_chroma,
145 max_sub_layers: max_sub_layers_minus1 + 1,
146 temporal_id_nesting,
147 width: width.saturating_sub(sw * (cl + cr)),
148 height: height.saturating_sub(sh * (ct + cb)),
149 })
150}
151
152pub fn sps_dimensions(nal: &[u8]) -> Option<(u32, u32)> {
154 sps_info(nal).map(|s| (s.width, s.height))
155}
156
157pub fn build_hvcc_record(vps: &[u8], sps: &[u8], pps: &[u8]) -> Option<Vec<u8>> {
159 let info = sps_info(sps)?;
160 let mut out = Vec::with_capacity(64 + vps.len() + sps.len() + pps.len());
161 out.push(1); out.push((info.profile_space << 6) | ((info.tier_flag as u8) << 5) | info.profile_idc);
163 out.extend_from_slice(&info.profile_compatibility_flags.to_be_bytes());
164 out.extend_from_slice(&info.constraint_flags);
165 out.push(info.level_idc);
166 out.extend_from_slice(&[0xf0, 0x00]); out.push(0xfc); out.push(0xfc | info.chroma_format_idc);
169 out.push(0xf8 | (info.bit_depth_luma - 8));
170 out.push(0xf8 | (info.bit_depth_chroma - 8));
171 out.extend_from_slice(&[0, 0]); out.push((info.max_sub_layers << 3) | ((info.temporal_id_nesting as u8) << 2) | 3);
174 let arrays: [(u8, &[u8]); 3] = [(32, vps), (33, sps), (34, pps)];
175 let present = arrays.iter().filter(|(_, n)| !n.is_empty()).count();
176 out.push(present as u8);
177 for (t, nal) in arrays {
178 if nal.is_empty() {
179 continue;
180 }
181 out.push(0x80 | t); out.extend_from_slice(&1u16.to_be_bytes());
183 out.extend_from_slice(&(nal.len() as u16).to_be_bytes());
184 out.extend_from_slice(nal);
185 }
186 Some(out)
187}
188
189pub fn find_nal_annexb(data: &[u8], nal_type: u8) -> Option<&[u8]> {
191 for nal in crate::avc::split_annexb(data) {
192 if !nal.is_empty() && (nal[0] >> 1) & 0x3f == nal_type {
193 return Some(nal);
194 }
195 }
196 None
197}
198
199fn be16(d: &[u8], i: usize) -> Option<u16> {
200 Some(u16::from_be_bytes([*d.get(i)?, *d.get(i + 1)?]))
201}
202
203fn unescape(ebsp: &[u8]) -> Vec<u8> {
204 let mut out = Vec::with_capacity(ebsp.len());
205 let mut zeros = 0;
206 for &b in ebsp {
207 if zeros >= 2 && b == 3 {
208 zeros = 0;
209 continue;
210 }
211 out.push(b);
212 zeros = if b == 0 { zeros + 1 } else { 0 };
213 }
214 out
215}
216
217struct Bits<'a> {
218 d: &'a [u8],
219 p: usize,
220}
221
222impl<'a> Bits<'a> {
223 fn new(d: &'a [u8]) -> Self {
224 Bits { d, p: 0 }
225 }
226 fn bit(&mut self) -> Option<bool> {
227 let b = *self.d.get(self.p / 8)?;
228 let v = (b >> (7 - self.p % 8)) & 1;
229 self.p += 1;
230 Some(v == 1)
231 }
232 fn bits(&mut self, n: u32) -> Option<u32> {
233 let mut v = 0u32;
234 for _ in 0..n {
235 v = (v << 1) | self.bit()? as u32;
236 }
237 Some(v)
238 }
239 fn ue(&mut self) -> Option<u32> {
240 let mut lz = 0;
241 while !self.bit()? {
242 lz += 1;
243 if lz > 31 {
244 return None;
245 }
246 }
247 if lz == 0 {
248 return Some(0);
249 }
250 Some((1u32 << lz) - 1 + self.bits(lz)?)
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257
258 const VPS: &[u8] = &[
261 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
262 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x99, 0xf0, 0x24,
263 ];
264 const SPS: &[u8] = &[
265 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
266 0x00, 0x03, 0x00, 0x99, 0xa0, 0x06, 0x82, 0x01, 0xe1, 0xfe, 0x5f, 0x92, 0x46, 0xd9, 0x6c,
267 0x80,
268 ];
269 const PPS: &[u8] = &[0x44, 0x01, 0xc1, 0x90, 0x95, 0x81, 0x12];
270
271 #[test]
272 fn reads_geometry_and_profile() {
273 let i = sps_info(SPS).expect("sps");
274 assert_eq!((i.width, i.height), (832, 480));
275 assert_eq!(i.level_idc, 153);
276 assert_eq!(i.max_sub_layers, 1);
277 assert_eq!(i.chroma_format_idc, 1);
278 assert_eq!(i.bit_depth_luma, 8);
279 assert_eq!(i.bit_depth_chroma, 8);
280 assert_eq!(i.profile_idc, 1);
281 assert_eq!(sps_dimensions(SPS), Some((832, 480)));
282 assert_eq!(sps_dimensions(&SPS[2..]), Some((832, 480)));
284 }
285
286 #[test]
287 fn hvcc_roundtrip() {
288 let (vps, pps) = (VPS, PPS);
289 let rec = build_hvcc_record(vps, SPS, pps).expect("build");
290 assert_eq!(rec[0], 1);
291 assert_eq!(rec[21] & 3, 3, "4-byte NAL length");
292 assert_eq!(rec[22], 3, "three arrays");
293 let cfg = parse_hvcc(&rec).expect("parse");
294 assert_eq!(cfg.nal_len, 4);
295 let mut want = Vec::new();
297 for n in [vps, SPS, pps] {
298 want.extend_from_slice(&[0, 0, 0, 1]);
299 want.extend_from_slice(n);
300 }
301 assert_eq!(cfg.headers_annexb, want);
302 }
303
304 #[test]
305 fn rejects_junk() {
306 assert!(parse_hvcc(&[]).is_none());
307 assert!(parse_hvcc(&[0u8; 40]).is_none());
308 assert!(sps_info(&[0x42, 0x01]).is_none());
309 }
310}