arcly_stream/codec/
nal.rs1pub fn iter_nals(data: &[u8]) -> NalIter<'_> {
11 NalIter { data, pos: 0 }
12}
13
14pub struct NalIter<'a> {
16 data: &'a [u8],
17 pos: usize,
18}
19
20impl<'a> Iterator for NalIter<'a> {
21 type Item = &'a [u8];
22
23 fn next(&mut self) -> Option<&'a [u8]> {
24 let start = next_start_code(self.data, self.pos)?;
25 let nal_begin = start.0 + start.1;
26 let nal_end = match next_start_code(self.data, nal_begin) {
27 Some((off, _)) => off,
28 None => self.data.len(),
29 };
30 self.pos = nal_end;
31 if nal_begin >= nal_end {
32 return self.next();
33 }
34 Some(&self.data[nal_begin..nal_end])
35 }
36}
37
38pub fn next_start_code(data: &[u8], from: usize) -> Option<(usize, usize)> {
41 let mut i = from;
42 while i + 3 <= data.len() {
43 if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
44 if i > from && data[i - 1] == 0 {
45 return Some((i - 1, 4));
46 }
47 return Some((i, 3));
48 }
49 i += 1;
50 }
51 None
52}
53
54pub fn unescape_rbsp(nal: &[u8]) -> Vec<u8> {
56 let mut out = Vec::with_capacity(nal.len());
57 let mut zeros = 0;
58 for &b in nal {
59 if zeros >= 2 && b == 0x03 {
60 zeros = 0;
61 continue;
62 }
63 if b == 0 {
64 zeros += 1;
65 } else {
66 zeros = 0;
67 }
68 out.push(b);
69 }
70 out
71}
72
73pub fn conformance_dims(
77 width_luma: u32,
78 height_luma: u32,
79 chroma_format_idc: u32,
80 crop_left: u32,
81 crop_right: u32,
82 crop_top: u32,
83 crop_bottom: u32,
84) -> (u32, u32) {
85 let (sub_w, sub_h) = match chroma_format_idc {
86 1 => (2, 2), 2 => (2, 1), _ => (1, 1), };
90 let width = width_luma.saturating_sub((crop_left + crop_right) * sub_w);
91 let height = height_luma.saturating_sub((crop_top + crop_bottom) * sub_h);
92 (width, height)
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn iterates_three_and_four_byte_start_codes() {
101 let data = [0, 0, 0, 1, 9, 0xF0, 0, 0, 1, 7, 0x42];
102 let nals: Vec<&[u8]> = iter_nals(&data).collect();
103 assert_eq!(nals, vec![&[9u8, 0xF0][..], &[7u8, 0x42][..]]);
104 }
105
106 #[test]
107 fn unescape_removes_emulation_bytes() {
108 assert_eq!(unescape_rbsp(&[0, 0, 3, 1]), vec![0, 0, 1]);
109 assert_eq!(unescape_rbsp(&[0, 0, 3, 0, 0, 3, 2]), vec![0, 0, 0, 0, 2]);
110 }
111
112 #[test]
113 fn conformance_crop_420() {
114 assert_eq!(conformance_dims(1920, 1088, 1, 0, 0, 0, 4), (1920, 1080));
116 }
117}