1use super::bitreader::BitReader;
6use super::nal::{iter_nals, unescape_rbsp};
7use super::parser::{CodecParser, VideoParams};
8use crate::CodecId;
9use bytes::{BufMut, Bytes, BytesMut};
10
11pub const NAL_SPS: u8 = 7;
13pub const NAL_PPS: u8 = 8;
15pub const NAL_IDR: u8 = 5;
17
18pub fn iter_nals_annexb(data: &[u8]) -> impl Iterator<Item = &[u8]> {
21 iter_nals(data)
22}
23
24pub fn annexb_to_avcc(data: &[u8]) -> Bytes {
26 let mut out = BytesMut::with_capacity(data.len());
27 for nal in iter_nals(data) {
28 out.put_u32(nal.len() as u32);
29 out.put_slice(nal);
30 }
31 out.freeze()
32}
33
34pub fn avcc_to_annexb(data: &[u8], nal_length_size: usize) -> Option<Bytes> {
39 if !(1..=4).contains(&nal_length_size) {
40 return None;
41 }
42 let mut out = BytesMut::with_capacity(data.len() + 16);
43 let mut i = 0;
44 while i + nal_length_size <= data.len() {
45 let mut len = 0usize;
46 for _ in 0..nal_length_size {
47 len = (len << 8) | data[i] as usize;
48 i += 1;
49 }
50 if i + len > data.len() {
51 return None; }
53 out.put_slice(&[0, 0, 0, 1]);
54 out.put_slice(&data[i..i + len]);
55 i += len;
56 }
57 Some(out.freeze())
58}
59
60#[derive(Debug, Clone, Default, PartialEq, Eq)]
67pub struct AvcConfig {
68 pub nal_length_size: usize,
70 pub sps: Vec<Vec<u8>>,
72 pub pps: Vec<Vec<u8>>,
74}
75
76impl AvcConfig {
77 pub fn parse(rec: &[u8]) -> Option<Self> {
80 if rec.len() < 7 || rec[0] != 1 {
81 return None;
82 }
83 let nal_length_size = (rec[4] & 0x03) as usize + 1;
84 let mut pos = 5;
85 let num_sps = (rec.get(pos)? & 0x1F) as usize;
86 pos += 1;
87 let mut sps = Vec::with_capacity(num_sps);
88 for _ in 0..num_sps {
89 let len = u16::from_be_bytes(rec.get(pos..pos + 2)?.try_into().ok()?) as usize;
90 pos += 2;
91 sps.push(rec.get(pos..pos + len)?.to_vec());
92 pos += len;
93 }
94 let num_pps = *rec.get(pos)? as usize;
95 pos += 1;
96 let mut pps = Vec::with_capacity(num_pps);
97 for _ in 0..num_pps {
98 let len = u16::from_be_bytes(rec.get(pos..pos + 2)?.try_into().ok()?) as usize;
99 pos += 2;
100 pps.push(rec.get(pos..pos + len)?.to_vec());
101 pos += len;
102 }
103 Some(Self {
104 nal_length_size,
105 sps,
106 pps,
107 })
108 }
109
110 pub fn to_annexb(&self) -> Bytes {
112 let mut out = BytesMut::new();
113 for nal in self.sps.iter().chain(self.pps.iter()) {
114 out.put_slice(&[0, 0, 0, 1]);
115 out.put_slice(nal);
116 }
117 out.freeze()
118 }
119
120 pub fn to_avc_record(&self) -> Bytes {
123 let sps0 = self
124 .sps
125 .first()
126 .map(|s| s.as_slice())
127 .unwrap_or(&[0, 0, 0, 0]);
128 let mut out = BytesMut::new();
129 out.put_u8(1); out.put_u8(*sps0.get(1).unwrap_or(&0)); out.put_u8(*sps0.get(2).unwrap_or(&0)); out.put_u8(*sps0.get(3).unwrap_or(&0)); out.put_u8(0xFF); out.put_u8(0xE0 | (self.sps.len() as u8 & 0x1F));
135 for s in &self.sps {
136 out.put_u16(s.len() as u16);
137 out.put_slice(s);
138 }
139 out.put_u8(self.pps.len() as u8);
140 for p in &self.pps {
141 out.put_u16(p.len() as u16);
142 out.put_slice(p);
143 }
144 out.freeze()
145 }
146
147 pub fn avcc_to_annexb(&self, avcc: &[u8], prepend_params: bool) -> Option<Bytes> {
150 let body = avcc_to_annexb(avcc, self.nal_length_size)?;
151 if prepend_params {
152 let mut out = BytesMut::with_capacity(body.len() + 64);
153 out.put(self.to_annexb());
154 out.put(body);
155 Some(out.freeze())
156 } else {
157 Some(body)
158 }
159 }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub struct SpsInfo {
165 pub width: u32,
167 pub height: u32,
169 pub profile_idc: u8,
171 pub level_idc: u8,
173}
174
175pub fn parse_sps(nal: &[u8]) -> Option<SpsInfo> {
179 if nal.is_empty() || nal[0] & 0x1f != NAL_SPS {
180 return None;
181 }
182 let rbsp = unescape_rbsp(&nal[1..]);
183 let mut r = BitReader::new(&rbsp);
184 if r.remaining() < 24 {
185 return None; }
187
188 let profile_idc = r.read_bits(8)? as u8;
189 let _constraints = r.read_bits(8)?;
190 let level_idc = r.read_bits(8)? as u8;
191 let _sps_id = r.read_ue()?;
192
193 let mut chroma_format_idc = 1u32; if matches!(
195 profile_idc,
196 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135
197 ) {
198 chroma_format_idc = r.read_ue()?;
199 if chroma_format_idc == 3 {
200 let _separate_colour_plane = r.read_bit()?;
201 }
202 let _bit_depth_luma = r.read_ue()?;
203 let _bit_depth_chroma = r.read_ue()?;
204 let _qpprime = r.read_bit()?;
205 let scaling_matrix_present = r.read_bit()?;
206 if scaling_matrix_present == 1 {
207 return None; }
209 }
210
211 let _log2_max_frame_num = r.read_ue()?;
212 let pic_order_cnt_type = r.read_ue()?;
213 if pic_order_cnt_type == 0 {
214 let _log2_max_poc_lsb = r.read_ue()?;
215 } else if pic_order_cnt_type == 1 {
216 let _delta_pic_order_always_zero = r.read_bit()?;
217 let _offset_for_non_ref = r.read_se()?;
218 let _offset_for_top_to_bottom = r.read_se()?;
219 let cycle = r.read_ue()?;
220 for _ in 0..cycle {
221 let _ = r.read_se()?;
222 }
223 }
224
225 let _max_num_ref_frames = r.read_ue()?;
226 let _gaps_allowed = r.read_bit()?;
227 let pic_width_in_mbs_minus1 = r.read_ue()?;
228 let pic_height_in_map_units_minus1 = r.read_ue()?;
229 let frame_mbs_only_flag = r.read_bit()?;
230 if frame_mbs_only_flag == 0 {
231 let _mb_adaptive = r.read_bit()?;
232 }
233 let _direct_8x8 = r.read_bit()?;
234
235 let frame_cropping_flag = r.read_bit()?;
236 let (mut crop_left, mut crop_right, mut crop_top, mut crop_bottom) = (0u32, 0u32, 0u32, 0u32);
237 if frame_cropping_flag == 1 {
238 crop_left = r.read_ue()?;
239 crop_right = r.read_ue()?;
240 crop_top = r.read_ue()?;
241 crop_bottom = r.read_ue()?;
242 }
243
244 let width_mbs = pic_width_in_mbs_minus1 + 1;
245 let height_map = pic_height_in_map_units_minus1 + 1;
246 let frame_height_mbs = (2 - frame_mbs_only_flag) * height_map;
247
248 let (sub_w, sub_h) = match chroma_format_idc {
250 0 => (1, 1), 1 => (2, 2), 2 => (2, 1), _ => (1, 1), };
255 let crop_unit_x = if chroma_format_idc == 0 { 1 } else { sub_w };
256 let crop_unit_y = (if chroma_format_idc == 0 { 1 } else { sub_h }) * (2 - frame_mbs_only_flag);
257
258 let width = width_mbs * 16 - (crop_left + crop_right) * crop_unit_x;
259 let height = frame_height_mbs * 16 - (crop_top + crop_bottom) * crop_unit_y;
260
261 Some(SpsInfo {
262 width,
263 height,
264 profile_idc,
265 level_idc,
266 })
267}
268
269pub fn hls_codec_string(p: &VideoParams) -> String {
272 format!("avc1.{:02x}00{:02x}", p.profile, p.level)
273}
274
275pub struct H264;
277
278impl CodecParser for H264 {
279 const CODEC: CodecId = CodecId::H264;
280
281 fn parse_config(data: &[u8]) -> Option<VideoParams> {
282 for nal in iter_nals(data) {
283 if !nal.is_empty() && nal[0] & 0x1f == NAL_SPS {
284 let sps = parse_sps(nal)?;
285 return Some(VideoParams {
286 width: sps.width,
287 height: sps.height,
288 profile: sps.profile_idc,
289 level: sps.level_idc,
290 tier: 0,
291 bit_depth: 8,
292 });
293 }
294 }
295 None
296 }
297
298 fn is_random_access_point(data: &[u8]) -> bool {
299 iter_nals(data).any(|n| !n.is_empty() && n[0] & 0x1f == NAL_IDR)
300 }
301
302 fn carries_config(data: &[u8]) -> bool {
303 iter_nals(data).any(|n| !n.is_empty() && matches!(n[0] & 0x1f, NAL_SPS | NAL_PPS))
304 }
305
306 fn hls_codec_string(params: &VideoParams) -> String {
307 hls_codec_string(params)
308 }
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314 use crate::codec::testutil::BitWriter;
315
316 #[test]
317 fn iterates_and_converts_nals() {
318 let annexb = [0, 0, 0, 1, 9, 0xF0, 0, 0, 1, 7, 0x42];
320 let nals: Vec<&[u8]> = iter_nals_annexb(&annexb).collect();
321 assert_eq!(nals, vec![&[9u8, 0xF0][..], &[7u8, 0x42][..]]);
322
323 let avcc = annexb_to_avcc(&annexb);
325 assert_eq!(&avcc[..], &[0, 0, 0, 2, 9, 0xF0, 0, 0, 0, 2, 7, 0x42]);
326 let back = avcc_to_annexb(&avcc, 4).unwrap();
327 assert_eq!(&back[..], &[0, 0, 0, 1, 9, 0xF0, 0, 0, 0, 1, 7, 0x42]);
328 }
329
330 #[test]
331 fn avc_config_parses_and_round_trips() {
332 let avcc = [
335 0x01, 0x42, 0x00, 0x1F, 0xFF, 0xE1, 0x00, 0x04, 0x67, 0x42, 0x00, 0x1F, 0x01, 0x00,
336 0x02, 0x68, 0xCE,
337 ];
338 let cfg = AvcConfig::parse(&avcc).expect("parse avcC");
339 assert_eq!(cfg.nal_length_size, 4);
340 assert_eq!(cfg.sps, vec![vec![0x67, 0x42, 0x00, 0x1F]]);
341 assert_eq!(cfg.pps, vec![vec![0x68, 0xCE]]);
342
343 assert_eq!(
345 &cfg.to_annexb()[..],
346 &[0, 0, 0, 1, 0x67, 0x42, 0x00, 0x1F, 0, 0, 0, 1, 0x68, 0xCE]
347 );
348
349 let idr_avcc = [0, 0, 0, 2, 0x65, 0xAA];
351 let plain = cfg.avcc_to_annexb(&idr_avcc, false).unwrap();
352 assert_eq!(&plain[..], &[0, 0, 0, 1, 0x65, 0xAA]);
353 let with_params = cfg.avcc_to_annexb(&idr_avcc, true).unwrap();
354 assert!(with_params.ends_with(&[0, 0, 0, 1, 0x65, 0xAA]));
355 assert!(with_params.len() > plain.len());
356
357 assert_eq!(AvcConfig::parse(&cfg.to_avc_record()), Some(cfg));
359
360 assert_eq!(AvcConfig::parse(&[0, 0, 0, 1, 0x67]), None);
362 }
363
364 fn sps_1280x720() -> Vec<u8> {
366 let mut w = BitWriter::default();
367 w.bits(66, 8); w.bits(0, 8); w.bits(31, 8); w.ue(0); w.ue(0); w.ue(0); w.ue(0); w.ue(1); w.bit(0); w.ue(79); w.ue(44); w.bit(1); w.bit(0); w.bit(0); w.bit(0); let mut nal = vec![0x67u8]; nal.extend_from_slice(&w.bytes());
384 nal
385 }
386
387 #[test]
388 fn parse_sps_extracts_resolution() {
389 let sps = parse_sps(&sps_1280x720()).expect("parse");
390 assert_eq!((sps.width, sps.height), (1280, 720));
391 assert_eq!(sps.profile_idc, 66);
392 assert_eq!(sps.level_idc, 31);
393 }
394
395 #[test]
396 fn codec_parser_classifies_and_extracts() {
397 let mut au = vec![0, 0, 0, 1];
399 au.extend_from_slice(&sps_1280x720());
400 au.extend_from_slice(&[0, 0, 0, 1, 0x65, 0xAA]); assert!(H264::is_random_access_point(&au));
403 assert!(H264::carries_config(&au));
404 let p = H264::parse_config(&au).expect("params");
405 assert_eq!((p.width, p.height, p.profile, p.level), (1280, 720, 66, 31));
406 assert_eq!(H264::hls_codec_string(&p), "avc1.42001f");
407
408 let delta = [0, 0, 0, 1, 0x41, 0xAA];
410 assert!(!H264::is_random_access_point(&delta));
411 }
412}