Skip to main content

pixelflux/encoders/vaapi/
vp9.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//! The VP9 arm: the sequence and picture parameters; the driver writes the uncompressed
8//! header. The eight buffer slots hold the last eight frames by timestamp, a frame refreshes
9//! its own and predicts from the slot of the newest frame the client still has, and every
10//! frame is coded in the error-resilient mode, since a decoder otherwise takes the previous
11//! frame's motion vectors and probability contexts whatever the reference says.
12
13use va_sys::*;
14
15use super::super::reference::REFERENCE_FRAMES;
16use super::{Buffers, Frame, Negotiated};
17
18const LOOP_FILTER_LEVEL: u8 = 16;
19const SHARPNESS: u8 = 4;
20/// The widest tile the codec allows, which sets the fewest tile columns a picture needs.
21const MAX_TILE_WIDTH: u32 = 4096;
22
23pub(super) struct Arm {
24    sequence: VAEncSequenceParameterBufferVP9,
25    log2_tile_columns: u8,
26}
27
28impl Arm {
29    pub(super) fn new() -> Self {
30        Self {
31            sequence: unsafe { std::mem::zeroed() },
32            log2_tile_columns: 0,
33        }
34    }
35
36    pub(super) fn configure(&mut self, n: &Negotiated) {
37        let s = &mut self.sequence;
38        *s = unsafe { std::mem::zeroed() };
39        s.max_frame_width = n.width;
40        s.max_frame_height = n.height;
41        s.kf_auto = 0;
42        if n.rc_mode != VA_RC_CQP {
43            s.bits_per_second = n.bits_per_second;
44            s.intra_period = i32::MAX as u32;
45        }
46        let columns = n.width.div_ceil(MAX_TILE_WIDTH);
47        self.log2_tile_columns = if columns <= 1 {
48            0
49        } else {
50            (32 - (columns - 1).leading_zeros()) as u8
51        };
52    }
53
54    pub(super) fn sequence(&mut self, _n: &Negotiated, out: &mut Buffers) {
55        out.push(VAEncSequenceParameterBufferType, &self.sequence);
56    }
57
58    pub(super) fn picture(
59        &mut self,
60        n: &Negotiated,
61        frame: &Frame,
62        out: &mut Buffers,
63    ) -> Result<(), String> {
64        let slot_of = |pts: u64| (pts % u64::from(REFERENCE_FRAMES)) as u8;
65        let mut pic: VAEncPictureParameterBufferVP9 = unsafe { std::mem::zeroed() };
66        pic.frame_width_src = n.width;
67        pic.frame_height_src = n.height;
68        pic.frame_width_dst = n.width;
69        pic.frame_height_dst = n.height;
70        pic.reconstructed_frame = frame.recon;
71        pic.coded_buf = frame.coded;
72        pic.reference_frames = [VA_INVALID_SURFACE; 8];
73        for &(pts, surface, _) in frame.held {
74            if !frame.key && pts >= frame.key_pts {
75                pic.reference_frames[slot_of(pts) as usize] = surface;
76            }
77        }
78        pic.log2_tile_columns = self.log2_tile_columns;
79        unsafe {
80            let r = &mut pic.ref_flags.bits;
81            if frame.key {
82                r.set_force_kf(1);
83                pic.refresh_frame_flags = 0xff;
84            } else {
85                let (ref_pts, _) = frame
86                    .reference
87                    .ok_or("a predicted VP9 picture without a reference")?;
88                let slot = u32::from(slot_of(ref_pts));
89                r.set_ref_frame_ctrl_l0(1);
90                r.set_ref_last_idx(slot);
91                r.set_ref_last_sign_bias(1);
92                r.set_ref_gf_idx(slot);
93                r.set_ref_arf_idx(slot);
94                pic.refresh_frame_flags = 1 << slot_of(frame.pts);
95            }
96            let p = &mut pic.pic_flags.bits;
97            p.set_frame_type(u32::from(!frame.key));
98            p.set_show_frame(1);
99            p.set_error_resilient_mode(1);
100        }
101        pic.luma_ac_qindex = if n.rc_mode == VA_RC_CQP {
102            frame.qp.min(255) as u8
103        } else {
104            100
105        };
106        pic.filter_level = LOOP_FILTER_LEVEL;
107        pic.sharpness_level = SHARPNESS;
108        out.push(VAEncPictureParameterBufferType, &pic);
109        Ok(())
110    }
111}