blob: f29f7ab104846d4729c284db9082e06b6f229afb [file] [log] [blame]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::codec::h264::parser::Pps;
use crate::codec::h264::parser::SliceHeader;
use crate::codec::h264::parser::Sps;
use crate::codec::h264::picture::Field;
use crate::codec::h264::picture::IsIdr;
use crate::codec::h264::picture::PictureData;
use crate::codec::h264::picture::RcPictureData;
use crate::codec::h264::picture::Reference;
use v4l2r::bindings::v4l2_ctrl_h264_decode_params;
use v4l2r::bindings::v4l2_ctrl_h264_pps;
use v4l2r::bindings::v4l2_ctrl_h264_scaling_matrix;
use v4l2r::bindings::v4l2_ctrl_h264_sps;
use v4l2r::bindings::v4l2_h264_dpb_entry;
use v4l2r::bindings::v4l2_stateless_h264_decode_mode_V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED as V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED;
use v4l2r::bindings::v4l2_stateless_h264_decode_mode_V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED as V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED;
use v4l2r::bindings::V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD;
use v4l2r::bindings::V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC;
use v4l2r::bindings::V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC;
use v4l2r::bindings::V4L2_H264_DPB_ENTRY_FLAG_ACTIVE;
use v4l2r::bindings::V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM;
use v4l2r::bindings::V4L2_H264_DPB_ENTRY_FLAG_VALID;
use v4l2r::bindings::V4L2_H264_FRAME_REF;
use v4l2r::bindings::V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT;
use v4l2r::bindings::V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED;
use v4l2r::bindings::V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT;
use v4l2r::bindings::V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE;
use v4l2r::bindings::V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT;
use v4l2r::bindings::V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT;
use v4l2r::bindings::V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE;
use v4l2r::bindings::V4L2_H264_PPS_FLAG_WEIGHTED_PRED;
use v4l2r::bindings::V4L2_H264_SPS_CONSTRAINT_SET0_FLAG;
use v4l2r::bindings::V4L2_H264_SPS_CONSTRAINT_SET1_FLAG;
use v4l2r::bindings::V4L2_H264_SPS_CONSTRAINT_SET2_FLAG;
use v4l2r::bindings::V4L2_H264_SPS_CONSTRAINT_SET3_FLAG;
use v4l2r::bindings::V4L2_H264_SPS_CONSTRAINT_SET4_FLAG;
use v4l2r::bindings::V4L2_H264_SPS_CONSTRAINT_SET5_FLAG;
use v4l2r::bindings::V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO;
use v4l2r::bindings::V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE;
use v4l2r::bindings::V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY;
use v4l2r::bindings::V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED;
use v4l2r::bindings::V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD;
use v4l2r::bindings::V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS;
use v4l2r::bindings::V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
use v4l2r::controls::codec::H264DecodeMode;
use v4l2r::controls::codec::H264DecodeParams;
use v4l2r::controls::codec::H264ScalingMatrix;
use v4l2r::controls::SafeExtControl;
impl From<&Sps> for v4l2_ctrl_h264_sps {
fn from(sps: &Sps) -> Self {
let mut constraint_set_flags: u32 = 0;
if sps.constraint_set0_flag {
constraint_set_flags |= V4L2_H264_SPS_CONSTRAINT_SET0_FLAG;
}
if sps.constraint_set1_flag {
constraint_set_flags |= V4L2_H264_SPS_CONSTRAINT_SET1_FLAG;
}
if sps.constraint_set2_flag {
constraint_set_flags |= V4L2_H264_SPS_CONSTRAINT_SET2_FLAG;
}
if sps.constraint_set3_flag {
constraint_set_flags |= V4L2_H264_SPS_CONSTRAINT_SET3_FLAG;
}
if sps.constraint_set4_flag {
constraint_set_flags |= V4L2_H264_SPS_CONSTRAINT_SET4_FLAG;
}
if sps.constraint_set5_flag {
constraint_set_flags |= V4L2_H264_SPS_CONSTRAINT_SET5_FLAG;
}
let mut flags: u32 = 0;
if sps.separate_colour_plane_flag {
flags |= V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
}
if sps.qpprime_y_zero_transform_bypass_flag {
flags |= V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS;
}
if sps.delta_pic_order_always_zero_flag {
flags |= V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO;
}
if sps.gaps_in_frame_num_value_allowed_flag {
flags |= V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED;
}
if sps.frame_mbs_only_flag {
flags |= V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY;
}
if sps.mb_adaptive_frame_field_flag {
flags |= V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD;
}
if sps.direct_8x8_inference_flag {
flags |= V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE;
}
Self {
profile_idc: sps.profile_idc,
constraint_set_flags: constraint_set_flags as u8,
level_idc: sps.level_idc as u8,
seq_parameter_set_id: sps.seq_parameter_set_id,
chroma_format_idc: sps.chroma_format_idc,
bit_depth_luma_minus8: sps.bit_depth_luma_minus8,
bit_depth_chroma_minus8: sps.bit_depth_chroma_minus8,
log2_max_frame_num_minus4: sps.log2_max_frame_num_minus4,
pic_order_cnt_type: sps.pic_order_cnt_type,
log2_max_pic_order_cnt_lsb_minus4: sps.log2_max_pic_order_cnt_lsb_minus4,
max_num_ref_frames: sps.max_num_ref_frames as u8,
num_ref_frames_in_pic_order_cnt_cycle: sps.num_ref_frames_in_pic_order_cnt_cycle,
offset_for_ref_frame: sps.offset_for_ref_frame,
offset_for_non_ref_pic: sps.offset_for_non_ref_pic,
offset_for_top_to_bottom_field: sps.offset_for_top_to_bottom_field,
pic_width_in_mbs_minus1: sps.pic_width_in_mbs_minus1 as u16,
pic_height_in_map_units_minus1: sps.pic_height_in_map_units_minus1 as u16,
flags,
..Default::default()
}
}
}
impl From<&Pps> for v4l2_ctrl_h264_pps {
fn from(pps: &Pps) -> Self {
let mut flags: u32 = 0;
if pps.entropy_coding_mode_flag {
flags |= V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE;
}
if pps.bottom_field_pic_order_in_frame_present_flag {
flags |= V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT;
}
if pps.weighted_pred_flag {
flags |= V4L2_H264_PPS_FLAG_WEIGHTED_PRED;
}
if pps.deblocking_filter_control_present_flag {
flags |= V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT;
}
if pps.constrained_intra_pred_flag {
flags |= V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED;
}
if pps.redundant_pic_cnt_present_flag {
flags |= V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT;
}
if pps.transform_8x8_mode_flag {
flags |= V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE;
}
if pps.pic_scaling_matrix_present_flag {
flags |= V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT;
}
Self {
pic_parameter_set_id: pps.pic_parameter_set_id,
seq_parameter_set_id: pps.seq_parameter_set_id,
num_slice_groups_minus1: pps.num_slice_groups_minus1 as u8,
num_ref_idx_l0_default_active_minus1: pps.num_ref_idx_l0_default_active_minus1,
num_ref_idx_l1_default_active_minus1: pps.num_ref_idx_l1_default_active_minus1,
weighted_bipred_idc: pps.weighted_bipred_idc,
pic_init_qp_minus26: pps.pic_init_qp_minus26,
pic_init_qs_minus26: pps.pic_init_qs_minus26,
chroma_qp_index_offset: pps.chroma_qp_index_offset,
second_chroma_qp_index_offset: pps.second_chroma_qp_index_offset,
flags: flags as u16,
..Default::default()
}
}
}
pub struct V4l2CtrlH264DpbEntry {
pub timestamp: u64,
pub pic: RcPictureData,
}
impl From<&V4l2CtrlH264DpbEntry> for v4l2_h264_dpb_entry {
fn from(dpb: &V4l2CtrlH264DpbEntry) -> Self {
let pic: &PictureData = &dpb.pic.borrow();
// TODO DCHECK_EQ(pic->field, H264Picture::FIELD_NONE)
// TODO << "Interlacing not supported";
let (frame_num, pic_num): (u16, u32) = match pic.reference() {
Reference::LongTerm => (pic.long_term_pic_num as u16, pic.long_term_frame_idx),
_ => (pic.frame_num as u16, pic.pic_num as u32),
};
let mut flags: u32 = V4L2_H264_DPB_ENTRY_FLAG_VALID;
if pic.nal_ref_idc != 0 {
flags |= V4L2_H264_DPB_ENTRY_FLAG_ACTIVE;
}
if matches!(pic.reference(), Reference::LongTerm) {
flags |= V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM;
}
Self {
reference_ts: dpb.timestamp * 1000, // usec to nsec
frame_num,
pic_num,
fields: V4L2_H264_FRAME_REF as u8,
top_field_order_cnt: pic.top_field_order_cnt,
bottom_field_order_cnt: pic.bottom_field_order_cnt,
flags,
..Default::default()
}
}
}
#[derive(Default)]
pub struct V4l2CtrlH264ScalingMatrix {
handle: v4l2_ctrl_h264_scaling_matrix,
}
impl V4l2CtrlH264ScalingMatrix {
pub fn new() -> Self {
Default::default()
}
pub fn set(&mut self) -> &mut Self {
todo!()
}
}
impl From<&V4l2CtrlH264ScalingMatrix> for SafeExtControl<H264ScalingMatrix> {
fn from(scaling_matrix: &V4l2CtrlH264ScalingMatrix) -> Self {
SafeExtControl::<H264ScalingMatrix>::from(scaling_matrix.handle)
}
}
#[derive(Default)]
pub struct V4l2CtrlH264DecodeParams {
handle: v4l2_ctrl_h264_decode_params,
}
impl V4l2CtrlH264DecodeParams {
pub fn new() -> Self {
Default::default()
}
pub fn set_picture_data(&mut self, pic: &PictureData) -> &mut Self {
self.handle.top_field_order_cnt = pic.top_field_order_cnt;
self.handle.bottom_field_order_cnt = pic.bottom_field_order_cnt;
self.handle.flags |= match pic.field {
Field::Top => V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC,
Field::Bottom => {
V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC | V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD
}
_ => 0,
};
self.handle.flags |= match pic.is_idr {
IsIdr::Yes { idr_pic_id: _ } => V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC,
_ => 0,
};
self.handle.nal_ref_idc = pic.nal_ref_idc as u16;
self
}
pub fn set_dpb_entries(&mut self, dpb: Vec<V4l2CtrlH264DpbEntry>) -> &mut Self {
for i in 0..dpb.len() {
self.handle.dpb[i] = v4l2_h264_dpb_entry::from(&dpb[i]);
}
self
}
pub fn set_slice_header(&mut self, slice_header: &SliceHeader) -> &mut Self {
self.handle.frame_num = slice_header.frame_num;
self.handle.idr_pic_id = slice_header.idr_pic_id;
self.handle.pic_order_cnt_lsb = slice_header.pic_order_cnt_lsb;
self.handle.delta_pic_order_cnt_bottom = slice_header.delta_pic_order_cnt_bottom;
self.handle.delta_pic_order_cnt0 = slice_header.delta_pic_order_cnt[0];
self.handle.delta_pic_order_cnt1 = slice_header.delta_pic_order_cnt[1];
self.handle.dec_ref_pic_marking_bit_size = slice_header.dec_ref_pic_marking_bit_size as u32;
self.handle.pic_order_cnt_bit_size = slice_header.pic_order_cnt_bit_size as u32;
self
}
}
impl From<&V4l2CtrlH264DecodeParams> for SafeExtControl<H264DecodeParams> {
fn from(decode_params: &V4l2CtrlH264DecodeParams) -> Self {
SafeExtControl::<H264DecodeParams>::from(decode_params.handle)
}
}
pub enum V4l2CtrlH264DecodeMode {
SliceBased = V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED as isize,
FrameBased = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED as isize,
}
impl From<V4l2CtrlH264DecodeMode> for SafeExtControl<H264DecodeMode> {
fn from(decode_mode: V4l2CtrlH264DecodeMode) -> Self {
SafeExtControl::<H264DecodeMode>::from_value(decode_mode as i32)
}
}