#![forbid(unsafe_code)]
use super::av1_frame_header::FrameHeader;
use super::av1_sequence_header::SequenceHeader;
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub(super) struct DxvaPicEntryAv1 {
pub(super) width: u32,
pub(super) height: u32,
pub(super) wmmat: [i32; 6],
pub(super) global_motion_flags: u8,
pub(super) index: u8,
pub(super) reserved16_bits: u16,
}
impl DxvaPicEntryAv1 {
pub(super) const UNUSED: Self = Self {
width: 0,
height: 0,
wmmat: [0; 6],
global_motion_flags: 0,
index: 0xFF,
reserved16_bits: 0,
};
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub(super) struct DxvaTileAv1 {
pub(super) data_offset: u32,
pub(super) data_size: u32,
pub(super) row: u16,
pub(super) column: u16,
pub(super) reserved16_bits: u16,
pub(super) anchor_frame: u8,
pub(super) reserved8_bits: u8,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub(super) struct DxvaTilesAv1 {
pub(super) cols: u8,
pub(super) rows: u8,
pub(super) context_update_id: u16,
pub(super) widths: [u16; 64],
pub(super) heights: [u16; 64],
}
impl Default for DxvaTilesAv1 {
fn default() -> Self {
Self {
cols: 0,
rows: 0,
context_update_id: 0,
widths: [0u16; 64],
heights: [0u16; 64],
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub(super) struct DxvaLoopFilterAv1 {
pub(super) filter_level: [u8; 2],
pub(super) filter_level_u: u8,
pub(super) filter_level_v: u8,
pub(super) sharpness_level: u8,
pub(super) control_flags: u8,
pub(super) ref_deltas: [i8; 8],
pub(super) mode_deltas: [i8; 2],
pub(super) delta_lf_res: u8,
pub(super) frame_restoration_type: [u8; 3],
pub(super) log2_restoration_unit_size: [u16; 3],
pub(super) reserved16_bits: u16,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub(super) struct DxvaQuantizationAv1 {
pub(super) control_flags: u8,
pub(super) base_qindex: u8,
pub(super) y_dc_delta_q: i8,
pub(super) u_dc_delta_q: i8,
pub(super) v_dc_delta_q: i8,
pub(super) u_ac_delta_q: i8,
pub(super) v_ac_delta_q: i8,
pub(super) qm_y: u8,
pub(super) qm_u: u8,
pub(super) qm_v: u8,
pub(super) reserved16_bits: u16,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub(super) struct DxvaCdefAv1 {
pub(super) control_flags: u8,
pub(super) y_strengths: [u8; 8],
pub(super) uv_strengths: [u8; 8],
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub(super) struct DxvaSegmentationAv1 {
pub(super) control_flags: u8,
pub(super) reserved24_bits: [u8; 3],
pub(super) feature_mask: [u8; 8],
pub(super) feature_data: [[i16; 8]; 8],
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub(super) struct DxvaFilmGrainAv1 {
pub(super) control_flags: u16,
pub(super) grain_seed: u16,
pub(super) scaling_points_y: [[u8; 2]; 14],
pub(super) num_y_points: u8,
pub(super) scaling_points_cb: [[u8; 2]; 10],
pub(super) num_cb_points: u8,
pub(super) scaling_points_cr: [[u8; 2]; 10],
pub(super) num_cr_points: u8,
pub(super) ar_coeffs_y: [u8; 24],
pub(super) ar_coeffs_cb: [u8; 25],
pub(super) ar_coeffs_cr: [u8; 25],
pub(super) cb_mult: u8,
pub(super) cb_luma_mult: u8,
pub(super) cr_mult: u8,
pub(super) cr_luma_mult: u8,
pub(super) reserved8_bits: u8,
pub(super) cb_offset: i16,
pub(super) cr_offset: i16,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub(super) struct DxvaPicParamsAv1 {
pub(super) width: u32,
pub(super) height: u32,
pub(super) max_width: u32,
pub(super) max_height: u32,
pub(super) curr_pic_texture_index: u8,
pub(super) superres_denom: u8,
pub(super) bitdepth: u8,
pub(super) seq_profile: u8,
pub(super) tiles: DxvaTilesAv1,
pub(super) coding_param_tool_flags: u32,
pub(super) format_and_picture_info_flags: u8,
pub(super) primary_ref_frame: u8,
pub(super) order_hint: u8,
pub(super) order_hint_bits: u8,
pub(super) frame_refs: [DxvaPicEntryAv1; 7],
pub(super) ref_frame_map_texture_index: [u8; 8],
pub(super) loop_filter: DxvaLoopFilterAv1,
pub(super) quantization: DxvaQuantizationAv1,
pub(super) cdef: DxvaCdefAv1,
pub(super) interp_filter: u8,
pub(super) segmentation: DxvaSegmentationAv1,
pub(super) film_grain: DxvaFilmGrainAv1,
pub(super) reserved32_bits: u32,
pub(super) status_report_feedback_number: u32,
}
const SUPERRES_NUM: u8 = 8;
const PRIMARY_REF_NONE: u8 = 7;
const TOTAL_REFS_PER_FRAME: usize = 8;
const FORCE_INTEGER_MV_INTRA: bool = true;
#[allow(
clippy::too_many_arguments,
clippy::fn_params_excessive_bools,
reason = "mirrors the DXVA bitfield layout 1:1 — each bool is one independent \
bitfield, not a state machine, same reasoning h264_pic_params.rs's pack_bit_fields gives"
)]
fn pack_coding_param_tool_flags(
use_128x128_superblock: bool,
intra_edge_filter: bool,
interintra_compound: bool,
masked_compound: bool,
dual_filter: bool,
jnt_comp: bool,
disable_frame_end_update_cdf: bool,
disable_cdf_update: bool,
reduced_tx_set: bool,
tx_mode: u8,
enable_ref_frame_mvs: bool,
filter_intra: bool,
) -> u32 {
u32::from(use_128x128_superblock)
| (u32::from(intra_edge_filter) << 1)
| (u32::from(interintra_compound) << 2)
| (u32::from(masked_compound) << 3)
| (u32::from(dual_filter) << 5)
| (u32::from(jnt_comp) << 6)
| (u32::from(FORCE_INTEGER_MV_INTRA) << 8)
| (u32::from(filter_intra) << 15)
| (u32::from(disable_frame_end_update_cdf) << 16)
| (u32::from(disable_cdf_update) << 17)
| (u32::from(reduced_tx_set) << 20)
| (u32::from(tx_mode & 0b11) << 22)
| (u32::from(enable_ref_frame_mvs) << 25)
| (1 << 26) }
const fn pack_format_and_picture_info_flags() -> u8 {
0b0011_0100 }
#[allow(
clippy::too_many_lines,
reason = "one linear DXVA struct fill, mirrors hevc_pic_params.rs::build_pic_params's identical shape"
)]
pub(super) fn build_pic_params(
seq: &SequenceHeader,
fh: &FrameHeader,
output_slot: u32,
status_report_feedback_number: u32,
) -> DxvaPicParamsAv1 {
let coding_param_tool_flags = pack_coding_param_tool_flags(
seq.use_128x128_superblock,
seq.enable_intra_edge_filter,
seq.enable_interintra_compound,
seq.enable_masked_compound,
seq.enable_dual_filter,
seq.enable_jnt_comp,
fh.disable_frame_end_update_cdf,
fh.disable_cdf_update,
fh.reduced_tx_set,
fh.tx_mode,
seq.enable_ref_frame_mvs,
seq.enable_filter_intra,
);
let loop_filter_control_flags = u8::from(fh.loop_filter.delta_enabled)
| (u8::from(fh.loop_filter.delta_update) << 1)
| (u8::from(fh.delta_lf_multi) << 2)
| (u8::from(fh.delta_lf_present) << 3);
let mut ref_deltas = [0i8; TOTAL_REFS_PER_FRAME];
for (dst, &src) in ref_deltas.iter_mut().zip(fh.loop_filter.ref_deltas.iter()) {
*dst = i8::try_from(src).unwrap_or(0);
}
let mut mode_deltas = [0i8; 2];
for (dst, &src) in mode_deltas
.iter_mut()
.zip(fh.loop_filter.mode_deltas.iter())
{
*dst = i8::try_from(src).unwrap_or(0);
}
let loop_filter = DxvaLoopFilterAv1 {
filter_level: [
u8::try_from(fh.loop_filter.level[0]).unwrap_or(0),
u8::try_from(fh.loop_filter.level[1]).unwrap_or(0),
],
filter_level_u: u8::try_from(fh.loop_filter.level_u).unwrap_or(0),
filter_level_v: u8::try_from(fh.loop_filter.level_v).unwrap_or(0),
sharpness_level: u8::try_from(fh.loop_filter.sharpness).unwrap_or(0),
control_flags: loop_filter_control_flags,
ref_deltas,
mode_deltas,
delta_lf_res: u8::try_from(fh.delta_lf_res).unwrap_or(0),
frame_restoration_type: [0u8; 3],
log2_restoration_unit_size: [0u16; 3],
reserved16_bits: 0,
};
let quantization_control_flags =
u8::from(fh.delta_q_present) | (u8::try_from(fh.delta_q_res & 0b11).unwrap_or(0) << 1);
let quantization = DxvaQuantizationAv1 {
control_flags: quantization_control_flags,
base_qindex: u8::try_from(fh.quantization.base_q_idx).unwrap_or(0),
y_dc_delta_q: i8::try_from(fh.quantization.delta_q_y_dc).unwrap_or(0),
u_dc_delta_q: i8::try_from(fh.quantization.delta_q_u_dc).unwrap_or(0),
v_dc_delta_q: i8::try_from(fh.quantization.delta_q_v_dc).unwrap_or(0),
u_ac_delta_q: i8::try_from(fh.quantization.delta_q_u_ac).unwrap_or(0),
v_ac_delta_q: i8::try_from(fh.quantization.delta_q_v_ac).unwrap_or(0),
qm_y: 0xFF,
qm_u: 0xFF,
qm_v: 0xFF,
reserved16_bits: 0,
};
let mut tiles = DxvaTilesAv1 {
cols: 1,
rows: 1,
context_update_id: 0,
..DxvaTilesAv1::default()
};
tiles.widths[0] = u16::try_from(fh.tile.tile_width_sb).unwrap_or(u16::MAX);
tiles.heights[0] = u16::try_from(fh.tile.tile_height_sb).unwrap_or(u16::MAX);
DxvaPicParamsAv1 {
width: fh.width,
height: fh.height,
max_width: seq.max_frame_width,
max_height: seq.max_frame_height,
curr_pic_texture_index: u8::try_from(output_slot).unwrap_or(0),
superres_denom: SUPERRES_NUM,
bitdepth: 8,
seq_profile: 0,
tiles,
coding_param_tool_flags,
format_and_picture_info_flags: pack_format_and_picture_info_flags(),
primary_ref_frame: PRIMARY_REF_NONE,
order_hint: u8::try_from(fh.order_hint).unwrap_or(0),
order_hint_bits: u8::try_from(seq.order_hint_bits).unwrap_or(0),
frame_refs: [DxvaPicEntryAv1::UNUSED; 7],
ref_frame_map_texture_index: [0xFFu8; TOTAL_REFS_PER_FRAME],
loop_filter,
quantization,
cdef: DxvaCdefAv1::default(),
interp_filter: 0,
segmentation: DxvaSegmentationAv1::default(),
film_grain: DxvaFilmGrainAv1::default(),
reserved32_bits: 0,
status_report_feedback_number,
}
}
pub(super) const fn build_tile(data_offset: u32, data_size: u32) -> DxvaTileAv1 {
DxvaTileAv1 {
data_offset,
data_size,
row: 0,
column: 0,
reserved16_bits: 0,
anchor_frame: 0xFF,
reserved8_bits: 0,
}
}
#[cfg(test)]
#[path = "av1_pic_params_tests.rs"]
mod tests;