• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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