• 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::collections::VecDeque;
6 use std::rc::Rc;
7 
8 use crate::encoder::stateless::Predictor;
9 use crate::encoder::EncodeError;
10 use crate::encoder::EncodeResult;
11 use crate::encoder::FrameMetadata;
12 use crate::encoder::RateControl;
13 use crate::encoder::Tunings;
14 
15 /// Implementation of [`LowDelay`] prediction structure. See [`LowDelay`] for details.
16 ///
17 /// [`LowDelay`]: crate::encoder::PredictionStructure::LowDelay
18 pub(crate) struct LowDelay<Picture, Reference, Delegate, Request> {
19     /// Pending frames for encoding
20     pub(super) queue: VecDeque<(Picture, FrameMetadata)>,
21 
22     /// Availabe frames for references
23     pub(super) references: VecDeque<Rc<Reference>>,
24 
25     /// Current frame counter
26     pub(super) counter: usize,
27 
28     /// The number of frames between intra frames
29     pub(super) limit: u16,
30 
31     /// Codec specific delegate. Holds codec specific state. Is also used to differentiate
32     /// [`LowDelay`] implementations between codecs.
33     pub(super) delegate: Delegate,
34 
35     /// Currently set tunings for the stream
36     pub(super) tunings: Tunings,
37 
38     /// Pending [`Tunings`] to be applied with `counter` value when to set them.
39     /// In this way we ensure that the requested frames prior tuning request are encoded using
40     /// previous tunings. This is especially important for bitrate, this way we ensure the bitrate
41     /// changes when requested.
42     pub(super) tunings_queue: VecDeque<(usize, Tunings)>,
43 
44     pub(super) _phantom: std::marker::PhantomData<Request>,
45 }
46 
47 /// Helper trait enabling forcing [`LowDelay`] to implement codec specific functions.
48 pub(crate) trait LowDelayDelegate<Picture, Reference, Request> {
49     /// Creates keyframe or IDR request for the codec backend
request_keyframe( &mut self, input: Picture, input_meta: FrameMetadata, idr: bool, ) -> EncodeResult<Request>50     fn request_keyframe(
51         &mut self,
52         input: Picture,
53         input_meta: FrameMetadata,
54         idr: bool,
55     ) -> EncodeResult<Request>;
56 
57     /// Creates interframe request for the codec backend
request_interframe( &mut self, input: Picture, input_meta: FrameMetadata, ) -> EncodeResult<Request>58     fn request_interframe(
59         &mut self,
60         input: Picture,
61         input_meta: FrameMetadata,
62     ) -> EncodeResult<Request>;
63 
64     /// Checks if the `_tunings` can be applied
try_tunings(&self, _tunings: &Tunings) -> EncodeResult<()>65     fn try_tunings(&self, _tunings: &Tunings) -> EncodeResult<()> {
66         Err(EncodeError::Unsupported)
67     }
68 
69     /// Applies `_tunings`
apply_tunings(&mut self, _tunings: &Tunings) -> EncodeResult<()>70     fn apply_tunings(&mut self, _tunings: &Tunings) -> EncodeResult<()> {
71         Err(EncodeError::Unsupported)
72     }
73 }
74 
75 impl<Picture, Reference, Delegate, Request> LowDelay<Picture, Reference, Delegate, Request>
76 where
77     Self: LowDelayDelegate<Picture, Reference, Request>,
78 {
pop_tunings(&mut self) -> EncodeResult<()>79     fn pop_tunings(&mut self) -> EncodeResult<()> {
80         while let Some((when_counter, _)) = self.tunings_queue.front() {
81             if self.counter < *when_counter {
82                 log::trace!(
83                     "Pending tuning skipped counter={} scheduled={}",
84                     self.counter,
85                     when_counter
86                 );
87                 break;
88             }
89 
90             // SAFETY: checked in loop condition
91             let (_, tunings) = self.tunings_queue.pop_front().unwrap();
92             log::info!("Applying tuning {tunings:?}");
93             self.apply_tunings(&tunings)?;
94             self.tunings = tunings;
95         }
96 
97         Ok(())
98     }
99 
next_request(&mut self) -> EncodeResult<Vec<Request>>100     fn next_request(&mut self) -> EncodeResult<Vec<Request>> {
101         log::trace!("Pending frames in the queue: {}", self.queue.len());
102 
103         let mut requests = Vec::new();
104         while let Some((input, meta)) = self.queue.pop_front() {
105             self.pop_tunings()?;
106 
107             if self.counter == 0 || meta.force_keyframe {
108                 log::trace!("Requesting keyframe/IDR for timestamp={}", meta.timestamp);
109                 // If first frame in the sequence or forced IDR then clear references and create
110                 // keyframe request.
111                 // TODO: Maybe don't clear references on just keyframe (!= IDR)
112                 self.references.clear();
113 
114                 let request = self.request_keyframe(input, meta, self.counter == 0)?;
115 
116                 requests.push(request);
117                 self.counter = self.counter.wrapping_add(1) % (self.limit as usize);
118             } else if self.references.is_empty() {
119                 log::trace!("Awaiting more reconstructed frames");
120                 // There is no enough frames reconstructed
121                 self.queue.push_front((input, meta));
122                 break;
123             } else {
124                 log::trace!("Requesting interframe for timestamp={}", meta.timestamp);
125                 let request = self.request_interframe(input, meta)?;
126 
127                 requests.push(request);
128                 self.counter = self.counter.wrapping_add(1) % (self.limit as usize);
129 
130                 break;
131             }
132         }
133 
134         Ok(requests)
135     }
136 }
137 
138 impl<Picture, Reference, Delegate, Request> Predictor<Picture, Reference, Request>
139     for LowDelay<Picture, Reference, Delegate, Request>
140 where
141     Self: LowDelayDelegate<Picture, Reference, Request>,
142 {
new_frame( &mut self, input: Picture, frame_metadata: FrameMetadata, ) -> EncodeResult<Vec<Request>>143     fn new_frame(
144         &mut self,
145         input: Picture,
146         frame_metadata: FrameMetadata,
147     ) -> EncodeResult<Vec<Request>> {
148         log::trace!("New frame added to queue timestamp={}", frame_metadata.timestamp);
149         // Add new frame in the request queue and request new encoding if possible
150         self.queue.push_back((input, frame_metadata));
151         self.next_request()
152     }
153 
reconstructed(&mut self, reference: Reference) -> EncodeResult<Vec<Request>>154     fn reconstructed(&mut self, reference: Reference) -> EncodeResult<Vec<Request>> {
155         log::trace!("A frame was reconstructed");
156         // Add new reconstructed surface and request next encoding if possible
157         self.references.push_back(Rc::new(reference));
158         self.next_request()
159     }
160 
tune(&mut self, tunings: Tunings) -> EncodeResult<()>161     fn tune(&mut self, tunings: Tunings) -> EncodeResult<()> {
162         log::trace!("Tuning requested with {tunings:?}");
163         if !RateControl::is_same_variant(&self.tunings.rate_control, &tunings.rate_control) {
164             // TODO(bgrzesik): consider enabling switching between RateControl variants
165             log::error!("Changing RateControl variant is not supported at the moment");
166             return Err(EncodeError::Unsupported);
167         }
168 
169         // Check if the tunings are or will be the same, in such case we skip.
170         let skip = match self.tunings_queue.front() {
171             Some((_, preceeding_tunnings)) if preceeding_tunnings == &tunings => true,
172             None if self.tunings == tunings => true,
173             _ => false,
174         };
175 
176         if skip {
177             log::debug!("Tuning skipped, the requested values are the same.");
178             return Ok(());
179         }
180 
181         // Check if applying tunings will succeed.
182         self.try_tunings(&tunings)?;
183 
184         let when_counter = self.counter + self.queue.len();
185         self.tunings_queue.push_back((when_counter, tunings));
186 
187         Ok(())
188     }
189 
drain(&mut self) -> EncodeResult<Vec<Request>>190     fn drain(&mut self) -> EncodeResult<Vec<Request>> {
191         // [`LowDelay`] will not hold any frames, therefore the drain function shall never be called.
192         Err(EncodeError::InvalidInternalState)
193     }
194 }
195 
196 #[cfg(test)]
197 mod tests {
198     use crate::Fourcc;
199 
200     use super::*;
201 
202     #[derive(Debug, PartialEq, Eq)]
203     enum MockRequest {
204         KeyFrameRequest(u32, Tunings),
205         InterframerRequest(u32, Tunings),
206     }
207 
208     struct MockDelegate;
209 
210     impl LowDelayDelegate<u32, u32, MockRequest> for LowDelay<u32, u32, MockDelegate, MockRequest> {
request_interframe( &mut self, input: u32, _input_meta: FrameMetadata, ) -> EncodeResult<MockRequest>211         fn request_interframe(
212             &mut self,
213             input: u32,
214             _input_meta: FrameMetadata,
215         ) -> EncodeResult<MockRequest> {
216             Ok(MockRequest::InterframerRequest(input, self.tunings.clone()))
217         }
218 
request_keyframe( &mut self, input: u32, _input_meta: FrameMetadata, _idr: bool, ) -> EncodeResult<MockRequest>219         fn request_keyframe(
220             &mut self,
221             input: u32,
222             _input_meta: FrameMetadata,
223             _idr: bool,
224         ) -> EncodeResult<MockRequest> {
225             Ok(MockRequest::KeyFrameRequest(input, self.tunings.clone()))
226         }
227 
try_tunings(&self, _tunings: &Tunings) -> EncodeResult<()>228         fn try_tunings(&self, _tunings: &Tunings) -> EncodeResult<()> {
229             Ok(())
230         }
231 
apply_tunings(&mut self, _tunings: &Tunings) -> EncodeResult<()>232         fn apply_tunings(&mut self, _tunings: &Tunings) -> EncodeResult<()> {
233             Ok(())
234         }
235     }
236 
dummy_frame_meta(timestamp: u64, force_keyframe: bool) -> FrameMetadata237     fn dummy_frame_meta(timestamp: u64, force_keyframe: bool) -> FrameMetadata {
238         FrameMetadata {
239             timestamp,
240             layout: crate::FrameLayout {
241                 format: (Fourcc::from(b"NV12"), 0),
242                 size: crate::Resolution { width: 0, height: 0 },
243                 planes: vec![],
244             },
245             force_keyframe,
246         }
247     }
248 
249     /// This test ensures that Tunings change applies to only frames following the change
250     #[test]
test_tuning_delay()251     fn test_tuning_delay() {
252         let _ = env_logger::try_init();
253 
254         let tunings_prev = Tunings { framerate: 1, ..Default::default() };
255 
256         let mut predictor: LowDelay<u32, u32, MockDelegate, MockRequest> = LowDelay {
257             queue: Default::default(),
258             references: Default::default(),
259             counter: 0,
260             limit: 1028,
261             delegate: MockDelegate,
262             tunings: tunings_prev.clone(),
263             tunings_queue: Default::default(),
264             _phantom: Default::default(),
265         };
266 
267         let mut requests = Vec::new();
268 
269         requests.extend(predictor.new_frame(0, dummy_frame_meta(0, false)).unwrap());
270         requests.extend(predictor.new_frame(1, dummy_frame_meta(1, false)).unwrap());
271         requests.extend(predictor.new_frame(2, dummy_frame_meta(2, false)).unwrap());
272         requests.extend(predictor.new_frame(3, dummy_frame_meta(3, false)).unwrap());
273 
274         let tunings_next = Tunings { framerate: 2, ..Default::default() };
275 
276         predictor.tune(tunings_next.clone()).unwrap();
277 
278         assert_eq!(predictor.tunings, tunings_prev);
279 
280         requests.extend(predictor.new_frame(4, dummy_frame_meta(4, false)).unwrap());
281 
282         requests.extend(predictor.reconstructed(0).unwrap());
283         requests.extend(predictor.reconstructed(1).unwrap());
284         requests.extend(predictor.reconstructed(2).unwrap());
285 
286         assert_eq!(predictor.tunings, tunings_prev);
287         requests.extend(predictor.reconstructed(3).unwrap());
288 
289         assert_eq!(predictor.tunings, tunings_next);
290         requests.extend(predictor.reconstructed(4).unwrap());
291 
292         assert_eq!(
293             requests,
294             vec![
295                 MockRequest::KeyFrameRequest(0, tunings_prev.clone()),
296                 MockRequest::InterframerRequest(1, tunings_prev.clone()),
297                 MockRequest::InterframerRequest(2, tunings_prev.clone()),
298                 MockRequest::InterframerRequest(3, tunings_prev.clone()),
299                 MockRequest::InterframerRequest(4, tunings_next.clone()),
300             ]
301         );
302     }
303 
304     #[test]
test_keyframes()305     fn test_keyframes() {
306         const FRAME_COUNT: u32 = 1028;
307         const IDR_PERIOD: u16 = 37;
308         const KEYFRAME_REQUEST_PERIOD: u32 = 31;
309 
310         let _ = env_logger::try_init();
311 
312         let tunings = Tunings::default();
313         let mut predictor: LowDelay<u32, u32, MockDelegate, MockRequest> = LowDelay {
314             queue: Default::default(),
315             references: Default::default(),
316             counter: 0,
317             limit: IDR_PERIOD,
318             delegate: MockDelegate,
319             tunings: tunings.clone(),
320             tunings_queue: Default::default(),
321             _phantom: Default::default(),
322         };
323 
324         let mut requests = Vec::new();
325 
326         for i in 0..FRAME_COUNT {
327             let keyframe = i % KEYFRAME_REQUEST_PERIOD == 0;
328             requests.extend(predictor.new_frame(i, dummy_frame_meta(i as u64, keyframe)).unwrap());
329         }
330 
331         for i in 0..FRAME_COUNT {
332             requests.extend(predictor.reconstructed(i).unwrap());
333         }
334 
335         let mut expected = Vec::new();
336         for i in 0..FRAME_COUNT {
337             if (i % IDR_PERIOD as u32 == 0) || (i % KEYFRAME_REQUEST_PERIOD) == 0 {
338                 expected.push(MockRequest::KeyFrameRequest(i, tunings.clone()));
339             } else {
340                 expected.push(MockRequest::InterframerRequest(i, tunings.clone()));
341             }
342         }
343 
344         assert_eq!(requests, expected);
345     }
346 }
347