Skip to main content

pixelflux/encoders/vaapi/
vp8.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 VP8 arm: the sequence and picture parameters and the quantizer matrix; the driver
8//! writes the frame header. The three buffers, LAST, GOLDEN, and ALTREF, follow the session's
9//! slot plan, and no frame updates the entropy probabilities, so a frame a client lost leaves
10//! nothing behind that a later one depends on.
11
12use va_sys::*;
13
14use super::super::reference::SlotRefresh;
15use super::{Buffers, Frame, Negotiated};
16
17const LOOP_FILTER_LEVEL: i8 = 16;
18const SHARPNESS: u8 = 4;
19
20pub(super) struct Arm {
21    sequence: VAEncSequenceParameterBufferVP8,
22}
23
24impl Arm {
25    pub(super) fn new() -> Self {
26        Self {
27            sequence: unsafe { std::mem::zeroed() },
28        }
29    }
30
31    pub(super) fn configure(&mut self, n: &Negotiated) {
32        let s = &mut self.sequence;
33        *s = unsafe { std::mem::zeroed() };
34        s.frame_width = n.width;
35        s.frame_height = n.height;
36        s.error_resilient = 0;
37        s.kf_auto = 0;
38        if n.rc_mode != VA_RC_CQP {
39            s.bits_per_second = n.bits_per_second;
40            s.intra_period = i32::MAX as u32;
41        }
42    }
43
44    pub(super) fn sequence(&mut self, _n: &Negotiated, out: &mut Buffers) {
45        out.push(VAEncSequenceParameterBufferType, &self.sequence);
46    }
47
48    pub(super) fn picture(
49        &mut self,
50        n: &Negotiated,
51        frame: &Frame,
52        out: &mut Buffers,
53    ) -> Result<(), String> {
54        let plan = frame.slots;
55        let mut pic: VAEncPictureParameterBufferVP8 = unsafe { std::mem::zeroed() };
56        pic.reconstructed_frame = frame.recon;
57        pic.coded_buf = frame.coded;
58        if frame.key {
59            pic.ref_last_frame = VA_INVALID_SURFACE;
60            pic.ref_gf_frame = VA_INVALID_SURFACE;
61            pic.ref_arf_frame = VA_INVALID_SURFACE;
62        } else {
63            if plan.predict_from == 0 {
64                return Err("a predicted VP8 picture without a reference".into());
65            }
66            pic.ref_last_frame = frame.slot_surfaces[0];
67            pic.ref_gf_frame = frame.slot_surfaces[1];
68            pic.ref_arf_frame = frame.slot_surfaces[2];
69        }
70        unsafe {
71            let r = &mut pic.ref_flags.bits;
72            r.set_force_kf(u32::from(frame.key));
73            r.set_no_ref_last(u32::from(plan.predict_from != SlotRefresh::LAST));
74            r.set_no_ref_gf(u32::from(plan.predict_from != SlotRefresh::GOLDEN));
75            r.set_no_ref_arf(u32::from(plan.predict_from != SlotRefresh::ALTREF));
76            let p = &mut pic.pic_flags.bits;
77            p.set_frame_type(u32::from(!frame.key));
78            p.set_show_frame(1);
79            p.set_refresh_entropy_probs(0);
80            p.set_refresh_last(u32::from(plan.refresh.refreshes(SlotRefresh::LAST)));
81            p.set_refresh_golden_frame(u32::from(plan.refresh.refreshes(SlotRefresh::GOLDEN)));
82            p.set_refresh_alternate_frame(u32::from(plan.refresh.refreshes(SlotRefresh::ALTREF)));
83        }
84        pic.loop_filter_level = [LOOP_FILTER_LEVEL; 4];
85        pic.sharpness_level = SHARPNESS;
86        pic.clamp_qindex_low = 0;
87        pic.clamp_qindex_high = 127;
88        out.push(VAEncPictureParameterBufferType, &pic);
89
90        let q = if n.rc_mode == VA_RC_CQP {
91            frame.qp.min(127) as u16
92        } else {
93            0
94        };
95        let mut quant: VAQMatrixBufferVP8 = unsafe { std::mem::zeroed() };
96        quant.quantization_index = [q; 4];
97        out.push(VAQMatrixBufferType, &quant);
98        Ok(())
99    }
100}