1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16#[repr(u32)]
17pub enum Codec {
18 Jpeg = 0,
19 H264 = 1,
20 Vp8 = 2,
21 Vp9 = 3,
22 Av1 = 4,
23 H265 = 5,
24}
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub enum Hardware {
30 Nvenc,
31 Vaapi,
32 VaapiIntel,
33}
34
35use super::reference::{REFERENCE_FRAMES, Reference};
36
37pub const WIRE_JPEG: u8 = 0x03;
39pub const WIRE_VIDEO: u8 = 0x04;
44pub const FRAME_KEY: u8 = 0x01;
47pub const FRAME_INTRA: u8 = 0x02;
48pub const FRAME_DELTA: u8 = 0x00;
49pub const FRAME_ANCHOR: u8 = 0x08;
53pub const JPEG_HEADER_LEN: usize = 6;
55pub const VIDEO_HEADER_LEN: usize = 12;
56
57impl Codec {
58 pub const VIDEO: [Codec; 5] = [Codec::H264, Codec::Vp8, Codec::Vp9, Codec::Av1, Codec::H265];
60
61 pub const fn id(self) -> u32 {
63 self as u32
64 }
65
66 pub fn from_id(id: u32) -> Option<Codec> {
68 [
69 Codec::Jpeg,
70 Codec::H264,
71 Codec::Vp8,
72 Codec::Vp9,
73 Codec::Av1,
74 Codec::H265,
75 ]
76 .into_iter()
77 .find(|c| c.id() == id)
78 }
79
80 pub fn parse(name: &str) -> Option<Codec> {
82 match name.trim().to_ascii_lowercase().as_str() {
83 "jpeg" | "mjpeg" => Some(Codec::Jpeg),
84 "h264" | "avc" => Some(Codec::H264),
85 "h265" | "hevc" => Some(Codec::H265),
86 "vp8" => Some(Codec::Vp8),
87 "vp9" => Some(Codec::Vp9),
88 "av1" => Some(Codec::Av1),
89 _ => None,
90 }
91 }
92
93 pub fn name(self) -> &'static str {
95 match self {
96 Codec::Jpeg => "jpeg",
97 Codec::H264 => "h264",
98 Codec::H265 => "h265",
99 Codec::Vp8 => "vp8",
100 Codec::Vp9 => "vp9",
101 Codec::Av1 => "av1",
102 }
103 }
104
105 pub fn display(self) -> &'static str {
107 match self {
108 Codec::Jpeg => "JPEG",
109 Codec::H264 => "H264",
110 Codec::H265 => "H265",
111 Codec::Vp8 => "VP8",
112 Codec::Vp9 => "VP9",
113 Codec::Av1 => "AV1",
114 }
115 }
116
117 pub fn is_video(self) -> bool {
119 self != Codec::Jpeg
120 }
121
122 pub fn stripes(self) -> bool {
125 self == Codec::Jpeg
126 }
127
128 pub fn wire_id(self) -> u8 {
130 self.id() as u8
131 }
132
133 pub fn from_wire_id(id: u8) -> Option<Codec> {
135 Codec::from_id(u32::from(id)).filter(|c| c.is_video())
136 }
137
138 pub fn data_type(self) -> i32 {
140 self.id() as i32
141 }
142
143 pub fn is_inter_coded(self) -> bool {
146 self.is_video()
147 }
148
149 pub fn fullcolor(self) -> bool {
152 matches!(self, Codec::H264 | Codec::H265 | Codec::Vp9)
153 }
154
155 pub fn high_bit_depth(self) -> bool {
159 matches!(self, Codec::H265 | Codec::Vp9 | Codec::Av1)
160 }
161
162 pub fn keyframes_self_contained(self) -> bool {
166 self.is_video()
167 }
168
169 pub fn quantizer_max(self) -> u32 {
172 match self {
173 Codec::Jpeg => 100,
174 Codec::H264 | Codec::H265 => 51,
175 Codec::Vp8 => 127,
176 Codec::Vp9 | Codec::Av1 => 255,
177 }
178 }
179
180 pub fn quantizer(self, crf: i32) -> u32 {
197 let crf = crf.clamp(0, 51) as u32;
198 match self {
199 Codec::Jpeg => crf,
200 Codec::H264 | Codec::H265 => crf,
201 Codec::Vp8 => interpolate(&VP8_QINDEX, crf),
202 Codec::Vp9 => interpolate(&VP9_QINDEX, crf),
203 Codec::Av1 => interpolate(&AV1_QINDEX, crf).max(1),
204 }
205 }
206
207 pub fn refresh_index(self, quality: i32) -> i32 {
212 let finer = quality - crate::ledger::REFRESH_FINER as i32;
213 if self != Codec::Vp8
214 || quality > VP8_FINEST_MATCHED
215 || self.quantizer(finer) <= VP8_REFRESH_QUANTIZER
216 {
217 return finer;
218 }
219 (0..finer)
220 .rev()
221 .find(|&i| self.quantizer(i) <= VP8_REFRESH_QUANTIZER)
222 .unwrap_or(0)
223 }
224
225 pub fn quantizer_bound(self, qp: i32) -> u32 {
228 if qp <= 0 { 0 } else { self.quantizer(qp) }
229 }
230
231 pub fn hardware_quantizer(self, hw: Hardware, crf: i32) -> u32 {
246 let crf = crf.clamp(0, 51) as u32;
247 match (self, hw) {
248 (Codec::H264, _) | (Codec::H265, Hardware::Vaapi) => {
249 interpolate(&H26X_HARDWARE_QP, crf)
250 }
251 (Codec::H265, Hardware::VaapiIntel) => interpolate(&H265_INTEL_QP, crf),
252 (Codec::Vp9, Hardware::Vaapi | Hardware::VaapiIntel) => {
253 interpolate(&VP9_VAAPI_QINDEX, crf)
254 }
255 (Codec::Av1, Hardware::Nvenc) => interpolate(&AV1_NVENC_QINDEX, crf).max(1),
256 (Codec::Av1, Hardware::Vaapi | Hardware::VaapiIntel) => {
257 interpolate(&AV1_VAAPI_QINDEX, crf).max(1)
258 }
259 _ => self.quantizer(crf as i32),
260 }
261 }
262
263 pub fn hardware_quantizer_bound(self, hw: Hardware, qp: i32) -> u32 {
265 if qp <= 0 {
266 0
267 } else {
268 self.hardware_quantizer(hw, qp)
269 }
270 }
271
272 pub fn quality_index(self, q: u32) -> u32 {
276 nearest_index(q, |crf| self.quantizer(crf))
277 }
278
279 pub fn hardware_quality_index(self, hw: Hardware, q: u32) -> u32 {
281 nearest_index(q, |crf| self.hardware_quantizer(hw, crf))
282 }
283}
284
285fn nearest_index(q: u32, quantizer: impl Fn(i32) -> u32) -> u32 {
287 (0..=51)
288 .min_by_key(|&crf| (i64::from(quantizer(crf)) - i64::from(q)).abs())
289 .unwrap_or(0) as u32
290}
291
292const VP8_QINDEX: [(u32, u32); 10] = [
294 (0, 0),
295 (15, 1),
296 (20, 3),
297 (25, 5),
298 (30, 24),
299 (35, 49),
300 (40, 73),
301 (45, 106),
302 (50, 127),
303 (51, 127),
304];
305const VP8_FINEST_MATCHED: i32 = 25;
308const VP8_REFRESH_QUANTIZER: u32 = 2;
318const VP9_QINDEX: [(u32, u32); 12] = [
320 (0, 0),
321 (5, 1),
322 (10, 6),
323 (15, 18),
324 (20, 32),
325 (25, 66),
326 (30, 108),
327 (35, 140),
328 (40, 176),
329 (45, 208),
330 (50, 236),
331 (51, 255),
332];
333const VP9_VAAPI_QINDEX: [(u32, u32); 12] = [
335 (0, 0),
336 (5, 2),
337 (10, 5),
338 (15, 11),
339 (20, 19),
340 (25, 48),
341 (30, 88),
342 (35, 124),
343 (40, 163),
344 (45, 200),
345 (50, 228),
346 (51, 240),
347];
348const AV1_QINDEX: [(u32, u32); 10] = [
350 (0, 0),
351 (10, 12),
352 (15, 43),
353 (20, 88),
354 (25, 134),
355 (30, 168),
356 (35, 190),
357 (40, 215),
358 (45, 253),
359 (51, 255),
360];
361const H26X_HARDWARE_QP: [(u32, u32); 11] = [
363 (0, 0),
364 (10, 9),
365 (15, 14),
366 (20, 17),
367 (25, 22),
368 (30, 27),
369 (35, 32),
370 (40, 37),
371 (45, 43),
372 (50, 47),
373 (51, 48),
374];
375const H265_INTEL_QP: [(u32, u32); 11] = [
377 (0, 0),
378 (10, 8),
379 (15, 12),
380 (20, 17),
381 (25, 24),
382 (30, 29),
383 (35, 34),
384 (40, 39),
385 (45, 45),
386 (50, 49),
387 (51, 50),
388];
389const AV1_VAAPI_QINDEX: [(u32, u32); 12] = [
391 (0, 1),
392 (5, 3),
393 (10, 10),
394 (15, 26),
395 (20, 40),
396 (25, 80),
397 (30, 106),
398 (35, 136),
399 (40, 171),
400 (45, 205),
401 (50, 236),
402 (51, 244),
403];
404const AV1_NVENC_QINDEX: [(u32, u32); 12] = [
406 (0, 1),
407 (5, 20),
408 (10, 26),
409 (15, 44),
410 (20, 66),
411 (25, 105),
412 (30, 135),
413 (35, 163),
414 (40, 195),
415 (45, 219),
416 (50, 241),
417 (51, 244),
418];
419
420fn interpolate(points: &[(u32, u32)], x: u32) -> u32 {
422 let (first, last) = (points[0], points[points.len() - 1]);
423 if x <= first.0 {
424 return first.1;
425 }
426 if x >= last.0 {
427 return last.1;
428 }
429 for pair in points.windows(2) {
430 let ((x0, y0), (x1, y1)) = (pair[0], pair[1]);
431 if x >= x0 && x <= x1 {
432 let span = i64::from(x1 - x0);
433 let along = i64::from(x - x0);
434 let delta = i64::from(y1) - i64::from(y0);
435 return (i64::from(y0) + (delta * along + span / 2) / span) as u32;
436 }
437 }
438 last.1
439}
440
441pub const VPX_QINDEX: [u8; 64] = [
444 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
445 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168,
446 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244,
447 249, 255,
448];
449pub const VP8_LEVEL_QINDEX: [u8; 64] = [
451 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30,
452 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 64, 67, 70, 73, 76, 79, 82, 85,
453 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127,
454];
455
456pub fn vpx_level(codec: Codec, qindex: u32) -> u32 {
459 let table: &[u8; 64] = if codec == Codec::Vp8 {
460 &VP8_LEVEL_QINDEX
461 } else {
462 &VPX_QINDEX
463 };
464 let target = i64::from(qindex.min(codec.quantizer_max()));
465 let mut best = 0usize;
466 for (level, &q) in table.iter().enumerate() {
467 if (i64::from(q) - target).abs() < (i64::from(table[best]) - target).abs() {
468 best = level;
469 }
470 }
471 best as u32
472}
473
474#[allow(clippy::too_many_arguments)]
479pub fn push_video_header(
480 out: &mut Vec<u8>,
481 codec: Codec,
482 frame_type: u8,
483 frame_id: u16,
484 y_start: u16,
485 width: u16,
486 height: u16,
487 reference: Reference,
488) {
489 out.push(WIRE_VIDEO);
490 out.push((frame_type & 0x0f) | (codec.wire_id() << 4));
491 out.extend_from_slice(&frame_id.to_be_bytes());
492 out.extend_from_slice(&y_start.to_be_bytes());
493 out.extend_from_slice(&width.to_be_bytes());
494 out.extend_from_slice(&height.to_be_bytes());
495 let reference = match reference {
496 Reference::Frame(id) => id,
497 Reference::None | Reference::Untracked => frame_id,
498 };
499 out.extend_from_slice(&reference.to_be_bytes());
500}
501
502pub fn push_jpeg_header(out: &mut Vec<u8>, frame_id: u16, y_start: u16) {
504 out.push(WIRE_JPEG);
505 out.push(0);
506 out.extend_from_slice(&frame_id.to_be_bytes());
507 out.extend_from_slice(&y_start.to_be_bytes());
508}
509
510pub fn parse_video_type(type_byte: u8) -> Option<(Codec, u8)> {
512 Codec::from_wire_id(type_byte >> 4).map(|c| (c, type_byte & 0x0f & !FRAME_ANCHOR))
513}
514
515pub fn frame_type_from_key(key: bool) -> u8 {
517 if key { FRAME_KEY } else { FRAME_DELTA }
518}
519
520pub fn h264_level(width: u32, height: u32, fps: u32, bitrate_bps: u64) -> u32 {
534 let mbs = u64::from(width).div_ceil(16) * u64::from(height).div_ceil(16);
535 let mbps = mbs * u64::from(fps.max(1));
536 const LEVELS: [(u32, u64, u64, u64); 8] = [
537 (41, 8192, 245760, 50_000_000),
538 (42, 8704, 522240, 50_000_000),
539 (50, 22080, 589824, 135_000_000),
540 (51, 36864, 983040, 240_000_000),
541 (52, 36864, 2073600, 240_000_000),
542 (60, 139264, 4177920, 240_000_000),
543 (61, 139264, 8355840, 480_000_000),
544 (62, 139264, 16711680, 800_000_000),
545 ];
546 for &(level, max_fs, max_mbps, max_br) in &LEVELS {
547 if mbs <= max_fs && mbps <= max_mbps && bitrate_bps <= max_br / 4 * 5 {
548 return level;
549 }
550 }
551 62
552}
553
554pub fn h264_dpb_frames(level: u32, width: u32, height: u32) -> u32 {
558 let mbs = u64::from(width).div_ceil(16) * u64::from(height).div_ceil(16);
559 let max_dpb_mbs: u64 = match level {
560 41 => 32768,
561 42 => 34816,
562 50 => 110400,
563 51 | 52 => 184320,
564 _ => 696320,
565 };
566 ((max_dpb_mbs / mbs.max(1)) as u32).clamp(1, REFERENCE_FRAMES)
567}
568
569#[cfg(any(feature = "gpl", test))]
573pub fn h264_reference_level(level: u32, width: u32, height: u32) -> u32 {
574 if level > 52 {
575 return level;
576 }
577 [41, 42, 50, 51, 52]
578 .into_iter()
579 .filter(|&l| l >= level)
580 .find(|&l| h264_dpb_frames(l, width, height) == REFERENCE_FRAMES)
581 .unwrap_or(52)
582}
583
584pub fn h265_level(width: u32, height: u32, fps: u32, bitrate_bps: u64, high_tier: bool) -> u32 {
593 let ps = u64::from(width) * u64::from(height);
594 let sr = ps * u64::from(fps.max(1));
595 const LEVELS: [(u32, u64, u64, u64, u64); 7] = [
596 (123, 2_228_224, 133_693_440, 20_000_000, 50_000_000),
597 (150, 8_912_896, 267_386_880, 25_000_000, 100_000_000),
598 (153, 8_912_896, 534_773_760, 40_000_000, 160_000_000),
599 (156, 8_912_896, 1_069_547_520, 60_000_000, 240_000_000),
600 (180, 35_651_584, 1_069_547_520, 60_000_000, 240_000_000),
601 (183, 35_651_584, 2_139_095_040, 120_000_000, 480_000_000),
602 (186, 35_651_584, 4_278_190_080, 240_000_000, 800_000_000),
603 ];
604 for &(level, max_ps, max_sr, main_br, high_br) in &LEVELS {
605 if ps <= max_ps && sr <= max_sr && bitrate_bps <= if high_tier { high_br } else { main_br }
606 {
607 return level;
608 }
609 }
610 186
611}
612
613pub fn h265_dpb_frames(level: u32, width: u32, height: u32) -> u32 {
618 let max_luma_ps: u64 = match level {
619 ..=123 => 2_228_224,
620 150..=156 => 8_912_896,
621 _ => 35_651_584,
622 };
623 let picture = u64::from(width) * u64::from(height);
624 let pictures = if picture <= max_luma_ps / 4 {
625 16
626 } else if picture <= max_luma_ps / 2 {
627 12
628 } else if picture <= max_luma_ps * 3 / 4 {
629 8
630 } else {
631 6
632 };
633 (pictures - 1).min(REFERENCE_FRAMES)
634}
635
636pub fn h265_tier(level: u32) -> u32 {
641 if level >= 120 { 1 } else { 0 }
642}
643
644pub fn av1_level(width: u32, height: u32, fps: u32, bitrate_bps: u64) -> u32 {
656 let ps = u64::from(width) * u64::from(height);
657 let rate = ps * u64::from(fps.max(1));
658 const LEVELS: [(u32, u64, u32, u32, u64, u64); 10] = [
659 (8, 2_359_296, 6144, 3456, 70_778_880, 12_000_000),
660 (9, 2_359_296, 6144, 3456, 141_557_760, 20_000_000),
661 (12, 8_912_896, 8192, 4352, 267_386_880, 30_000_000),
662 (13, 8_912_896, 8192, 4352, 534_773_760, 40_000_000),
663 (14, 8_912_896, 8192, 4352, 1_069_547_520, 60_000_000),
664 (15, 8_912_896, 8192, 4352, 1_069_547_520, 60_000_000),
665 (16, 35_651_584, 16384, 8704, 1_069_547_520, 60_000_000),
666 (17, 35_651_584, 16384, 8704, 2_139_095_040, 100_000_000),
667 (18, 35_651_584, 16384, 8704, 4_278_190_080, 160_000_000),
668 (19, 35_651_584, 16384, 8704, 4_278_190_080, 160_000_000),
669 ];
670 for &(level, max_ps, max_w, max_h, max_rate, max_br) in &LEVELS {
671 if ps <= max_ps
672 && width <= max_w
673 && height <= max_h
674 && rate <= max_rate
675 && bitrate_bps <= max_br
676 {
677 return level;
678 }
679 }
680 19
681}
682
683pub fn h264_frame_type(au: &[u8]) -> u8 {
690 let mut intra = false;
691 for nal in annexb_nals(au) {
692 match nal[0] & 0x1f {
693 5 => return FRAME_KEY,
694 1 => match h264_slice_is_intra(&nal[1..]) {
695 Some(true) => intra = true,
696 _ => return FRAME_DELTA,
697 },
698 _ => {}
699 }
700 }
701 if intra { FRAME_INTRA } else { FRAME_DELTA }
702}
703
704pub fn h265_frame_type(au: &[u8]) -> u8 {
708 for nal in annexb_nals(au) {
709 let nal_type = (nal[0] >> 1) & 0x3f;
710 if (16..=23).contains(&nal_type) {
711 return FRAME_KEY;
712 }
713 }
714 FRAME_DELTA
715}
716
717pub fn vp8_is_key(frame: &[u8]) -> bool {
719 frame.first().is_some_and(|b| b & 1 == 0)
720}
721
722pub fn vp9_is_key(frame: &[u8]) -> bool {
725 let Some(&b) = frame.first() else {
726 return false;
727 };
728 if b >> 6 != 0b10 {
729 return false;
730 }
731 let profile = ((b >> 5) & 1) | (((b >> 4) & 1) << 1);
732 let (show_existing, frame_type) = if profile == 3 {
733 (b & 0x04, b & 0x02)
734 } else {
735 (b & 0x08, b & 0x04)
736 };
737 show_existing == 0 && frame_type == 0
738}
739
740pub fn vp9_base_q_idx(frame: &[u8]) -> Option<u32> {
744 let mut pos = 0usize;
745 let mut bits = |n: usize| -> Option<u32> {
746 let mut value = 0u32;
747 for _ in 0..n {
748 let byte = *frame.get(pos / 8)?;
749 value = (value << 1) | u32::from((byte >> (7 - pos % 8)) & 1);
750 pos += 1;
751 }
752 Some(value)
753 };
754 if bits(2)? != 2 {
755 return None;
756 }
757 let profile = bits(1)? | (bits(1)? << 1);
758 if profile == 3 {
759 bits(1)?;
760 }
761 if bits(1)? == 1 {
762 return None;
763 }
764 let key = bits(1)? == 0;
765 let show_frame = bits(1)? == 1;
766 let error_resilient = bits(1)? == 1;
767 let color_config = |bits: &mut dyn FnMut(usize) -> Option<u32>| -> Option<()> {
768 if profile >= 2 {
769 bits(1)?;
770 }
771 if bits(3)? != 7 {
772 bits(1)?;
773 if profile & 1 == 1 {
774 bits(3)?;
775 }
776 } else if profile & 1 == 1 {
777 bits(1)?;
778 }
779 Some(())
780 };
781 let sizes = |bits: &mut dyn FnMut(usize) -> Option<u32>| -> Option<()> {
782 bits(32)?;
783 if bits(1)? == 1 {
784 bits(32)?;
785 }
786 Some(())
787 };
788 if key {
789 bits(24)?;
790 color_config(&mut bits)?;
791 sizes(&mut bits)?;
792 } else {
793 let intra_only = !show_frame && bits(1)? == 1;
794 if !error_resilient {
795 bits(2)?;
796 }
797 if intra_only {
798 bits(24)?;
799 if profile > 0 {
800 color_config(&mut bits)?;
801 }
802 bits(8)?;
803 sizes(&mut bits)?;
804 } else {
805 bits(8)?;
806 bits(12)?;
807 let mut found = false;
808 for _ in 0..3 {
809 if bits(1)? == 1 {
810 found = true;
811 break;
812 }
813 }
814 if !found {
815 bits(32)?;
816 }
817 if bits(1)? == 1 {
818 bits(32)?;
819 }
820 bits(1)?;
821 if bits(1)? == 0 {
822 bits(2)?;
823 }
824 }
825 }
826 if !error_resilient {
827 bits(2)?;
828 }
829 bits(2)?;
830 bits(9)?;
831 if bits(1)? == 1 && bits(1)? == 1 {
832 for _ in 0..6 {
833 if bits(1)? == 1 {
834 bits(7)?;
835 }
836 }
837 }
838 bits(8)
839}
840
841pub fn av1_is_key(tu: &[u8]) -> bool {
845 let mut pos = 0usize;
846 while pos < tu.len() {
847 let header = tu[pos];
848 let obu_type = (header >> 3) & 0x0f;
849 let has_extension = header & 0x04 != 0;
850 let has_size = header & 0x02 != 0;
851 let mut i = pos + 1 + usize::from(has_extension);
852 let size = if has_size {
853 let mut value = 0u64;
854 let mut shift = 0u32;
855 loop {
856 if i >= tu.len() || shift > 56 {
857 return false;
858 }
859 let byte = tu[i];
860 i += 1;
861 value |= u64::from(byte & 0x7f) << shift;
862 if byte & 0x80 == 0 {
863 break;
864 }
865 shift += 7;
866 }
867 value as usize
868 } else {
869 tu.len().saturating_sub(i)
870 };
871 if matches!(obu_type, 3 | 6) {
872 let Some(&first) = tu.get(i) else {
873 return false;
874 };
875 let show_existing_frame = first & 0x80 != 0;
876 let frame_type = (first >> 5) & 0x03;
877 return !show_existing_frame && frame_type == 0;
878 }
879 pos = i.saturating_add(size);
880 }
881 false
882}
883
884pub(crate) use super::bits::annexb_nals;
885
886fn h264_slice_is_intra(payload: &[u8]) -> Option<bool> {
890 let mut rbsp = [0u8; 12];
891 let mut n = 0usize;
892 let mut zeros = 0usize;
893 for &b in payload {
894 if n == rbsp.len() {
895 break;
896 }
897 if zeros >= 2 && b == 3 {
898 zeros = 0;
899 continue;
900 }
901 zeros = if b == 0 { zeros + 1 } else { 0 };
902 rbsp[n] = b;
903 n += 1;
904 }
905 let mut pos = 0usize;
906 let bit = |p: &mut usize| -> Option<u8> {
907 if *p / 8 >= n {
908 return None;
909 }
910 let b = (rbsp[*p / 8] >> (7 - *p % 8)) & 1;
911 *p += 1;
912 Some(b)
913 };
914 let ue = |p: &mut usize| -> Option<u32> {
915 let mut leading = 0u32;
916 while bit(p)? == 0 {
917 leading += 1;
918 if leading > 24 {
919 return None;
920 }
921 }
922 let mut val = 0u32;
923 for _ in 0..leading {
924 val = (val << 1) | u32::from(bit(p)?);
925 }
926 Some((1u32 << leading) - 1 + val)
927 };
928 ue(&mut pos)?;
929 let slice_type = ue(&mut pos)?;
930 if slice_type > 9 {
931 return None;
932 }
933 Some(matches!(slice_type % 5, 2 | 4))
934}
935
936#[cfg(test)]
937mod tests {
938 use super::*;
939
940 #[test]
944 fn a_vp8_refresh_comes_to_its_quantizer_two_at_the_finest_indices() {
945 for quality in 0..=51 {
946 let finer = quality - crate::ledger::REFRESH_FINER as i32;
947 for codec in [Codec::H264, Codec::H265, Codec::Vp9, Codec::Av1] {
948 assert_eq!(
949 codec.refresh_index(quality),
950 finer,
951 "{codec:?} at {quality}"
952 );
953 }
954 let vp8 = Codec::Vp8.refresh_index(quality);
955 if quality > VP8_FINEST_MATCHED {
956 assert_eq!(vp8, finer, "VP8 at {quality}");
957 } else {
958 assert!(vp8 <= finer, "VP8 at {quality}: {vp8}");
959 assert!(Codec::Vp8.quantizer(vp8) <= VP8_REFRESH_QUANTIZER);
960 assert!(vp8 == finer || Codec::Vp8.quantizer(vp8 + 1) > VP8_REFRESH_QUANTIZER);
961 }
962 }
963 assert_eq!(Codec::Vp8.refresh_index(25), 18);
964 assert_eq!(Codec::Vp8.refresh_index(26), 23);
965 }
966
967 #[test]
970 fn hevc_tier_follows_the_level() {
971 assert_eq!(h265_tier(93), 0);
972 assert_eq!(h265_tier(120), 1);
973 assert_eq!(h265_tier(h265_level(1280, 720, 30, 0, true)), 1);
974 assert_eq!(h265_tier(h265_level(3840, 2160, 60, 0, true)), 1);
975 }
976
977 #[test]
979 fn names_round_trip() {
980 for codec in [
981 Codec::Jpeg,
982 Codec::H264,
983 Codec::H265,
984 Codec::Vp8,
985 Codec::Vp9,
986 Codec::Av1,
987 ] {
988 assert_eq!(Codec::parse(codec.name()), Some(codec));
989 }
990 assert_eq!(Codec::parse("HEVC"), Some(Codec::H265));
991 assert_eq!(Codec::parse(" avc "), Some(Codec::H264));
992 assert_eq!(Codec::parse("mjpeg"), Some(Codec::Jpeg));
993 assert_eq!(Codec::parse("h266"), None);
994 }
995
996 #[test]
999 fn wire_ids_are_distinct_and_packed() {
1000 let mut seen = std::collections::HashSet::new();
1001 for codec in Codec::VIDEO {
1002 assert!(seen.insert(codec.wire_id()));
1003 assert_eq!(Codec::from_wire_id(codec.wire_id()), Some(codec));
1004 let mut out = Vec::new();
1005 push_video_header(
1006 &mut out,
1007 codec,
1008 FRAME_KEY,
1009 0x1234,
1010 7,
1011 1920,
1012 1080,
1013 Reference::None,
1014 );
1015 assert_eq!(out.len(), VIDEO_HEADER_LEN);
1016 assert_eq!(out[0], WIRE_VIDEO);
1017 assert_eq!(parse_video_type(out[1]), Some((codec, FRAME_KEY)));
1018 assert_eq!(
1019 &out[2..],
1020 &[0x12, 0x34, 0, 7, 0x07, 0x80, 0x04, 0x38, 0x12, 0x34]
1021 );
1022 out.clear();
1023 push_video_header(
1024 &mut out,
1025 codec,
1026 FRAME_DELTA,
1027 0x1235,
1028 7,
1029 1920,
1030 1080,
1031 Reference::Frame(0x1230),
1032 );
1033 assert_eq!(
1034 &out[10..],
1035 &[0x12, 0x30],
1036 "a predicted frame names its reference"
1037 );
1038 }
1039 assert_eq!(
1040 Codec::from_wire_id(0),
1041 None,
1042 "JPEG never rides the video tag"
1043 );
1044 assert_eq!(Codec::from_wire_id(9), None);
1045 for id in 0..6 {
1046 assert_eq!(Codec::from_id(id).map(|c| c.id()), Some(id));
1047 }
1048 assert_eq!(Codec::from_id(6), None);
1049 assert_eq!(Codec::H264.data_type(), 1);
1050 assert_eq!(Codec::Jpeg.data_type(), 0);
1051 let mut jpeg = Vec::new();
1052 push_jpeg_header(&mut jpeg, 3, 64);
1053 assert_eq!(jpeg, [WIRE_JPEG, 0, 0, 3, 0, 64]);
1054 }
1055
1056 #[test]
1058 fn striping_and_chroma_by_codec() {
1059 assert!(Codec::Jpeg.stripes());
1060 for codec in Codec::VIDEO {
1061 assert!(!codec.stripes(), "{codec:?}");
1062 assert!(codec.is_video());
1063 }
1064 assert!(Codec::H264.fullcolor() && Codec::H265.fullcolor() && Codec::Vp9.fullcolor());
1065 assert!(!Codec::Vp8.fullcolor() && !Codec::Av1.fullcolor());
1066 }
1067
1068 #[test]
1072 fn quantizer_maps_are_monotonic_and_bounded() {
1073 for codec in Codec::VIDEO {
1074 let mut last = 0;
1075 for crf in 0..=51 {
1076 let q = codec.quantizer(crf);
1077 assert!(q >= last, "{codec:?} crf {crf}: {q} < {last}");
1078 for hw in [Hardware::Nvenc, Hardware::Vaapi, Hardware::VaapiIntel] {
1079 let h = codec.hardware_quantizer(hw, crf);
1080 assert!(h >= codec.hardware_quantizer(hw, crf.max(1) - 1));
1081 assert!(h <= codec.quantizer_max());
1082 }
1083 assert!(q <= codec.quantizer_max());
1084 last = q;
1085 }
1086 assert_eq!(codec.quantizer(51), codec.quantizer_max());
1087 assert_eq!(codec.quantizer(99), codec.quantizer(51));
1088 assert_eq!(codec.quantizer(-4), codec.quantizer(0));
1089 assert_eq!(codec.quantizer_bound(0), 0);
1090 assert_eq!(codec.quantizer_bound(30), codec.quantizer(30));
1091 }
1092 assert_eq!(Codec::H264.quantizer(25), 25);
1093 assert_eq!(Codec::H265.quantizer(25), 25);
1094 assert_eq!(Codec::Av1.quantizer(0), 1);
1095 assert_eq!(Codec::H264.hardware_quantizer(Hardware::Nvenc, 25), 22);
1096 assert_eq!(Codec::H264.hardware_quantizer(Hardware::Vaapi, 25), 22);
1097 assert_eq!(Codec::H265.hardware_quantizer(Hardware::Nvenc, 25), 25);
1098 assert_eq!(Codec::H265.hardware_quantizer(Hardware::Vaapi, 25), 22);
1099 assert_eq!(Codec::Av1.hardware_quantizer(Hardware::Vaapi, 25), 80);
1100 assert_eq!(Codec::H265.hardware_quantizer(Hardware::VaapiIntel, 25), 24);
1101 assert_eq!(Codec::H264.hardware_quantizer(Hardware::VaapiIntel, 25), 22);
1102 assert_eq!(Codec::Av1.hardware_quantizer(Hardware::VaapiIntel, 25), 80);
1103 assert_eq!(Codec::Av1.hardware_quantizer(Hardware::Nvenc, 0), 1);
1104 assert_eq!(Codec::Vp9.quantizer(25), 66);
1105 assert_eq!(Codec::Vp9.hardware_quantizer(Hardware::Vaapi, 25), 48);
1106 assert_eq!(Codec::Vp9.hardware_quantizer(Hardware::VaapiIntel, 25), 48);
1107 assert_eq!(
1108 Codec::Vp8.hardware_quantizer(Hardware::Vaapi, 25),
1109 Codec::Vp8.quantizer(25)
1110 );
1111 assert_eq!(Codec::H264.hardware_quantizer_bound(Hardware::Nvenc, 0), 0);
1112 assert_eq!(Codec::H264.hardware_quality_index(Hardware::Nvenc, 22), 25);
1113 assert_eq!(interpolate(&[(0, 0), (10, 100)], 5), 50);
1114 assert_eq!(interpolate(&[(0, 0), (10, 100)], 3), 30);
1115 }
1116
1117 #[test]
1120 fn vpx_levels_invert_the_tables() {
1121 assert_eq!(vpx_level(Codec::Vp9, 0), 0);
1122 assert_eq!(vpx_level(Codec::Vp9, 255), 63);
1123 assert_eq!(vpx_level(Codec::Vp9, 104), 26);
1124 assert_eq!(vpx_level(Codec::Av1, 249), 62);
1125 assert_eq!(vpx_level(Codec::Vp8, 0), 0);
1126 assert_eq!(vpx_level(Codec::Vp8, 127), 63);
1127 assert_eq!(
1128 vpx_level(Codec::Vp8, 52),
1129 36,
1130 "a tie resolves to the lower level"
1131 );
1132 for level in 0..64u32 {
1133 assert_eq!(
1134 vpx_level(Codec::Vp9, u32::from(VPX_QINDEX[level as usize])),
1135 level
1136 );
1137 assert_eq!(
1138 vpx_level(Codec::Vp8, u32::from(VP8_LEVEL_QINDEX[level as usize])),
1139 level
1140 );
1141 }
1142 }
1143
1144 #[test]
1147 fn the_reference_level_holds_every_reference_up_to_5_2() {
1148 assert_eq!(h264_reference_level(41, 1280, 720), 41);
1149 assert_eq!(h264_reference_level(42, 1920, 1080), 50);
1150 assert_eq!(h264_dpb_frames(50, 1920, 1080), REFERENCE_FRAMES);
1151 assert_eq!(h264_reference_level(51, 2560, 1440), 51);
1152 assert_eq!(h264_reference_level(52, 3840, 2160), 52);
1153 assert_eq!(h264_dpb_frames(52, 3840, 2160), 5);
1154 assert_eq!(h264_reference_level(60, 7680, 4320), 60);
1155 }
1156
1157 #[test]
1158 fn dpb_follows_the_level() {
1159 assert_eq!(h264_dpb_frames(41, 1280, 720), REFERENCE_FRAMES);
1160 assert_eq!(h264_dpb_frames(42, 1920, 1080), 4);
1161 assert_eq!(h264_dpb_frames(50, 2560, 1440), 7);
1162 assert_eq!(h264_dpb_frames(52, 3840, 2160), 5);
1163 assert_eq!(h264_dpb_frames(62, 7680, 4320), 5);
1164 assert_eq!(h265_dpb_frames(123, 1920, 1080), 5);
1165 assert_eq!(h265_dpb_frames(123, 1280, 720), REFERENCE_FRAMES);
1166 assert_eq!(h265_dpb_frames(156, 3840, 2160), 5);
1167 assert_eq!(h265_dpb_frames(180, 3840, 2160), REFERENCE_FRAMES);
1168 }
1169
1170 #[test]
1173 fn level_ladders() {
1174 assert_eq!(h264_level(1920, 1080, 60, 0), 42);
1175 assert_eq!(h264_level(1280, 720, 30, 0), 41);
1176 assert_eq!(h264_level(3840, 2160, 60, 0), 52);
1177 assert_eq!(h264_level(7680, 4320, 60, 0), 61);
1178 assert_eq!(h264_level(16384, 16384, 240, 0), 62);
1179
1180 assert_eq!(h265_level(1920, 1080, 60, 0, true), 123);
1181 assert_eq!(h265_level(1920, 1080, 65, 0, true), 150);
1182 assert_eq!(h265_level(3840, 2160, 60, 0, true), 153);
1183 assert_eq!(h265_level(3840, 2160, 120, 0, true), 156);
1184 assert_eq!(h265_level(7680, 4320, 30, 0, true), 180);
1185 assert_eq!(h265_level(7680, 4320, 60, 0, true), 183);
1186 assert_eq!(h265_level(7680, 4320, 120, 0, true), 186);
1187 assert_eq!(h265_level(16384, 16384, 240, 0, true), 186);
1188
1189 assert_eq!(av1_level(1280, 720, 30, 0), 8);
1190 assert_eq!(av1_level(1920, 1080, 60, 0), 9);
1191 assert_eq!(av1_level(3840, 2160, 60, 0), 13);
1192 assert_eq!(av1_level(3840, 2160, 120, 0), 14);
1193 assert_eq!(
1194 av1_level(4096, 2304, 30, 0),
1195 16,
1196 "larger than 5.x's MaxPicSize"
1197 );
1198 assert_eq!(av1_level(7680, 4320, 60, 0), 17);
1199 assert_eq!(av1_level(7680, 4320, 120, 0), 18);
1200 assert_eq!(av1_level(8192, 4352, 60, 0), 17);
1202 assert_eq!(av1_level(8192, 4352, 240, 0), 19);
1203 }
1204
1205 #[test]
1209 fn level_ladders_carry_the_bitrate() {
1210 assert_eq!(h264_level(1920, 1080, 60, 62_500_000), 42);
1211 assert_eq!(h264_level(1920, 1080, 60, 100_000_000), 50);
1212 assert_eq!(h264_level(1920, 1080, 60, 300_000_000), 51);
1213 assert_eq!(h264_level(1920, 1080, 60, 1_000_000_000), 62);
1214
1215 assert_eq!(h265_level(1920, 1080, 60, 50_000_000, true), 123);
1216 assert_eq!(h265_level(1920, 1080, 60, 60_000_000, true), 150);
1217 assert_eq!(h265_level(1920, 1080, 60, 60_000_000, false), 156);
1218 assert_eq!(h265_level(1920, 1080, 60, 20_000_000, false), 123);
1219 assert_eq!(h265_level(3840, 2160, 60, 200_000_000, true), 156);
1220
1221 assert_eq!(av1_level(1920, 1080, 60, 20_000_000), 9);
1222 assert_eq!(av1_level(1920, 1080, 60, 25_000_000), 12);
1223 assert_eq!(av1_level(3840, 2160, 60, 45_000_000), 14);
1224 assert_eq!(av1_level(1280, 720, 30, 100_000_000), 17);
1225 assert_eq!(av1_level(1280, 720, 30, 1_000_000_000), 19);
1226 }
1227
1228 #[test]
1231 fn h264_labels_from_the_bitstream() {
1232 let idr = [
1233 0, 0, 0, 1, 0x67, 0x64, 0, 0x1f, 0, 0, 1, 0x65, 0x88, 0x84, 0,
1234 ];
1235 assert_eq!(h264_frame_type(&idr), FRAME_KEY);
1236 let intra = [0, 0, 1, 0x41, 0b1000_1000, 0b0000_0000];
1238 assert_eq!(h264_frame_type(&intra), FRAME_INTRA);
1239 let p = [0, 0, 1, 0x41, 0b1100_0000];
1241 assert_eq!(h264_frame_type(&p), FRAME_DELTA);
1242 assert_eq!(h264_frame_type(&[0, 0, 1, 0x41]), FRAME_DELTA);
1243 assert_eq!(h264_frame_type(&[]), FRAME_DELTA);
1244 }
1245
1246 #[test]
1250 fn h265_labels_from_the_bitstream() {
1251 let idr = [0, 0, 0, 1, 0x40, 0x01, 0x0c, 0, 0, 1, 0x26, 0x01, 0xaf];
1252 assert_eq!(h265_frame_type(&idr), FRAME_KEY);
1253 let cra = [0, 0, 1, 0x2a, 0x01, 0xaf];
1254 assert_eq!(h265_frame_type(&cra), FRAME_KEY);
1255 let trail = [0, 0, 1, 0x02, 0x01, 0xd0];
1256 assert_eq!(h265_frame_type(&trail), FRAME_DELTA);
1257 let headers_only = [0, 0, 1, 0x40, 0x01, 0, 0, 1, 0x42, 0x01];
1258 assert_eq!(h265_frame_type(&headers_only), FRAME_DELTA);
1259 }
1260
1261 #[test]
1264 fn vpx_labels_from_the_bitstream() {
1265 assert!(vp8_is_key(&[0x50, 0x42, 0x00]));
1266 assert!(!vp8_is_key(&[0x51, 0x42, 0x00]));
1267 assert!(!vp8_is_key(&[]));
1268 assert!(vp9_is_key(&[0x82, 0x49, 0x83]));
1269 assert!(!vp9_is_key(&[0x86, 0x00]));
1270 assert!(!vp9_is_key(&[0x8a, 0x00]));
1271 assert!(vp9_is_key(&[0xb0, 0x00]), "profile 3");
1272 assert!(!vp9_is_key(&[0xb2, 0x00]), "profile 3 inter");
1273 assert!(!vp9_is_key(&[0x42, 0x00]), "bad frame marker");
1274 }
1275
1276 #[test]
1280 fn av1_labels_from_the_temporal_unit() {
1281 let key = [0x12, 0x00, 0x0a, 0x01, 0x00, 0x32, 0x02, 0x10, 0x00];
1283 assert!(av1_is_key(&key));
1284 let inter = [0x12, 0x00, 0x32, 0x02, 0x30, 0x00];
1285 assert!(!av1_is_key(&inter));
1286 let existing = [0x32, 0x01, 0x80];
1287 assert!(!av1_is_key(&existing));
1288 let frame_header_only = [0x1a, 0x01, 0x00];
1289 assert!(av1_is_key(&frame_header_only));
1290 assert!(!av1_is_key(&[0x12, 0x00]));
1291 assert!(!av1_is_key(&[
1292 0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1293 ]));
1294 assert!(!av1_is_key(&[]));
1295 }
1296}