pixelflux/encoders/vaapi/
vp9.rs1use 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;
20const 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}