Skip to main content

pixelflux/encoders/
codec.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5 */
6
7//! What every encoder backend shares about a codec: its name and wire identity, the
8//! quantizer domain the session-wide quality index maps onto, the level a stream of a
9//! given geometry advertises, and the bitstream reads that label a frame on the wire.
10
11/// The picture codec of a capture session, and of a virtual-camera uplink. `Jpeg` is the
12/// striped still-image mode; the rest are video codecs, which stream as whole frames. The
13/// discriminants are the codec ids the
14/// Python API speaks (`VirtualCamera.CODEC_*`) and the video wire ids.
15#[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/// The hardware encoder family a session's quantizer curve is read for
27/// (`Codec::hardware_quantizer`).
28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub enum Hardware {
30    Nvenc,
31    Vaapi,
32    VaapiIntel,
33}
34
35use super::reference::{REFERENCE_FRAMES, Reference};
36
37/// Wire tag of a JPEG stripe: `u8 reserved`, `u16 frame id`, `u16 stripe Y`, JPEG data.
38pub const WIRE_JPEG: u8 = 0x03;
39/// Wire tag of an encoded video frame: a type byte whose low nibble is the frame kind and
40/// whose high nibble is the codec's [`Codec::wire_id`], then `u16 frame id`, `u16 y` (the
41/// frame's top row, 0), `u16 width`, `u16 height`, `u16 reference` (the frame it predicts
42/// from, its own id where it names none), and the codec's own bitstream.
43pub const WIRE_VIDEO: u8 = 0x04;
44/// Frame kinds in the low nibble of the video type byte: a decode entry point, an
45/// intra-coded picture that is not one, and a predicted picture.
46pub const FRAME_KEY: u8 = 0x01;
47pub const FRAME_INTRA: u8 = 0x02;
48pub const FRAME_DELTA: u8 = 0x00;
49/// A bit ORed into a delta frame's kind: the session keeps the frame as a long-term reference and
50/// it predicts from one every client holds (`ReferenceWindow::settle`), so every client can
51/// decode it.
52pub const FRAME_ANCHOR: u8 = 0x08;
53/// Bytes of the JPEG stripe header and the video frame header.
54pub const JPEG_HEADER_LEN: usize = 6;
55pub const VIDEO_HEADER_LEN: usize = 12;
56
57impl Codec {
58    /// The video codecs, in wire-id order.
59    pub const VIDEO: [Codec; 5] = [Codec::H264, Codec::Vp8, Codec::Vp9, Codec::Av1, Codec::H265];
60
61    /// The codec's numeric id, as the Python API and the video wire carry it.
62    pub const fn id(self) -> u32 {
63        self as u32
64    }
65
66    /// The codec a numeric id names.
67    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    /// The codec a settings name selects; `None` for a name no backend serves.
81    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    /// The settings and log name of the codec.
94    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    /// The name a stream line prints.
106    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    /// Whether the session is a video stream rather than striped stills.
118    pub fn is_video(self) -> bool {
119        self != Codec::Jpeg
120    }
121
122    /// Whether a frame of this codec is cut into independently encoded stripes: the
123    /// still-image mode is, and every video codec streams whole frames.
124    pub fn stripes(self) -> bool {
125        self == Codec::Jpeg
126    }
127
128    /// The codec's identity in the high nibble of the video type byte: its id.
129    pub fn wire_id(self) -> u8 {
130        self.id() as u8
131    }
132
133    /// The video codec a wire id names.
134    pub fn from_wire_id(id: u8) -> Option<Codec> {
135        Codec::from_id(u32::from(id)).filter(|c| c.is_video())
136    }
137
138    /// The codec tag the Python `StripeFrame` carries: the codec id.
139    pub fn data_type(self) -> i32 {
140        self.id() as i32
141    }
142
143    /// Whether frames depend on earlier ones, so a dropped frame forces a wait for a key
144    /// frame.
145    pub fn is_inter_coded(self) -> bool {
146        self.is_video()
147    }
148
149    /// Whether the codec can carry 4:4:4 chroma at all (H.264 High 4:4:4, H.265 RExt, VP9
150    /// profile 1); whether a given backend does is negotiated by that backend.
151    pub fn fullcolor(self) -> bool {
152        matches!(self, Codec::H264 | Codec::H265 | Codec::Vp9)
153    }
154
155    /// Whether the codec has a 10-bit profile a session here can ask for (H.265 Main 10 and
156    /// its 4:4:4, VP9 profiles 2 and 3, AV1); whether a given backend does is negotiated by
157    /// that backend.
158    pub fn high_bit_depth(self) -> bool {
159        matches!(self, Codec::H265 | Codec::Vp9 | Codec::Av1)
160    }
161
162    /// Whether a forced key frame of this codec repeats the stream's parameter sets, so
163    /// a joining decoder can start there. Every backend is configured to, so the answer
164    /// is the same for all of them.
165    pub fn keyframes_self_contained(self) -> bool {
166        self.is_video()
167    }
168
169    /// The top of the codec's quantizer domain: H.26x QP, the VP8 quantizer index, or
170    /// the VP9 / AV1 `base_q_idx`. The value a backend programs never exceeds it.
171    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    /// The quantizer, in this codec's own domain, that a session quality index (`video_crf`,
181    /// on the H.26x QP scale) selects.
182    ///
183    /// H.26x takes the index as its QP. The VP8, VP9, and AV1 quantizer indices come from
184    /// tables measured on the software encoders against libx264 (ultrafast, zerolatency, four
185    /// threads) at the same index, every encoder at the settings pixelflux gives it — VP8 at
186    /// libvpx speed 16, VP9 at speed 8 with screen tuning, AV1 at SVT-AV1 preset 11 in its
187    /// real-time mode — interpolated in between. An AV1 point is the quantizer whose SSIM
188    /// matches on a scrolling text desktop. A VP8 or VP9 point is the one whose PSNR matches,
189    /// the finest of a text desktop held still, the same scrolled, and a gradient wallpaper,
190    /// which agree within two libvpx levels for VP9; VP8 reaches 43 dB at its finest, so
191    /// below index 25 it has nothing left to match. Each table ends at the codec's maximum
192    /// quantizer at index 51, since past its last matched point the encoder cannot degrade
193    /// as far as x264 does and there is nothing left to match. A hardware session reads
194    /// `hardware_quantizer`. An AV1 index of zero is lossless, so its floor is one; the
195    /// SVT-AV1 session floors its level at ten, below which its real-time mode miscodes.
196    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    /// The quality index a capped constant quality's refresh codes a block at
208    /// (`ledger::BlockLedger::refresh`), the session's being `quality`: `ledger::REFRESH_FINER`
209    /// steps finer, and VP8's no coarser than its quantizer `VP8_REFRESH_QUANTIZER` where
210    /// `quality` is at or under `VP8_FINEST_MATCHED`.
211    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    /// The quantizer a CBR QP clamp (`video_min_qp` / `video_max_qp`, on the H.26x scale)
226    /// becomes in this codec's domain; zero stays zero, meaning "the encoder's default".
227    pub fn quantizer_bound(self, qp: i32) -> u32 {
228        if qp <= 0 { 0 } else { self.quantizer(qp) }
229    }
230
231    /// `quantizer` for a hardware session, matched to libx264 the same way. H.264 is measured on
232    /// NVENC (Pascal and Ada) and on AMD's VA-API, which agree within a step, each coding a
233    /// quantizer about three finer than the index to match x264; AMD's VA-API H.265 follows
234    /// the same curve within a step, where NVENC's H.265 is within two steps of the index from
235    /// 22 up and keeps it. Intel's VA-API H.265 matches x264 on a still frame at that curve but
236    /// refines a moving picture well past it for fewer bytes (Arc and Alder Lake-N), so it reads
237    /// one two steps coarser from index 25 up; below 20 its still frames of text fall 3 to 4 dB
238    /// short of x264's at that curve, so there it reads one finer, down to the floor of 10 its
239    /// low-power encoder codes (`vaapi::h265::INTEL_LOW_POWER_MIN_QP`). AV1 has a curve per backend:
240    /// NVENC's is measured on Ada, and VA-API's on Intel (Arc) with the in-loop filters its
241    /// constant-quantizer frames carry, on a
242    /// text desktop and a gradient wallpaper, taking the finer match of the two. VA-API's VP9
243    /// is matched the same way on Intel (Arc), finer than libvpx at the same index on text.
244    /// VP8 keeps the software table. NVENC refuses an AV1 index of zero, so the floor stays one.
245    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    /// `quantizer_bound` for a hardware session.
264    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    /// The session quality index whose quantizer (`quantizer`) is nearest `q`, a quantizer of
273    /// this codec's domain: what a rate-controlled frame's quantizer amounts to on the H.26x
274    /// scale the quality settings use.
275    pub fn quality_index(self, q: u32) -> u32 {
276        nearest_index(q, |crf| self.quantizer(crf))
277    }
278
279    /// `quality_index` for a hardware session.
280    pub fn hardware_quality_index(self, hw: Hardware, q: u32) -> u32 {
281        nearest_index(q, |crf| self.hardware_quantizer(hw, crf))
282    }
283}
284
285/// The quality index in `0..=51` whose quantizer is nearest `q`, the lowest on a tie.
286fn 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
292/// Session quality index → VP8 quantizer index (0..=127) breakpoints.
293const 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];
305/// The finest session quality index `VP8_QINDEX` matches against x264, under which a step of the
306/// index moves VP8's quantizer by one or none.
307const VP8_FINEST_MATCHED: i32 = 25;
308/// The VP8 quantizer a capped CRF's refresh codes a block at, at the coarsest, where the session's
309/// quality index is at or under `VP8_FINEST_MATCHED` (`Codec::refresh_index`), where three index
310/// steps move VP8's quantizer by one or two. Refreshed three steps finer, a 320x240 page of text a
311/// capped session coded bound came out 0.5 dB under the uncapped session at indices 22 to 24, and
312/// a 1280x720 page of text and UI 0.11 under at 22 and 23; at quantizer 2 they came within 0.06 dB
313/// at 22 and 23 and level or past at 24 and 25, at 4% fewer to 8% more bytes. Quantizer 3 came out
314/// under 4 (43.95 dB against 44.40 at 25), and 1 under 2 (44.68 against 44.79, at 4% more bytes);
315/// nine index steps at every index took those past 26 to quantizers 1 to 9, 4 to 17 dB past the
316/// session's quality at up to twice the bytes.
317const VP8_REFRESH_QUANTIZER: u32 = 2;
318/// Session quality index → VP9 `base_q_idx` (0..=255) breakpoints.
319const 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];
333/// Session quality index → VA-API VP9 `base_q_idx` breakpoints.
334const 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];
348/// Session quality index → AV1 `base_q_idx` (0..=255) breakpoints.
349const 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];
361/// Session quality index → hardware H.264 QP breakpoints, and VA-API H.265's.
362const 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];
375/// Session quality index → Intel VA-API H.265 QP breakpoints.
376const 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];
389/// Session quality index → VA-API AV1 `base_q_idx` breakpoints.
390const 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];
404/// Session quality index → NVENC AV1 `base_q_idx` breakpoints.
405const 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
420/// Piecewise-linear lookup of `x` in ascending `(x, y)` breakpoints, clamped at both ends.
421fn 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
441/// `base_q_idx` of each libvpx / libaom quantizer level 0..=63, as those libraries map
442/// their `--min-q` / `--max-q` / `--cq-level` arguments.
443pub 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];
449/// VP8 quantizer index of each libvpx VP8 quantizer level 0..=63.
450pub 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
456/// The libvpx / SVT-AV1 quantizer level (0..=63) closest to a quantizer index of
457/// `codec`'s domain: the software encoders take the level, the hardware ones the index.
458pub 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/// Append the header of one encoded video frame: the tag, the codec and frame kind, then the
475/// frame id, its top row, its width and height, and the id of the frame it
476/// predicts from, all big-endian u16. A frame that predicts from none, or whose encoder does
477/// not say, names itself there.
478#[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
502/// Append the header of one JPEG stripe.
503pub 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
510/// The codec and frame kind a video type byte carries.
511pub 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
515/// The frame kind of a key/delta answer an encoder reports without a bitstream parse.
516pub fn frame_type_from_key(key: bool) -> u8 {
517    if key { FRAME_KEY } else { FRAME_DELTA }
518}
519
520/// Lowest H.264 level whose Annex-A Table A-1 limits admit a `width` x `height` stream at
521/// `fps` carrying up to `bitrate_bps` (0 where no rate is declared), as level_idc (41 = 4.1,
522/// 52 = 5.2, 62 = 6.2).
523///
524/// A frame is charged two ways: **MaxFS**, its size in macroblocks, and **MaxMBPS**, that
525/// size times the frame rate; a declared rate is charged against **MaxBR** at the High
526/// profile's factor of 1.25, which every session here encodes with (4:4:4 allows more), since
527/// an encoder that validates the level against the rate refuses a CBR target past it.
528/// Advertising the lowest fitting level asks the least of a decoder, so clients that gate
529/// hardware decode on the level accept the widest range of streams. One shared ladder keeps
530/// every backend agreeing on the same geometry; it starts at 4.1 and a caller needing more
531/// raises the floor itself. Above 6.2's limits there is no higher level, so it returns 62 as
532/// a best effort.
533pub 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
554/// The decoded picture buffer, in frames, an H.264 stream at `level` may declare for a
555/// `width` x `height` picture: the level's MaxDpbMbs over the picture's macroblocks, at most
556/// `REFERENCE_FRAMES`.
557pub 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/// The level an x264 session declares so its decoded picture buffer holds `REFERENCE_FRAMES`:
570/// the lowest from `level` up to 5.2 whose buffer admits them at `width` x `height`, else 5.2,
571/// or `level` itself above 5.2.
572#[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
584/// Lowest H.265 level whose Annex-A Tables A.8 and A.9 limits admit a `width` x `height`
585/// stream at `fps` carrying up to `bitrate_bps` (0 where no rate is declared) at the High
586/// tier or the Main one, as general_level_idc (123 = 4.1, 156 = 5.2, 186 = 6.2).
587///
588/// A frame is charged by **MaxLumaPs**, its luma samples, and **MaxLumaSr**, those times the
589/// frame rate; a declared rate by the tier's **MaxBR**, which an encoder that validates the
590/// level against the rate refuses a CBR target past. The ladder starts at 4.1 like the H.264
591/// one and answers 6.2 for anything beyond its limits.
592pub 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
613/// The reference frames an H.265 stream at `level` may hold for a `width` x `height`
614/// picture: the decoded picture buffer A.4.2 sizes (six pictures at the level's full
615/// MaxLumaPs, more for a smaller picture) less the picture being decoded, at most
616/// `REFERENCE_FRAMES`.
617pub 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
636/// The tier an H.265 session declares at `level` (general_level_idc): High (1) from level 4.0
637/// up, where Annex A defines one and every decoder of those levels takes it, so a CBR target
638/// above the level's Main-tier MaxBR is not refused by an encoder that validates the two
639/// together; Main (0) below, where no High tier exists.
640pub fn h265_tier(level: u32) -> u32 {
641    if level >= 120 { 1 } else { 0 }
642}
643
644/// Lowest AV1 level whose Annex A limits admit a `width` x `height` stream at `fps` carrying
645/// up to `bitrate_bps` (0 where no rate is declared), as seq_level_idx (8 = 4.0, 13 = 5.1,
646/// 19 = 6.3).
647///
648/// A frame is charged by **MaxPicSize** and the per-axis **MaxHSize** / **MaxVSize**, its
649/// rate by **MaxDisplayRate**, and a declared bitrate by the Main tier's **MaxBitrate**, the
650/// tier every hardware encoder declares, which an encoder that validates the level against
651/// the rate refuses a CBR target past. MaxPicSize is its own limit, far below the product of
652/// the axis maxima -- no level admits a picture that is both its widest and its tallest -- so
653/// it is carried per level rather than derived. The ladder starts at 4.0 and answers 6.3 for
654/// anything beyond its limits.
655pub 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
683/// Wire frame kind of one encoded H.264 access unit, read from the bitstream itself:
684/// IDR = key, intra-only non-IDR = intra, predicted = delta. The video header labels
685/// real decode entry points, so the NAL and slice types the encoder actually produced
686/// decide, never what was requested of it. An access unit whose slices cannot be parsed
687/// is labeled delta: a false delta costs one skipped entry point, a false key breaks the
688/// decoder.
689pub 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
704/// Wire frame kind of one encoded H.265 access unit: an IRAP picture (BLA, IDR, or CRA,
705/// which every backend here emits as an IDR with its parameter sets) is a key, anything
706/// else a delta.
707pub 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
717/// Whether a VP8 frame is a key frame: the frame tag's lowest bit is clear.
718pub fn vp8_is_key(frame: &[u8]) -> bool {
719    frame.first().is_some_and(|b| b & 1 == 0)
720}
721
722/// Whether a VP9 frame is a key frame, read from its uncompressed header: not a shown existing
723/// frame, and `frame_type` KEY_FRAME. Profile 3 carries one reserved bit ahead of those two.
724pub 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
740/// The `base_q_idx` of a VP9 frame, read from its uncompressed header past the color
741/// configuration, the frame size, the references, and the loop filter; None for a shown
742/// existing frame or a header cut short.
743pub 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
841/// Whether an AV1 temporal unit opens with a key frame: the first frame header or frame
842/// OBU's `frame_type`, read past any temporal delimiter and sequence header. A show
843/// existing frame, or a unit without a frame, is a delta.
844pub 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
886/// Whether a non-IDR H.264 slice header opens an I/SI slice. Reads `first_mb_in_slice`
887/// and `slice_type` (both ue(v)) from the start of the slice RBSP, undoing emulation
888/// prevention bytes; `None` when the header is truncated or malformed.
889fn 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    /// A capped CRF's refresh codes VP8 no coarser than its quantizer 2 where the session's index
941    /// is at or under the finest its table matches, at the coarsest index that reaches it, and a
942    /// refresh's steps finer elsewhere and on every other codec.
943    #[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    /// High tier exists from level 4.0 up and is declared there; the ladder never answers below
968    /// 4.1, so every level it names carries one.
969    #[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    /// Names round-trip through the parser, and the aliases land on the same codec.
978    #[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    /// Every video codec has a distinct wire id that reads back, and the type byte packs
997    /// the frame kind beside it.
998    #[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    /// Only the still-image mode stripes; every video codec is a whole-frame stream.
1057    #[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    /// The quantizer maps are monotonic, span their domain, clamp the index, and keep AV1
1069    /// off the zero NVENC refuses; H.26x takes the index as it is in software, and hardware
1070    /// H.264, and VA-API's H.265, a quantizer about three finer.
1071    #[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    /// The libvpx quantizer level found for an index is the closest table entry, at both
1118    /// ends of both tables.
1119    #[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    /// The decoded picture buffer follows the level and the picture: the reference frames a
1145    /// session asks for where the level admits them, fewer where it does not.
1146    #[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    /// The level ladders start at their floors, step through the standard limits, and
1171    /// saturate rather than fail past the top.
1172    #[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        // Both axes fit 5.x, the picture does not: MaxPicSize is not the product of the axes.
1201        assert_eq!(av1_level(8192, 4352, 60, 0), 17);
1202        assert_eq!(av1_level(8192, 4352, 240, 0), 19);
1203    }
1204
1205    /// A declared bitrate raises a level the picture alone would not: past 4.2's 62.5 Mbit/s
1206    /// (High profile) for H.264 at 1080p60, past the tier's ceiling for HEVC, past the Main
1207    /// tier's for AV1; a rate within the ceiling leaves the level where the picture put it.
1208    #[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    /// H.264 labels follow the NAL and slice types: an IDR is a key, an I slice in a
1229    /// non-IDR is intra, a P slice is delta, and a truncated slice is delta.
1230    #[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        // slice_type 7 (I, all slices) encoded ue: first_mb=0 -> '1', slice_type 7 -> '0001000'
1237        let intra = [0, 0, 1, 0x41, 0b1000_1000, 0b0000_0000];
1238        assert_eq!(h264_frame_type(&intra), FRAME_INTRA);
1239        // slice_type 0 (P): first_mb '1', slice_type '1'
1240        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    /// H.265 labels follow the NAL type: an IDR (19) or CRA (21) is a key, a TRAIL_R (1)
1247    /// picture behind parameter sets is a delta, and a stream of parameter sets alone is
1248    /// a delta.
1249    #[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    /// VP8 keys are read from the frame tag, VP9 keys from the uncompressed header in every
1262    /// profile, with a shown existing frame never a key.
1263    #[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    /// AV1 labels come from the first frame's header past the temporal delimiter and
1277    /// sequence header: frame_type 0 is a key, 1 (inter) or a shown existing frame a
1278    /// delta, and a unit that ends before a frame, or a malformed size, is a delta.
1279    #[test]
1280    fn av1_labels_from_the_temporal_unit() {
1281        // TD (type 2, has_size, size 0), SEQ (type 1, size 1), FRAME (type 6, size 2) key.
1282        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}