1 // Copyright 2024 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::rc::Rc; 6 7 use log::trace; 8 9 use crate::codec::h264::parser::Level; 10 use crate::codec::h264::parser::Pps; 11 use crate::codec::h264::parser::PpsBuilder; 12 use crate::codec::h264::parser::Profile; 13 use crate::codec::h264::parser::SliceHeaderBuilder; 14 use crate::codec::h264::parser::SliceType; 15 use crate::codec::h264::parser::Sps; 16 use crate::codec::h264::parser::SpsBuilder; 17 use crate::codec::h264::synthesizer::Synthesizer; 18 use crate::encoder::stateless::h264::BackendRequest; 19 use crate::encoder::stateless::h264::DpbEntry; 20 use crate::encoder::stateless::h264::DpbEntryMeta; 21 use crate::encoder::stateless::h264::EncoderConfig; 22 use crate::encoder::stateless::h264::IsReference; 23 use crate::encoder::stateless::predictor::LowDelay; 24 use crate::encoder::stateless::predictor::LowDelayDelegate; 25 use crate::encoder::stateless::FrameMetadata; 26 use crate::encoder::EncodeError; 27 use crate::encoder::EncodeResult; 28 use crate::encoder::RateControl; 29 use crate::encoder::Tunings; 30 31 pub(crate) const MIN_QP: u8 = 1; 32 pub(crate) const MAX_QP: u8 = 51; 33 34 pub(crate) struct LowDelayH264Delegate { 35 /// Current sequence SPS 36 sps: Option<Rc<Sps>>, 37 /// Current sequence PPS 38 pps: Option<Rc<Pps>>, 39 40 // True if SPS or PPS changed and should reappear in the bitstream 41 update_params_sets: bool, 42 43 /// Encoder config 44 config: EncoderConfig, 45 } 46 47 pub(crate) type LowDelayH264<Picture, Reference> = LowDelay< 48 Picture, 49 DpbEntry<Reference>, 50 LowDelayH264Delegate, 51 BackendRequest<Picture, Reference>, 52 >; 53 54 impl<Picture, Reference> LowDelayH264<Picture, Reference> { new(config: EncoderConfig, limit: u16) -> Self55 pub(super) fn new(config: EncoderConfig, limit: u16) -> Self { 56 Self { 57 queue: Default::default(), 58 references: Default::default(), 59 counter: 0, 60 limit, 61 tunings: config.initial_tunings.clone(), 62 delegate: LowDelayH264Delegate { 63 config, 64 update_params_sets: false, 65 sps: None, 66 pps: None, 67 }, 68 tunings_queue: Default::default(), 69 _phantom: Default::default(), 70 } 71 } 72 new_sequence(&mut self)73 fn new_sequence(&mut self) { 74 trace!("beginning new sequence"); 75 let config = &self.delegate.config; 76 77 let mut sps = SpsBuilder::new().seq_parameter_set_id(0).profile_idc(config.profile); 78 79 // H.264 Table 6-1 80 sps = match config.profile { 81 // 4:2:2 subsampling 82 Profile::High422P => sps.chroma_format_idc(2), 83 // 4:2:0 subsampling 84 _ => sps.chroma_format_idc(1), 85 }; 86 87 let sps = sps 88 .level_idc(config.level) 89 .max_frame_num(self.limit as u32) 90 .pic_order_cnt_type(0) 91 .max_pic_order_cnt_lsb(self.limit as u32 * 2) 92 .max_num_ref_frames(1) 93 .frame_mbs_only_flag(true) 94 // H264 spec Table A-4 95 .direct_8x8_inference_flag(config.level >= Level::L3) 96 .resolution(config.resolution.width, config.resolution.height) 97 .bit_depth_luma(8) 98 .bit_depth_chroma(8) 99 .aspect_ratio(1, 1) 100 .timing_info(1, self.tunings.framerate * 2, false) 101 .build(); 102 103 let min_qp = self.tunings.min_quality.max(MIN_QP as u32); 104 let max_qp = self.tunings.max_quality.min(MAX_QP as u32); 105 106 let init_qp = if let RateControl::ConstantQuality(init_qp) = self.tunings.rate_control { 107 // Limit QP to valid values 108 init_qp.clamp(min_qp, max_qp) as u8 109 } else { 110 // Pick middle QP for default qp 111 ((min_qp + max_qp) / 2) as u8 112 }; 113 114 let pps = PpsBuilder::new(Rc::clone(&sps)) 115 .pic_parameter_set_id(0) 116 .pic_init_qp(init_qp) 117 .deblocking_filter_control_present_flag(true) 118 .num_ref_idx_l0_default_active(1) 119 // Unused, P frame relies only on list0 120 .num_ref_idx_l1_default_active_minus1(0) 121 .build(); 122 123 self.delegate.sps = Some(sps); 124 self.delegate.pps = Some(pps); 125 self.delegate.update_params_sets = true; 126 } 127 } 128 129 impl<Picture, Reference> 130 LowDelayDelegate<Picture, DpbEntry<Reference>, BackendRequest<Picture, Reference>> 131 for LowDelayH264<Picture, Reference> 132 { request_keyframe( &mut self, input: Picture, input_meta: FrameMetadata, idr: bool, ) -> EncodeResult<BackendRequest<Picture, Reference>>133 fn request_keyframe( 134 &mut self, 135 input: Picture, 136 input_meta: FrameMetadata, 137 idr: bool, 138 ) -> EncodeResult<BackendRequest<Picture, Reference>> { 139 if idr { 140 // Begin new sequence and start with I frame and no references. 141 self.new_sequence(); 142 } 143 144 let sps = self.delegate.sps.clone().ok_or(EncodeError::InvalidInternalState)?; 145 let pps = self.delegate.pps.clone().ok_or(EncodeError::InvalidInternalState)?; 146 147 let dpb_meta = DpbEntryMeta { 148 poc: ((self.counter * 2) & 0xffff) as u16, 149 frame_num: self.counter as u32, 150 is_reference: IsReference::ShortTerm, 151 }; 152 153 let header = SliceHeaderBuilder::new(&pps) 154 .slice_type(SliceType::I) 155 .first_mb_in_slice(0) 156 .pic_order_cnt_lsb(dpb_meta.poc) 157 .build(); 158 159 let mut headers = vec![]; 160 if idr || self.delegate.update_params_sets { 161 Synthesizer::<Sps, &mut Vec<u8>>::synthesize(3, &sps, &mut headers, true)?; 162 Synthesizer::<Pps, &mut Vec<u8>>::synthesize(3, &pps, &mut headers, true)?; 163 self.delegate.update_params_sets = false; 164 } 165 166 let num_macroblocks = (sps.pic_width_in_mbs_minus1 as usize + 1) 167 * (sps.pic_height_in_map_units_minus1 as usize + 1); 168 169 let request = BackendRequest { 170 sps, 171 pps, 172 header, 173 input, 174 input_meta, 175 dpb_meta, 176 // This frame is IDR, therefore it has no references 177 ref_list_0: vec![], 178 ref_list_1: vec![], 179 180 // I frame is every `self.limit` is requested 181 intra_period: self.limit as u32, 182 // There is no B frames between I and P frames 183 ip_period: 0, 184 185 num_macroblocks, 186 187 is_idr: idr, 188 tunings: self.tunings.clone(), 189 190 coded_output: headers, 191 }; 192 193 Ok(request) 194 } 195 request_interframe( &mut self, input: Picture, input_meta: FrameMetadata, ) -> EncodeResult<BackendRequest<Picture, Reference>>196 fn request_interframe( 197 &mut self, 198 input: Picture, 199 input_meta: FrameMetadata, 200 ) -> EncodeResult<BackendRequest<Picture, Reference>> { 201 let mut ref_list_0 = vec![]; 202 203 // Use all avaiable reference frames in DPB. Their number is limited by the parameter 204 for reference in self.references.iter().rev() { 205 ref_list_0.push(Rc::clone(reference)); 206 } 207 208 let sps = self.delegate.sps.clone().ok_or(EncodeError::InvalidInternalState)?; 209 let pps = self.delegate.pps.clone().ok_or(EncodeError::InvalidInternalState)?; 210 211 let dpb_meta = DpbEntryMeta { 212 poc: ((self.counter * 2) & 0xffff) as u16, 213 frame_num: self.counter as u32, 214 is_reference: IsReference::ShortTerm, 215 }; 216 217 let header = SliceHeaderBuilder::new(&pps) 218 .slice_type(SliceType::P) 219 .first_mb_in_slice(0) 220 .pic_order_cnt_lsb(dpb_meta.poc) 221 .build(); 222 223 let mut headers = Vec::new(); 224 if self.delegate.update_params_sets { 225 Synthesizer::<Sps, &mut Vec<u8>>::synthesize(3, &sps, &mut headers, true)?; 226 Synthesizer::<Pps, &mut Vec<u8>>::synthesize(3, &pps, &mut headers, true)?; 227 self.delegate.update_params_sets = false; 228 } 229 230 let num_macroblocks = (sps.pic_width_in_mbs_minus1 as usize + 1) 231 * (sps.pic_height_in_map_units_minus1 as usize + 1); 232 233 let request = BackendRequest { 234 sps, 235 pps, 236 header, 237 input, 238 input_meta, 239 dpb_meta, 240 ref_list_0, 241 ref_list_1: vec![], // No future references 242 243 // I frame is every `self.limit` is requested 244 intra_period: self.limit as u32, 245 // There is no B frames between I and P frames 246 ip_period: 0, 247 248 num_macroblocks, 249 250 is_idr: false, 251 tunings: self.tunings.clone(), 252 253 coded_output: headers, 254 }; 255 256 self.references.clear(); 257 258 Ok(request) 259 } 260 try_tunings(&self, _tunings: &Tunings) -> EncodeResult<()>261 fn try_tunings(&self, _tunings: &Tunings) -> EncodeResult<()> { 262 Ok(()) 263 } 264 apply_tunings(&mut self, _tunings: &Tunings) -> EncodeResult<()>265 fn apply_tunings(&mut self, _tunings: &Tunings) -> EncodeResult<()> { 266 self.new_sequence(); 267 Ok(()) 268 } 269 } 270