1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub struct ColorSignal {
32 pub full_range: bool,
33 pub primaries: u8,
34 pub transfer: u8,
35 pub matrix: u8,
36}
37
38impl ColorSignal {
39 pub const BT601_FULL: Self = Self {
42 full_range: true,
43 primaries: 6,
44 transfer: 6,
45 matrix: 6,
46 };
47
48 pub const BT709_LIMITED: Self = Self {
50 full_range: false,
51 primaries: 1,
52 transfer: 1,
53 matrix: 1,
54 };
55}
56
57struct Reader<'a> {
58 bits: &'a [u8],
59 pos: usize,
60}
61
62impl<'a> Reader<'a> {
63 fn new(bits: &'a [u8]) -> Self {
64 Self { bits, pos: 0 }
65 }
66
67 fn bit(&mut self) -> Result<u32, String> {
68 let byte = self
69 .bits
70 .get(self.pos >> 3)
71 .ok_or("the SPS ends mid-field")?;
72 let value = (byte >> (7 - (self.pos & 7))) & 1;
73 self.pos += 1;
74 Ok(value as u32)
75 }
76
77 fn bits(&mut self, count: usize) -> Result<u32, String> {
78 let mut value = 0;
79 for _ in 0..count {
80 value = (value << 1) | self.bit()?;
81 }
82 Ok(value)
83 }
84
85 fn ue(&mut self) -> Result<u32, String> {
87 let mut zeros = 0;
88 while self.bit()? == 0 {
89 zeros += 1;
90 if zeros > 31 {
91 return Err("an exp-Golomb code longer than the field it names".into());
92 }
93 }
94 if zeros == 0 {
95 return Ok(0);
96 }
97 Ok((1 << zeros) - 1 + self.bits(zeros)?)
98 }
99
100 fn se(&mut self) -> Result<i32, String> {
101 let value = self.ue()?;
102 Ok(if value.is_multiple_of(2) {
103 -((value / 2) as i32)
104 } else {
105 value.div_ceil(2) as i32
106 })
107 }
108}
109
110struct Writer {
111 bytes: Vec<u8>,
112 pos: usize,
113}
114
115impl Writer {
116 fn new() -> Self {
117 Self {
118 bytes: Vec::new(),
119 pos: 0,
120 }
121 }
122
123 fn bit(&mut self, value: u32) {
124 if self.pos.is_multiple_of(8) {
125 self.bytes.push(0);
126 }
127 if value & 1 != 0 {
128 let index = self.pos >> 3;
129 self.bytes[index] |= 1 << (7 - (self.pos & 7));
130 }
131 self.pos += 1;
132 }
133
134 fn bits(&mut self, value: u32, count: usize) {
135 for shift in (0..count).rev() {
136 self.bit((value >> shift) & 1);
137 }
138 }
139
140 fn copy_from(&mut self, source: &[u8], from: usize, to: usize) {
143 for index in from..to {
144 let byte = source[index >> 3];
145 self.bit(((byte >> (7 - (index & 7))) & 1) as u32);
146 }
147 }
148
149 fn ue(&mut self, value: u32) {
151 let coded = value as u64 + 1;
152 let length = 64 - coded.leading_zeros() as usize;
153 for _ in 1..length {
154 self.bit(0);
155 }
156 for shift in (0..length).rev() {
157 self.bit(((coded >> shift) & 1) as u32);
158 }
159 }
160
161 fn trailing_bits(&mut self) {
162 self.bit(1);
163 while !self.pos.is_multiple_of(8) {
164 self.bit(0);
165 }
166 }
167}
168
169struct Located {
171 start: usize,
173 end: usize,
175 vui_present: bool,
177 vui_flag: usize,
179 declared: Option<ColorSignal>,
180 pic_order_cnt_type: u32,
181 max_num_ref_frames: u32,
182 frame_num: Coded,
184 separate_planes: bool,
186}
187
188fn unescape(nal: &[u8]) -> Vec<u8> {
189 let mut out = Vec::with_capacity(nal.len());
190 let mut index = 0;
191 while index < nal.len() {
192 if index + 2 < nal.len() && nal[index] == 0 && nal[index + 1] == 0 && nal[index + 2] == 3 {
193 out.push(0);
194 out.push(0);
195 index += 3;
196 } else {
197 out.push(nal[index]);
198 index += 1;
199 }
200 }
201 out
202}
203
204fn escape(rbsp: &[u8]) -> Vec<u8> {
205 let mut out = Vec::with_capacity(rbsp.len() + 4);
206 let mut zeros = 0;
207 for &byte in rbsp {
208 if zeros >= 2 && byte <= 3 {
209 out.push(3);
210 zeros = 0;
211 }
212 out.push(byte);
213 zeros = if byte == 0 { zeros + 1 } else { 0 };
214 }
215 if rbsp.last() == Some(&0) {
218 out.push(3);
219 }
220 out
221}
222
223fn stop_bit(rbsp: &[u8]) -> Result<usize, String> {
225 for index in (0..rbsp.len() * 8).rev() {
226 let byte = rbsp[index >> 3];
227 if (byte >> (7 - (index & 7))) & 1 == 1 {
228 return Ok(index);
229 }
230 }
231 Err("the SPS carries no stop bit".into())
232}
233
234fn locate(rbsp: &[u8]) -> Result<Located, String> {
235 let mut r = Reader::new(rbsp);
236 let profile = r.bits(8)?;
237 r.bits(8)?;
238 r.bits(8)?;
239 r.ue()?;
240 let mut separate_planes = false;
241 if matches!(
242 profile,
243 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135
244 ) {
245 let chroma = r.ue()?;
246 if chroma == 3 {
247 separate_planes = r.bit()? == 1;
248 }
249 r.ue()?;
250 r.ue()?;
251 r.bit()?;
252 if r.bit()? == 1 {
253 return Err("the SPS carries scaling lists".into());
256 }
257 }
258 let frame_num_at = r.pos;
259 let frame_num = (r.ue()?, frame_num_at, r.pos);
260 let poc_type = r.ue()?;
261 if poc_type == 0 {
262 r.ue()?;
263 } else if poc_type == 1 {
264 r.bit()?;
265 r.se()?;
266 r.se()?;
267 let cycle = r.ue()?;
268 for _ in 0..cycle {
269 r.se()?;
270 }
271 }
272 let max_num_ref_frames = r.ue()?;
273 r.bit()?;
274 r.ue()?;
275 r.ue()?;
276 if r.bit()? == 0 {
277 r.bit()?;
278 }
279 r.bit()?;
280 if r.bit()? == 1 {
281 r.ue()?;
282 r.ue()?;
283 r.ue()?;
284 r.ue()?;
285 }
286 let vui_flag = r.pos;
287 if r.bit()? == 0 {
288 return Ok(Located {
289 start: vui_flag,
290 end: vui_flag,
291 vui_present: false,
292 vui_flag,
293 declared: None,
294 pic_order_cnt_type: poc_type,
295 max_num_ref_frames,
296 frame_num,
297 separate_planes,
298 });
299 }
300 if r.bit()? == 1 && r.bits(8)? == 255 {
301 r.bits(16)?;
302 r.bits(16)?;
303 }
304 if r.bit()? == 1 {
305 r.bit()?;
306 }
307 let start = r.pos;
308 let declared = if r.bit()? == 1 {
309 r.bits(3)?;
310 let full_range = r.bit()? == 1;
311 if r.bit()? == 1 {
312 Some(ColorSignal {
313 full_range,
314 primaries: r.bits(8)? as u8,
315 transfer: r.bits(8)? as u8,
316 matrix: r.bits(8)? as u8,
317 })
318 } else {
319 None
322 }
323 } else {
324 None
325 };
326 Ok(Located {
327 start,
328 end: r.pos,
329 vui_present: true,
330 vui_flag,
331 declared,
332 pic_order_cnt_type: poc_type,
333 max_num_ref_frames,
334 frame_num,
335 separate_planes,
336 })
337}
338
339type Coded = (u32, usize, usize);
341
342struct Restriction {
344 flag: usize,
347 declared: Option<(Coded, Coded)>,
350}
351
352fn restriction(rbsp: &[u8], at: &Located) -> Result<Restriction, String> {
355 let last = stop_bit(rbsp)?;
356 if !at.vui_present {
357 return if at.vui_flag + 1 == last {
358 Ok(Restriction {
359 flag: at.vui_flag,
360 declared: None,
361 })
362 } else {
363 Err("the SPS does not end after its VUI flag".into())
364 };
365 }
366 let mut r = Reader {
367 bits: rbsp,
368 pos: at.end,
369 };
370 if r.bit()? == 1 {
371 r.ue()?;
372 r.ue()?;
373 }
374 if r.bit()? == 1 {
375 r.bits(32)?;
376 r.bits(32)?;
377 r.bit()?;
378 }
379 let nal_hrd = r.bit()? == 1;
380 if nal_hrd {
381 hrd(&mut r)?;
382 }
383 let vcl_hrd = r.bit()? == 1;
384 if vcl_hrd {
385 hrd(&mut r)?;
386 }
387 if nal_hrd || vcl_hrd {
388 r.bit()?;
389 }
390 r.bit()?;
391 let flag = r.pos;
392 let declared = if r.bit()? == 1 {
393 r.bit()?;
394 for _ in 0..4 {
395 r.ue()?;
396 }
397 let at = r.pos;
398 let reorder = (r.ue()?, at, r.pos);
399 let at = r.pos;
400 Some((reorder, (r.ue()?, at, r.pos)))
401 } else {
402 None
403 };
404 if r.pos != last {
405 return Err("the VUI does not end where the SPS does".into());
406 }
407 Ok(Restriction { flag, declared })
408}
409
410fn hrd(r: &mut Reader) -> Result<(), String> {
412 let schedules = r.ue()? + 1;
413 if schedules > 32 {
414 return Err("an HRD with more schedules than the syntax allows".into());
415 }
416 r.bits(8)?;
417 for _ in 0..schedules {
418 r.ue()?;
419 r.ue()?;
420 r.bit()?;
421 }
422 r.bits(20)?;
423 Ok(())
424}
425
426pub fn read_color(nal: &[u8]) -> Option<ColorSignal> {
428 let rbsp = unescape(nal.get(1..)?);
429 locate(&rbsp).ok()?.declared
430}
431
432pub fn write_color(nal: &[u8], signal: ColorSignal) -> Result<Vec<u8>, String> {
434 let header = *nal.first().ok_or("an empty NAL unit")?;
435 let rbsp = unescape(&nal[1..]);
436 let at = locate(&rbsp)?;
437 let last = stop_bit(&rbsp)?;
438
439 let mut w = Writer::new();
440 if at.vui_present {
441 w.copy_from(&rbsp, 0, at.start);
442 write_signal(&mut w, signal);
443 w.copy_from(&rbsp, at.end, last);
444 } else {
445 w.copy_from(&rbsp, 0, at.vui_flag);
446 w.bit(1);
447 w.bit(0);
448 w.bit(0);
449 write_signal(&mut w, signal);
450 for _ in 0..6 {
453 w.bit(0);
454 }
455 }
456 w.trailing_bits();
457
458 let mut out = Vec::with_capacity(w.bytes.len() + 8);
459 out.push(header);
460 out.extend_from_slice(&escape(&w.bytes));
461 Ok(out)
462}
463
464fn write_signal(w: &mut Writer, signal: ColorSignal) {
465 w.bit(1);
466 w.bits(5, 3);
467 w.bit(u32::from(signal.full_range));
468 w.bit(1);
469 w.bits(signal.primaries as u32, 8);
470 w.bits(signal.transfer as u32, 8);
471 w.bits(signal.matrix as u32, 8);
472}
473
474pub fn bound_reorder(nal: &[u8], in_order: bool) -> Result<Option<Vec<u8>>, String> {
482 let header = *nal.first().ok_or("an empty NAL unit")?;
483 let rbsp = unescape(&nal[1..]);
484 let at = locate(&rbsp)?;
485 let bound = restriction(&rbsp, &at)?;
486 if let Some(((0, _, _), (buffering, ..))) = bound.declared
487 && buffering >= at.max_num_ref_frames
488 {
489 return Ok(None);
490 }
491 if !in_order && at.pic_order_cnt_type != 2 {
492 return Err(format!(
493 "picture order count type {} may reorder",
494 at.pic_order_cnt_type
495 ));
496 }
497 let last = stop_bit(&rbsp)?;
498 let mut w = Writer::new();
499 match bound.declared {
500 Some(((_, reorder_at, _), (buffering, _, buffering_end))) => {
501 w.copy_from(&rbsp, 0, reorder_at);
502 w.ue(0);
503 w.ue(buffering.max(at.max_num_ref_frames));
504 w.copy_from(&rbsp, buffering_end, last);
505 }
506 None => {
507 w.copy_from(&rbsp, 0, bound.flag);
508 if !at.vui_present {
509 w.bit(1);
510 for _ in 0..8 {
511 w.bit(0);
512 }
513 }
514 w.bit(1);
515 w.bit(1);
516 w.ue(2);
517 w.ue(1);
518 w.ue(15);
519 w.ue(15);
520 w.ue(0);
521 w.ue(at.max_num_ref_frames);
522 }
523 }
524 w.trailing_bits();
525 let mut out = Vec::with_capacity(w.bytes.len() + 8);
526 out.push(header);
527 out.extend_from_slice(&escape(&w.bytes));
528 Ok(Some(out))
529}
530
531pub fn sequence_parameter_sets(unit: &[u8]) -> Vec<(usize, usize)> {
536 let mut starts = Vec::new();
537 let mut index = 0;
538 while index + 3 < unit.len() {
539 if unit[index] == 0 && unit[index + 1] == 0 && unit[index + 2] == 1 {
540 starts.push(index + 3);
541 index += 3;
542 } else {
543 index += 1;
544 }
545 }
546 let mut sets = Vec::new();
547 for (position, &start) in starts.iter().enumerate() {
548 if unit[start] & 0x1f != 7 {
549 continue;
550 }
551 let mut end = starts.get(position + 1).map_or(unit.len(), |next| next - 3);
552 if end > start && unit[end - 1] == 0 {
553 end -= 1;
554 }
555 sets.push((start, end));
556 }
557 sets
558}
559
560pub struct NoReorder {
564 source: &'static str,
566 in_order: bool,
567 last: Option<(Vec<u8>, Option<Vec<u8>>)>,
569 logged: Option<bool>,
571}
572
573impl NoReorder {
574 pub fn new(source: &'static str, in_order: bool) -> Self {
575 Self {
576 source,
577 in_order,
578 last: None,
579 logged: None,
580 }
581 }
582
583 pub fn set(&mut self, sps: &[u8]) -> Option<Vec<u8>> {
585 if let Some((was, now)) = &self.last
586 && was == sps
587 {
588 return now.clone();
589 }
590 let now = match bound_reorder(sps, self.in_order) {
591 Ok(bounded) => {
592 if bounded.is_some() && self.logged != Some(true) {
593 self.logged = Some(true);
594 println!(
595 "[pixelflux] {} declares no bound on reordering; its sequence parameter sets are written a bound of zero.",
596 self.source
597 );
598 }
599 bounded
600 }
601 Err(e) => {
602 if self.logged != Some(false) {
603 self.logged = Some(false);
604 eprintln!(
605 "[pixelflux] {}'s sequence parameter set was left as it came, without a reorder bound of zero: {e}",
606 self.source
607 );
608 }
609 None
610 }
611 };
612 self.last = Some((sps.to_vec(), now.clone()));
613 now
614 }
615
616 pub fn apply(&mut self, unit: &[u8]) -> Option<Vec<u8>> {
618 let mut out: Option<Vec<u8>> = None;
619 let mut copied = 0;
620 for (start, end) in sequence_parameter_sets(unit) {
621 if let Some(set) = self.set(&unit[start..end]) {
622 let out = out.get_or_insert_with(|| Vec::with_capacity(unit.len() + 16));
623 out.extend_from_slice(&unit[copied..start]);
624 out.extend_from_slice(&set);
625 copied = end;
626 }
627 }
628 let mut out = out?;
629 out.extend_from_slice(&unit[copied..]);
630 Some(out)
631 }
632}
633
634const WIDER_FRAME_NUM: u32 = 8;
637
638#[derive(Default)]
647pub struct WideFrameNum {
648 narrow: Option<u32>,
651 frame_num: u32,
653 failed: bool,
655}
656
657impl WideFrameNum {
658 pub fn push(&mut self, payload: &[u8], out: &mut Vec<u8>) -> bool {
663 let code = payload
664 .iter()
665 .position(|&b| b != 0)
666 .map_or(payload.len(), |one| one + 1);
667 self.push_unit(&payload[..code], &payload[code..], out)
668 }
669
670 pub fn push_unit(&mut self, start: &[u8], nal: &[u8], out: &mut Vec<u8>) -> bool {
672 let widened = match nal.first().map(|h| h & 0x1f) {
673 Some(7) => {
674 let wide = if self.failed { None } else { widen_sps(nal) };
675 self.narrow = wide.as_ref().map(|w| w.0);
676 wide.map(|w| w.1)
677 }
678 Some(kind @ (1 | 5)) => match self.narrow {
679 Some(narrow) => match widen_slice(nal, narrow, kind == 5, self.frame_num) {
680 Some((frame_num, slice)) => {
681 self.frame_num = frame_num;
682 Some(slice)
683 }
684 None => {
685 self.failed = true;
686 self.narrow = None;
687 out.extend_from_slice(start);
688 out.extend_from_slice(nal);
689 return false;
690 }
691 },
692 None => None,
693 },
694 _ => None,
695 };
696 out.extend_from_slice(start);
697 out.extend_from_slice(widened.as_deref().unwrap_or(nal));
698 true
699 }
700}
701
702fn widen_sps(nal: &[u8]) -> Option<(u32, Vec<u8>)> {
705 let rbsp = unescape(nal.get(1..)?);
706 let at = locate(&rbsp).ok()?;
707 let (minus4, from, to) = at.frame_num;
708 if minus4 + 4 + WIDER_FRAME_NUM > 16 || at.separate_planes {
709 return None;
710 }
711 let last = stop_bit(&rbsp).ok()?;
712 let mut w = Writer::new();
713 w.copy_from(&rbsp, 0, from);
714 w.ue(minus4 + WIDER_FRAME_NUM);
715 w.copy_from(&rbsp, to, last);
716 w.trailing_bits();
717 let mut out = Vec::with_capacity(w.bytes.len() + 8);
718 out.push(nal[0]);
719 out.extend_from_slice(&escape(&w.bytes));
720 Some((minus4 + 4, out))
721}
722
723fn widen_slice(nal: &[u8], narrow: u32, idr: bool, last: u32) -> Option<(u32, Vec<u8>)> {
727 let mut rbsp = unescape(nal.get(1..)?);
728 let mut r = Reader::new(&rbsp);
729 for _ in 0..3 {
731 r.ue().ok()?;
732 }
733 let at = r.pos;
734 let low = r.bits(narrow as usize).ok()?;
735 let range = 1 << narrow;
736 let frame_num = if idr {
737 low
738 } else {
739 (last + (low + range - last % range) % range) % (range << WIDER_FRAME_NUM)
740 };
741 let high = (frame_num >> narrow) as u8;
742 let (byte, bit) = (at / 8, at % 8);
743 let kept = rbsp[byte];
744 rbsp.splice(
745 byte..=byte,
746 [
747 (kept & !(0xff >> bit)) | (high >> bit),
748 (((high as u16) << (8 - bit)) as u8) | (kept & (0xff >> bit)),
749 ],
750 );
751 let mut out = Vec::with_capacity(nal.len() + 4);
752 out.push(nal[0]);
753 out.extend_from_slice(&escape(&rbsp));
754 Some((frame_num, out))
755}
756
757mod dpb {
760 struct Bits<'a> {
761 rbsp: &'a [u8],
762 pos: usize,
763 }
764
765 impl Bits<'_> {
766 fn bits(&mut self, n: u32) -> u32 {
767 (0..n).fold(0, |acc, _| {
768 let bit = self
769 .rbsp
770 .get(self.pos / 8)
771 .map_or(0, |b| (b >> (7 - self.pos % 8)) & 1);
772 self.pos += 1;
773 (acc << 1) | bit as u32
774 })
775 }
776
777 fn ue(&mut self) -> u32 {
778 let mut zeros = 0;
779 while self.bits(1) == 0 && zeros < 32 {
780 zeros += 1;
781 }
782 (1 << zeros) - 1 + self.bits(zeros)
783 }
784
785 fn se(&mut self) -> i32 {
786 let k = self.ue() as i32;
787 if k % 2 == 1 { (k + 1) / 2 } else { -(k / 2) }
788 }
789 }
790
791 fn h264_sps(stream: &[u8]) -> Option<(u32, u32, u32)> {
794 let nal = crate::encoders::codec::annexb_nals(stream).find(|n| n[0] & 0x1f == 7)?;
795 let mut rbsp = Vec::with_capacity(nal.len());
796 let mut zeros = 0;
797 for &b in &nal[1..] {
798 if zeros >= 2 && b == 3 {
799 zeros = 0;
800 continue;
801 }
802 zeros = if b == 0 { zeros + 1 } else { 0 };
803 rbsp.push(b);
804 }
805 let mut r = Bits {
806 rbsp: &rbsp,
807 pos: 0,
808 };
809 let profile = r.bits(8);
810 r.bits(16);
811 r.ue();
812 let mut chroma = 1;
813 if matches!(
814 profile,
815 100 | 110 | 122 | 244 | 44 | 83 | 86 | 118 | 128 | 138 | 139 | 134 | 135
816 ) {
817 chroma = r.ue();
818 if chroma == 3 {
819 r.bits(1);
820 }
821 r.ue();
822 r.ue();
823 r.bits(1);
824 if r.bits(1) == 1 {
825 for list in 0..(if chroma == 3 { 12 } else { 8 }) {
826 if r.bits(1) == 1 {
827 let (mut last, mut next) = (8i32, 8i32);
828 for _ in 0..(if list < 6 { 16 } else { 64 }) {
829 if next != 0 {
830 next = (last + r.se()).rem_euclid(256);
831 }
832 if next != 0 {
833 last = next;
834 }
835 }
836 }
837 }
838 }
839 }
840 let log2_max_frame_num = r.ue() + 4;
841 match r.ue() {
842 0 => {
843 r.ue();
844 }
845 1 => {
846 r.bits(1);
847 r.se();
848 r.se();
849 for _ in 0..r.ue() {
850 r.se();
851 }
852 }
853 _ => {}
854 }
855 Some((log2_max_frame_num, r.ue(), chroma))
856 }
857
858 pub fn h264_frame_num_range(stream: &[u8]) -> Option<u32> {
861 h264_sps(stream).map(|(log2, _, _)| 1 << log2)
862 }
863
864 #[cfg(test)]
866 pub fn h264_max_num_ref_frames(stream: &[u8]) -> Option<u32> {
867 h264_sps(stream).map(|(_, refs, _)| refs)
868 }
869
870 #[cfg(test)]
872 pub fn h264_chroma_format_idc(stream: &[u8]) -> Option<u32> {
873 h264_sps(stream).map(|(_, _, chroma)| chroma)
874 }
875}
876
877pub use dpb::h264_frame_num_range;
878#[cfg(test)]
879pub use dpb::{h264_chroma_format_idc, h264_max_num_ref_frames};
880
881#[cfg(test)]
884pub fn h264_reorder(stream: &[u8]) -> Option<(u32, u32)> {
885 let nal = crate::encoders::codec::annexb_nals(stream).find(|n| n[0] & 0x1f == 7)?;
886 let rbsp = unescape(&nal[1..]);
887 let bound = restriction(&rbsp, &locate(&rbsp).ok()?).ok()?;
888 bound
889 .declared
890 .map(|((reorder, ..), (buffering, ..))| (reorder, buffering))
891}
892
893#[cfg(test)]
896pub fn h264_timing(stream: &[u8]) -> Option<(u32, u32)> {
897 let nal = crate::encoders::codec::annexb_nals(stream).find(|n| n[0] & 0x1f == 7)?;
898 let rbsp = unescape(&nal[1..]);
899 let at = locate(&rbsp).ok()?;
900 if !at.vui_present {
901 return None;
902 }
903 let mut r = Reader {
904 bits: &rbsp,
905 pos: at.end,
906 };
907 if r.bit().ok()? == 1 {
908 r.ue().ok()?;
909 r.ue().ok()?;
910 }
911 if r.bit().ok()? == 0 {
912 return None;
913 }
914 Some((r.bits(32).ok()?, r.bits(32).ok()?))
915}
916
917#[cfg(test)]
919pub(crate) mod fixtures {
920 use super::*;
921
922 pub const PI4_SPS: &[u8] = &[
924 0x27, 0x64, 0x00, 0x28, 0xac, 0x2b, 0x40, 0x28, 0x02, 0xdd, 0x08, 0x00, 0x00, 0x03, 0x00,
925 0x08, 0x00, 0x00, 0x03, 0x01, 0xe7, 0x15, 0x00, 0x01, 0xe8, 0x48, 0x00, 0x02, 0xfa, 0xf3,
926 0x7b, 0xdc, 0x03, 0xc4, 0x89, 0xa8,
927 ];
928
929 pub const VCE_SPS: &[u8] = &[
933 0x67, 0x64, 0x40, 0x2a, 0xac, 0x26, 0xc0, 0x78, 0x02, 0x27, 0xe5, 0xc0, 0x5a, 0x20, 0x00,
934 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x0f, 0x10, 0x80,
935 ];
936
937 pub fn reorder_of(nal: &[u8]) -> Option<(u32, u32)> {
939 let rbsp = unescape(&nal[1..]);
940 let bound =
941 restriction(&rbsp, &locate(&rbsp).expect("located")).expect("read to the stop bit");
942 bound
943 .declared
944 .map(|((reorder, ..), (buffering, ..))| (reorder, buffering))
945 }
946
947 pub fn without(nal: &[u8], whole_vui: bool) -> Vec<u8> {
949 let rbsp = unescape(&nal[1..]);
950 let at = locate(&rbsp).expect("located");
951 let bound = restriction(&rbsp, &at).expect("read");
952 let mut w = Writer::new();
953 w.copy_from(&rbsp, 0, if whole_vui { at.vui_flag } else { bound.flag });
954 w.bit(0);
955 w.trailing_bits();
956 let mut out = vec![nal[0]];
957 out.extend_from_slice(&escape(&w.bytes));
958 out
959 }
960
961 pub fn assert_no_reorder(stream: &[u8], what: &str) {
965 let refs = h264_max_num_ref_frames(stream).unwrap_or_else(|| panic!("{what}: no SPS"));
966 match h264_reorder(stream) {
967 Some((0, buffering)) => {
968 assert!(
969 buffering >= refs,
970 "{what}: a buffer of {buffering} below its {refs} references"
971 )
972 }
973 other => panic!("{what}: the SPS bounds reordering at {other:?}, not zero"),
974 }
975 }
976
977 pub fn with_depth(nal: &[u8], reorder: u32, buffering: u32) -> Vec<u8> {
979 let rbsp = unescape(&nal[1..]);
980 let bound = restriction(&rbsp, &locate(&rbsp).expect("located")).expect("read");
981 let ((_, at, _), _) = bound.declared.expect("a restriction to rewrite");
982 let mut w = Writer::new();
983 w.copy_from(&rbsp, 0, at);
984 w.ue(reorder);
985 w.ue(buffering);
986 w.trailing_bits();
987 let mut out = vec![nal[0]];
988 out.extend_from_slice(&escape(&w.bytes));
989 out
990 }
991}
992
993#[cfg(test)]
994mod tests {
995 use super::fixtures::*;
996 use super::*;
997 use crate::RustCaptureSettings;
998
999 #[test]
1000 fn a_stream_that_declares_nothing_reads_as_nothing() {
1001 assert_eq!(read_color(PI4_SPS), None);
1002 }
1003
1004 #[test]
1005 fn what_is_written_reads_back() {
1006 for signal in [ColorSignal::BT601_FULL, ColorSignal::BT709_LIMITED] {
1007 let patched = write_color(PI4_SPS, signal).expect("the SPS takes a color");
1008 assert_eq!(
1009 read_color(&patched),
1010 Some(signal),
1011 "what was written did not read back"
1012 );
1013 }
1014 }
1015
1016 #[test]
1019 fn the_bits_after_the_insertion_survive_it() {
1020 let patched = write_color(PI4_SPS, ColorSignal::BT601_FULL).expect("patched");
1021 let (before, after) = (unescape(&PI4_SPS[1..]), unescape(&patched[1..]));
1022 let at_before = locate(&before).expect("located");
1023 let at_after = locate(&after).expect("located");
1024 let tail_before = stop_bit(&before).expect("stop") - at_before.end;
1025 let tail_after = stop_bit(&after).expect("stop") - at_after.end;
1026 assert_eq!(tail_before, tail_after, "the tail changed length");
1027 for index in 0..tail_before {
1028 let bit = |data: &[u8], at: usize| (data[at >> 3] >> (7 - (at & 7))) & 1;
1029 assert_eq!(
1030 bit(&before, at_before.end + index),
1031 bit(&after, at_after.end + index),
1032 "bit {index} of the tail changed"
1033 );
1034 }
1035 }
1036
1037 #[test]
1038 fn a_declared_color_reads_back_as_declared() {
1039 let patched = write_color(PI4_SPS, ColorSignal::BT709_LIMITED).expect("patched");
1040 assert_eq!(read_color(&patched), Some(ColorSignal::BT709_LIMITED));
1041 let again = write_color(&patched, ColorSignal::BT601_FULL).expect("rewritten");
1042 assert_eq!(
1043 read_color(&again),
1044 Some(ColorSignal::BT601_FULL),
1045 "a rewrite did not replace"
1046 );
1047 assert_eq!(
1048 again.len(),
1049 patched.len(),
1050 "replacing a color changed the length"
1051 );
1052 }
1053
1054 #[test]
1057 fn escaping_round_trips() {
1058 let raw = vec![0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00];
1059 assert_eq!(unescape(&escape(&raw)), raw);
1060 assert!(escape(&raw).len() > raw.len(), "nothing was escaped");
1061 }
1062
1063 fn same_prefix(a: &[u8], b: &[u8], bits: usize) -> bool {
1065 let (a, b) = (unescape(&a[1..]), unescape(&b[1..]));
1066 (0..bits).all(|i| (a[i >> 3] >> (7 - (i & 7))) & 1 == (b[i >> 3] >> (7 - (i & 7))) & 1)
1067 }
1068
1069 #[test]
1070 fn exp_golomb_writes_what_it_reads() {
1071 let mut w = Writer::new();
1072 let values = [0, 1, 2, 3, 7, 15, 16, 255, 65_534, u32::MAX - 1];
1073 for v in values {
1074 w.ue(v);
1075 }
1076 w.trailing_bits();
1077 let mut r = Reader::new(&w.bytes);
1078 for v in values {
1079 assert_eq!(r.ue().expect("read"), v);
1080 }
1081 }
1082
1083 #[test]
1086 fn a_set_without_a_restriction_is_bounded_at_zero() {
1087 assert_eq!(
1088 reorder_of(VCE_SPS),
1089 None,
1090 "the fixture declares no restriction"
1091 );
1092 let bounded = bound_reorder(VCE_SPS, true)
1093 .expect("writable")
1094 .expect("a change");
1095 assert_eq!(
1096 reorder_of(&bounded),
1097 Some((0, 2)),
1098 "zero, in a buffer of the set's two references"
1099 );
1100 assert_eq!(read_color(&bounded), read_color(VCE_SPS), "the color moved");
1101 let flag = restriction(
1102 &unescape(&VCE_SPS[1..]),
1103 &locate(&unescape(&VCE_SPS[1..])).unwrap(),
1104 )
1105 .unwrap()
1106 .flag;
1107 assert!(
1108 same_prefix(VCE_SPS, &bounded, flag),
1109 "a bit before the restriction changed"
1110 );
1111 assert_eq!(
1112 bound_reorder(&bounded, true),
1113 Ok(None),
1114 "a bounded set is left as it came"
1115 );
1116 }
1117
1118 #[test]
1121 fn only_an_order_the_stream_proves_is_bounded() {
1122 assert!(bound_reorder(VCE_SPS, false).is_err(), "type 0 may reorder");
1123 let pi4 = without(PI4_SPS, false);
1124 assert_eq!(locate(&unescape(&pi4[1..])).unwrap().pic_order_cnt_type, 2);
1125 let bounded = bound_reorder(&pi4, false)
1126 .expect("type 2 cannot reorder")
1127 .expect("a change");
1128 assert_eq!(reorder_of(&bounded), Some((0, 1)));
1129 }
1130
1131 #[test]
1133 fn a_bounded_set_is_left_as_it_came() {
1134 assert_eq!(reorder_of(PI4_SPS), Some((0, 1)));
1135 assert_eq!(bound_reorder(PI4_SPS, true), Ok(None));
1136 let colored = write_color(PI4_SPS, ColorSignal::BT601_FULL).expect("colored");
1137 assert_eq!(
1138 reorder_of(&colored),
1139 Some((0, 1)),
1140 "the color write lost the restriction"
1141 );
1142 assert_eq!(bound_reorder(&colored, false), Ok(None));
1143 }
1144
1145 #[test]
1148 fn hrd_parameters_are_read_through_and_kept() {
1149 let bare = without(PI4_SPS, false);
1150 assert_eq!(reorder_of(&bare), None);
1151 let bounded = bound_reorder(&bare, true)
1152 .expect("writable")
1153 .expect("a change");
1154 assert_eq!(reorder_of(&bounded), Some((0, 1)));
1155 let flag = restriction(
1156 &unescape(&bare[1..]),
1157 &locate(&unescape(&bare[1..])).unwrap(),
1158 )
1159 .unwrap()
1160 .flag;
1161 assert!(
1162 same_prefix(&bare, &bounded, flag),
1163 "the HRD parameters changed"
1164 );
1165 }
1166
1167 #[test]
1169 fn a_set_without_a_vui_takes_one_with_the_restriction_alone() {
1170 let bare = without(VCE_SPS, true);
1171 assert!(!locate(&unescape(&bare[1..])).unwrap().vui_present);
1172 let bounded = bound_reorder(&bare, true)
1173 .expect("writable")
1174 .expect("a change");
1175 assert_eq!(reorder_of(&bounded), Some((0, 2)));
1176 assert_eq!(read_color(&bounded), None, "a color nobody declared");
1177 let colored = write_color(&bounded, ColorSignal::BT709_LIMITED).expect("colored after");
1178 assert_eq!(
1179 reorder_of(&colored),
1180 Some((0, 2)),
1181 "a color written later keeps the bound"
1182 );
1183 }
1184
1185 #[test]
1188 fn a_declared_depth_is_rewritten() {
1189 let deep = with_depth(PI4_SPS, 3, 3);
1190 assert_eq!(reorder_of(&deep), Some((3, 3)));
1191 let bounded = bound_reorder(&deep, true)
1192 .expect("writable")
1193 .expect("a change");
1194 assert_eq!(
1195 reorder_of(&bounded),
1196 Some((0, 3)),
1197 "the declared buffer is kept"
1198 );
1199 let short = with_depth(&bound_reorder(VCE_SPS, true).unwrap().unwrap(), 0, 1);
1200 assert_eq!(reorder_of(&short), Some((0, 1)));
1201 let raised = bound_reorder(&short, true)
1202 .expect("writable")
1203 .expect("a change");
1204 assert_eq!(
1205 reorder_of(&raised),
1206 Some((0, 2)),
1207 "a buffer below the two references"
1208 );
1209 }
1210
1211 #[test]
1213 fn a_set_the_reader_doubts_is_refused() {
1214 let rbsp = unescape(&VCE_SPS[1..]);
1215 let last = stop_bit(&rbsp).unwrap();
1216 let mut w = Writer::new();
1217 w.copy_from(&rbsp, 0, last);
1218 w.bit(1);
1219 w.trailing_bits();
1220 let mut trailing = vec![VCE_SPS[0]];
1221 trailing.extend_from_slice(&escape(&w.bytes));
1222 assert!(
1223 bound_reorder(&trailing, true).is_err(),
1224 "a bit after the VUI went unnoticed"
1225 );
1226 let mut scaled = unescape(&PI4_SPS[1..]);
1227 scaled[3] |= 0x01;
1228 let mut scaled_nal = vec![PI4_SPS[0]];
1229 scaled_nal.extend_from_slice(&escape(&scaled));
1230 assert!(
1231 bound_reorder(&scaled_nal, true).is_err(),
1232 "scaling lists are refused"
1233 );
1234 assert!(
1235 bound_reorder(&PI4_SPS[..10], true).is_err(),
1236 "a truncated set"
1237 );
1238 }
1239
1240 #[test]
1244 fn a_bounded_stream_decodes_as_it_came() {
1245 use crate::encoders::oh264::Openh264Encoder;
1246 use crate::webcam::decode::{Decoder as _, VideoDecoder};
1247 let (w, h) = (160usize, 96usize);
1248 let s = RustCaptureSettings {
1249 width: w as i32,
1250 height: h as i32,
1251 target_fps: 30.0,
1252 omit_stripe_headers: true,
1253 ..Default::default()
1254 };
1255 let mut enc = Openh264Encoder::new(&s).expect("openh264 init");
1256 let frames: Vec<Vec<u8>> = (0..6)
1257 .map(|t| {
1258 let pixels: Vec<u8> = (0..w * h)
1259 .flat_map(|i| {
1260 let v = ((i % w + 3 * t) * 5 + (i / w) * 3) as u8;
1261 [v, v.wrapping_mul(3), v.wrapping_add(t as u8), 255]
1262 })
1263 .collect();
1264 enc.encode_host_argb(&pixels, w * 4, t as u64, t == 0, false)
1265 .expect("encode")
1266 })
1267 .collect();
1268 let sets = sequence_parameter_sets(&frames[0]);
1269 assert_eq!(sets.len(), 1, "the key frame carries one set");
1270 let (start, end) = sets[0];
1271 let original = &frames[0][start..end];
1272 let refs = locate(&unescape(&original[1..]))
1273 .unwrap()
1274 .max_num_ref_frames;
1275 let decode = |stream: &[Vec<u8>]| -> Vec<Vec<u8>> {
1276 let mut dec = VideoDecoder::new(crate::encoders::codec::Codec::H264).expect("decoder");
1277 stream
1278 .iter()
1279 .map(|f| {
1280 assert!(dec.decode(f).expect("decodes"), "no picture");
1281 let p = dec.frame().expect("frame");
1282 let rows =
1283 |plane: &[u8], stride: usize, width: usize, height: usize| -> Vec<u8> {
1284 (0..height)
1285 .flat_map(|y| plane[y * stride..y * stride + width].to_vec())
1286 .collect()
1287 };
1288 let mut out = rows(p.y, p.y_stride, p.width, p.height);
1289 out.extend(rows(
1290 p.u,
1291 p.uv_stride,
1292 p.width.div_ceil(2),
1293 p.height.div_ceil(2),
1294 ));
1295 out.extend(rows(
1296 p.v,
1297 p.uv_stride,
1298 p.width.div_ceil(2),
1299 p.height.div_ceil(2),
1300 ));
1301 out
1302 })
1303 .collect()
1304 };
1305 let expected = decode(&frames);
1306 let mut variants = vec![
1307 (without(original, true), refs),
1308 (without(original, false), refs),
1309 ];
1310 if reorder_of(original).is_some() {
1311 variants.push((with_depth(original, 2, refs.max(2)), refs.max(2)));
1312 }
1313 for (variant, buffering) in variants {
1314 let mut stripped = frames.clone();
1315 stripped[0] = [&frames[0][..start], &variant[..], &frames[0][end..]].concat();
1316 let mut holder = NoReorder::new("The test encoder", true);
1317 let bounded = holder.apply(&stripped[0]).expect("a set to bound");
1318 assert_eq!(h264_reorder(&bounded), Some((0, buffering)));
1319 assert_eq!(
1320 holder.apply(&stripped[0]).as_ref(),
1321 Some(&bounded),
1322 "the second key frame differs"
1323 );
1324 assert_eq!(
1325 holder.apply(&frames[1]),
1326 None,
1327 "a unit without a set was touched"
1328 );
1329 assert!(
1330 bounded.starts_with(&frames[0][..start]),
1331 "what precedes the set changed"
1332 );
1333 assert!(
1334 bounded.ends_with(&frames[0][end..]),
1335 "the slices after the set changed"
1336 );
1337 let mut stream = stripped;
1338 stream[0] = bounded;
1339 assert_eq!(
1340 decode(&stream),
1341 expected,
1342 "the bounded stream decodes to other pictures"
1343 );
1344 }
1345 }
1346
1347 fn slice(first_mb: u32, slice_type: u32, narrow: u32, low: u32, tail: &[u8]) -> Vec<u8> {
1350 let mut w = Writer::new();
1351 w.ue(first_mb);
1352 w.ue(slice_type);
1353 w.ue(0);
1354 w.bits(low, narrow as usize);
1355 for &byte in tail {
1356 w.bits(byte as u32, 8);
1357 }
1358 w.trailing_bits();
1359 let idr = slice_type == 7;
1360 [
1361 &[0, 0, 0, 1, if idr { 0x65 } else { 0x41 }][..],
1362 &escape(&w.bytes),
1363 ]
1364 .concat()
1365 }
1366
1367 fn x264_like_sps(log2: u32) -> Vec<u8> {
1370 let mut w = Writer::new();
1371 w.bits(66, 8);
1372 w.bits(0xc0, 8);
1373 w.bits(31, 8);
1374 w.ue(0);
1375 w.ue(log2 - 4);
1376 w.ue(2);
1377 w.ue(8);
1378 w.bit(0);
1379 w.ue(79);
1380 w.ue(44);
1381 w.bit(1);
1382 w.bit(1);
1383 w.bit(0);
1384 w.bit(1);
1385 for _ in 0..8 {
1386 w.bit(0);
1387 }
1388 w.bit(1);
1389 w.bit(1);
1390 for v in [2, 1, 16, 16, 0, 8] {
1391 w.ue(v);
1392 }
1393 w.trailing_bits();
1394 [&[0x67][..], &escape(&w.bytes)].concat()
1395 }
1396
1397 fn read_slice(nal: &[u8], log2: u32) -> (u32, u32, u32, u32, Vec<u8>) {
1400 let code = nal.iter().position(|&b| b != 0).unwrap() + 1;
1401 let rbsp = unescape(&nal[code + 1..]);
1402 let mut r = Reader::new(&rbsp);
1403 let fields = (
1404 r.ue().unwrap(),
1405 r.ue().unwrap(),
1406 r.ue().unwrap(),
1407 r.bits(log2 as usize).unwrap(),
1408 );
1409 let stop = stop_bit(&rbsp).unwrap();
1410 assert_eq!((stop - r.pos) % 8, 0, "the tail is not whole bytes");
1411 let tail = (0..(stop - r.pos) / 8)
1412 .map(|_| r.bits(8).unwrap() as u8)
1413 .collect();
1414 assert!(
1415 rbsp.len() * 8 - stop <= 8,
1416 "the stop bit is not in the last byte"
1417 );
1418 (fields.0, fields.1, fields.2, fields.3, tail)
1419 }
1420
1421 fn escaped(nal: &[u8]) -> bool {
1423 let code = nal.iter().position(|&b| b != 0).unwrap() + 1;
1424 !nal[code..]
1425 .windows(3)
1426 .any(|w| w[0] == 0 && w[1] == 0 && w[2] <= 2)
1427 && nal.last() != Some(&0)
1428 }
1429
1430 #[test]
1433 fn a_widened_set_changes_its_frame_num_alone() {
1434 for sps in [PI4_SPS.to_vec(), VCE_SPS.to_vec(), x264_like_sps(4)] {
1435 let (narrow, wide) = widen_sps(&sps).expect("the set widens");
1436 let rbsp = unescape(&sps[1..]);
1437 let at = locate(&rbsp).unwrap();
1438 assert_eq!(narrow, at.frame_num.0 + 4);
1439 let stream = |nal: &[u8]| [&[0, 0, 0, 1][..], nal].concat();
1440 assert_eq!(
1441 h264_frame_num_range(&stream(&wide)),
1442 h264_frame_num_range(&stream(&sps)).map(|range| range << 8)
1443 );
1444 assert_eq!(
1445 h264_max_num_ref_frames(&stream(&wide)),
1446 h264_max_num_ref_frames(&stream(&sps))
1447 );
1448 assert_eq!(read_color(&wide), read_color(&sps));
1449 assert_eq!(h264_timing(&stream(&wide)), h264_timing(&stream(&sps)));
1450 assert_eq!(reorder_of(&wide), reorder_of(&sps));
1451 let wide_rbsp = unescape(&wide[1..]);
1452 let wide_at = locate(&wide_rbsp).unwrap();
1453 let bit = |data: &[u8], at: usize| (data[at >> 3] >> (7 - (at & 7))) & 1;
1454 let tail = stop_bit(&rbsp).unwrap() - at.frame_num.2;
1455 assert_eq!(tail, stop_bit(&wide_rbsp).unwrap() - wide_at.frame_num.2);
1456 assert!(
1457 (0..tail)
1458 .all(|i| bit(&rbsp, at.frame_num.2 + i)
1459 == bit(&wide_rbsp, wide_at.frame_num.2 + i)),
1460 "a bit after the field changed"
1461 );
1462 }
1463 assert!(
1464 widen_sps(&x264_like_sps(9)).is_none(),
1465 "a field past sixteen bits"
1466 );
1467 }
1468
1469 #[test]
1472 fn a_widened_slice_keeps_every_bit_after_its_frame_num() {
1473 let mut offsets = [false; 8];
1474 for first_mb in [0, 1, 2, 3, 6, 7, 14, 15, 300, 8159] {
1475 for slice_type in [0, 5, 2, 7] {
1476 let mut r = Writer::new();
1477 r.ue(first_mb);
1478 r.ue(slice_type);
1479 r.ue(0);
1480 offsets[r.pos % 8] = true;
1481 for (tail, wide) in [
1484 (&[0xde, 0xad, 0xbe, 0xef][..], 0x59u32),
1485 (&[0x00, 0x00, 0x01, 0x80][..], 9),
1486 (&[0x00, 0x00][..], 0),
1487 ] {
1488 let nal = slice(first_mb, slice_type, 4, wide & 15, tail);
1489 let last = (wide + 4095) % 4096;
1490 let (frame_num, widened) =
1491 widen_slice(&nal[4..], 4, slice_type == 7, last).expect("widens");
1492 let widened = [&nal[..4], &widened].concat();
1493 let expected = if slice_type == 7 { wide & 15 } else { wide };
1494 assert_eq!(frame_num, expected);
1495 assert_eq!(
1496 read_slice(&widened, 12),
1497 (first_mb, slice_type, 0, expected, tail.to_vec()),
1498 "first_mb {first_mb}, slice_type {slice_type}"
1499 );
1500 assert!(escaped(&widened), "{widened:02x?}");
1501 }
1502 }
1503 }
1504 assert_eq!(
1506 offsets,
1507 [false, true, false, true, false, true, false, true]
1508 );
1509 }
1510
1511 #[test]
1514 fn the_widened_count_runs_on_across_x264s_wrap() {
1515 let mut wide = WideFrameNum::default();
1516 let mut out = Vec::new();
1517 assert!(wide.push(&[&[0, 0, 0, 1][..], &x264_like_sps(4)].concat(), &mut out));
1518 assert_eq!(h264_frame_num_range(&out), Some(4096));
1519 let mut seen = Vec::new();
1520 for frame in 0..4100u32 {
1521 for first_mb in [0, 1800] {
1522 let nal = slice(
1523 first_mb,
1524 if frame == 0 { 7 } else { 5 },
1525 4,
1526 frame % 16,
1527 &[0x5a],
1528 );
1529 out.clear();
1530 assert!(wide.push(&nal, &mut out));
1531 let (_, _, _, frame_num, _) = read_slice(&out, 12);
1532 seen.push(frame_num);
1533 }
1534 }
1535 let expected: Vec<u32> = (0..4100u32).flat_map(|f| [f % 4096; 2]).collect();
1536 assert_eq!(seen, expected);
1537 out.clear();
1538 assert!(wide.push(&slice(0, 7, 4, 0, &[0x5a]), &mut out));
1539 assert_eq!(read_slice(&out, 12).3, 0, "a key frame restarts the count");
1540
1541 let mut narrow = WideFrameNum::default();
1542 let sps = [&[0, 0, 0, 1][..], &x264_like_sps(9)].concat();
1543 let p = slice(0, 5, 9, 300, &[0x5a]);
1544 out.clear();
1545 assert!(narrow.push(&sps, &mut out));
1546 assert!(narrow.push(&p, &mut out));
1547 assert_eq!(
1548 out,
1549 [&sps[..], &p[..]].concat(),
1550 "they went out as they came"
1551 );
1552 }
1553
1554 #[test]
1555 fn a_unit_ending_in_zeros_ends_escaped() {
1556 assert_eq!(escape(&[1, 0, 0]), [1, 0, 0, 3]);
1557 assert_eq!(unescape(&escape(&[1, 0, 0])), [1, 0, 0]);
1558 }
1559}