1use super::bitreader::BitReader;
5use super::nal::{iter_nals, unescape_rbsp};
6use super::parser::{CodecParser, VideoParams};
7use crate::CodecId;
8use bytes::{BufMut, Bytes, BytesMut};
9
10pub const NAL_SPS: u8 = 7;
12pub const NAL_PPS: u8 = 8;
14pub const NAL_IDR: u8 = 5;
16
17pub fn iter_nals_annexb(data: &[u8]) -> impl Iterator<Item = &[u8]> {
20 iter_nals(data)
21}
22
23pub fn annexb_to_avcc(data: &[u8]) -> Bytes {
25 let mut out = BytesMut::with_capacity(data.len());
26 for nal in iter_nals(data) {
27 out.put_u32(nal.len() as u32);
28 out.put_slice(nal);
29 }
30 out.freeze()
31}
32
33pub fn avcc_to_annexb(data: &[u8], nal_length_size: usize) -> Option<Bytes> {
38 if !(1..=4).contains(&nal_length_size) {
39 return None;
40 }
41 let mut out = BytesMut::with_capacity(data.len() + 16);
42 let mut i = 0;
43 while i + nal_length_size <= data.len() {
44 let mut len = 0usize;
45 for _ in 0..nal_length_size {
46 len = (len << 8) | data[i] as usize;
47 i += 1;
48 }
49 if i + len > data.len() {
50 return None; }
52 out.put_slice(&[0, 0, 0, 1]);
53 out.put_slice(&data[i..i + len]);
54 i += len;
55 }
56 Some(out.freeze())
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct SpsInfo {
62 pub width: u32,
64 pub height: u32,
66 pub profile_idc: u8,
68 pub level_idc: u8,
70}
71
72pub fn parse_sps(nal: &[u8]) -> Option<SpsInfo> {
76 if nal.is_empty() || nal[0] & 0x1f != NAL_SPS {
77 return None;
78 }
79 let rbsp = unescape_rbsp(&nal[1..]);
80 let mut r = BitReader::new(&rbsp);
81 if r.remaining() < 24 {
82 return None; }
84
85 let profile_idc = r.read_bits(8)? as u8;
86 let _constraints = r.read_bits(8)?;
87 let level_idc = r.read_bits(8)? as u8;
88 let _sps_id = r.read_ue()?;
89
90 let mut chroma_format_idc = 1u32; if matches!(
92 profile_idc,
93 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135
94 ) {
95 chroma_format_idc = r.read_ue()?;
96 if chroma_format_idc == 3 {
97 let _separate_colour_plane = r.read_bit()?;
98 }
99 let _bit_depth_luma = r.read_ue()?;
100 let _bit_depth_chroma = r.read_ue()?;
101 let _qpprime = r.read_bit()?;
102 let scaling_matrix_present = r.read_bit()?;
103 if scaling_matrix_present == 1 {
104 return None; }
106 }
107
108 let _log2_max_frame_num = r.read_ue()?;
109 let pic_order_cnt_type = r.read_ue()?;
110 if pic_order_cnt_type == 0 {
111 let _log2_max_poc_lsb = r.read_ue()?;
112 } else if pic_order_cnt_type == 1 {
113 let _delta_pic_order_always_zero = r.read_bit()?;
114 let _offset_for_non_ref = r.read_se()?;
115 let _offset_for_top_to_bottom = r.read_se()?;
116 let cycle = r.read_ue()?;
117 for _ in 0..cycle {
118 let _ = r.read_se()?;
119 }
120 }
121
122 let _max_num_ref_frames = r.read_ue()?;
123 let _gaps_allowed = r.read_bit()?;
124 let pic_width_in_mbs_minus1 = r.read_ue()?;
125 let pic_height_in_map_units_minus1 = r.read_ue()?;
126 let frame_mbs_only_flag = r.read_bit()?;
127 if frame_mbs_only_flag == 0 {
128 let _mb_adaptive = r.read_bit()?;
129 }
130 let _direct_8x8 = r.read_bit()?;
131
132 let frame_cropping_flag = r.read_bit()?;
133 let (mut crop_left, mut crop_right, mut crop_top, mut crop_bottom) = (0u32, 0u32, 0u32, 0u32);
134 if frame_cropping_flag == 1 {
135 crop_left = r.read_ue()?;
136 crop_right = r.read_ue()?;
137 crop_top = r.read_ue()?;
138 crop_bottom = r.read_ue()?;
139 }
140
141 let width_mbs = pic_width_in_mbs_minus1 + 1;
142 let height_map = pic_height_in_map_units_minus1 + 1;
143 let frame_height_mbs = (2 - frame_mbs_only_flag) * height_map;
144
145 let (sub_w, sub_h) = match chroma_format_idc {
147 0 => (1, 1), 1 => (2, 2), 2 => (2, 1), _ => (1, 1), };
152 let crop_unit_x = if chroma_format_idc == 0 { 1 } else { sub_w };
153 let crop_unit_y = (if chroma_format_idc == 0 { 1 } else { sub_h }) * (2 - frame_mbs_only_flag);
154
155 let width = width_mbs * 16 - (crop_left + crop_right) * crop_unit_x;
156 let height = frame_height_mbs * 16 - (crop_top + crop_bottom) * crop_unit_y;
157
158 Some(SpsInfo {
159 width,
160 height,
161 profile_idc,
162 level_idc,
163 })
164}
165
166pub fn hls_codec_string(p: &VideoParams) -> String {
169 format!("avc1.{:02x}00{:02x}", p.profile, p.level)
170}
171
172pub struct H264;
174
175impl CodecParser for H264 {
176 const CODEC: CodecId = CodecId::H264;
177
178 fn parse_config(data: &[u8]) -> Option<VideoParams> {
179 for nal in iter_nals(data) {
180 if !nal.is_empty() && nal[0] & 0x1f == NAL_SPS {
181 let sps = parse_sps(nal)?;
182 return Some(VideoParams {
183 width: sps.width,
184 height: sps.height,
185 profile: sps.profile_idc,
186 level: sps.level_idc,
187 tier: 0,
188 bit_depth: 8,
189 });
190 }
191 }
192 None
193 }
194
195 fn is_random_access_point(data: &[u8]) -> bool {
196 iter_nals(data).any(|n| !n.is_empty() && n[0] & 0x1f == NAL_IDR)
197 }
198
199 fn carries_config(data: &[u8]) -> bool {
200 iter_nals(data).any(|n| !n.is_empty() && matches!(n[0] & 0x1f, NAL_SPS | NAL_PPS))
201 }
202
203 fn hls_codec_string(params: &VideoParams) -> String {
204 hls_codec_string(params)
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use crate::codec::testutil::BitWriter;
212
213 #[test]
214 fn iterates_and_converts_nals() {
215 let annexb = [0, 0, 0, 1, 9, 0xF0, 0, 0, 1, 7, 0x42];
217 let nals: Vec<&[u8]> = iter_nals_annexb(&annexb).collect();
218 assert_eq!(nals, vec![&[9u8, 0xF0][..], &[7u8, 0x42][..]]);
219
220 let avcc = annexb_to_avcc(&annexb);
222 assert_eq!(&avcc[..], &[0, 0, 0, 2, 9, 0xF0, 0, 0, 0, 2, 7, 0x42]);
223 let back = avcc_to_annexb(&avcc, 4).unwrap();
224 assert_eq!(&back[..], &[0, 0, 0, 1, 9, 0xF0, 0, 0, 0, 1, 7, 0x42]);
225 }
226
227 fn sps_1280x720() -> Vec<u8> {
229 let mut w = BitWriter::default();
230 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());
247 nal
248 }
249
250 #[test]
251 fn parse_sps_extracts_resolution() {
252 let sps = parse_sps(&sps_1280x720()).expect("parse");
253 assert_eq!((sps.width, sps.height), (1280, 720));
254 assert_eq!(sps.profile_idc, 66);
255 assert_eq!(sps.level_idc, 31);
256 }
257
258 #[test]
259 fn codec_parser_classifies_and_extracts() {
260 let mut au = vec![0, 0, 0, 1];
262 au.extend_from_slice(&sps_1280x720());
263 au.extend_from_slice(&[0, 0, 0, 1, 0x65, 0xAA]); assert!(H264::is_random_access_point(&au));
266 assert!(H264::carries_config(&au));
267 let p = H264::parse_config(&au).expect("params");
268 assert_eq!((p.width, p.height, p.profile, p.level), (1280, 720, 66, 31));
269 assert_eq!(H264::hls_codec_string(&p), "avc1.42001f");
270
271 let delta = [0, 0, 0, 1, 0x41, 0xAA];
273 assert!(!H264::is_random_access_point(&delta));
274 }
275}