// 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 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_stateless_h264_start_code_V4L2_STATELESS_H264_START_CODE_ANNEX_B as V4L2_STATELESS_H264_START_CODE_ANNEX_B; use v4l2r::bindings::v4l2_stateless_h264_start_code_V4L2_STATELESS_H264_START_CODE_NONE as V4L2_STATELESS_H264_START_CODE_NONE; 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::H264StartCode; use v4l2r::controls::SafeExtControl; 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 crate::decoder::stateless::h264::get_raster_from_zigzag_4x4; use crate::decoder::stateless::h264::get_raster_from_zigzag_8x8; 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() } } } impl From<&Pps> for v4l2_ctrl_h264_scaling_matrix { fn from(pps: &Pps) -> Self { let mut scaling_list_4x4 = [[0; 16]; 6]; let mut scaling_list_8x8 = [[0; 64]; 6]; (0..6).for_each(|i| { get_raster_from_zigzag_4x4(pps.scaling_lists_4x4[i], &mut scaling_list_4x4[i]); }); (0..2).for_each(|i| { get_raster_from_zigzag_8x8(pps.scaling_lists_8x8[i], &mut scaling_list_8x8[i]); }); Self { scaling_list_4x4, scaling_list_8x8 } } } 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 matches!(pic.reference(), Reference::LongTerm | Reference::ShortTerm) { 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 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) -> &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 { fn from(decode_params: &V4l2CtrlH264DecodeParams) -> Self { SafeExtControl::::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 for SafeExtControl { fn from(decode_mode: V4l2CtrlH264DecodeMode) -> Self { SafeExtControl::::from_value(decode_mode as i32) } } impl From for SafeExtControl { fn from(decode_mode: V4l2CtrlH264StartCode) -> Self { SafeExtControl::::from_value(decode_mode as i32) } } pub enum V4l2CtrlH264StartCode { None = V4L2_STATELESS_H264_START_CODE_NONE as isize, AnnexB = V4L2_STATELESS_H264_START_CODE_ANNEX_B as isize, }