• 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 
7 use thiserror::Error;
8 
9 use crate::encoder::CodedBitstreamBuffer;
10 use crate::encoder::EncodeError;
11 use crate::encoder::EncodeResult;
12 use crate::encoder::FrameMetadata;
13 use crate::encoder::Tunings;
14 use crate::encoder::VideoEncoder;
15 use crate::BlockingMode;
16 
17 #[cfg(feature = "vaapi")]
18 pub mod av1;
19 #[cfg(feature = "vaapi")]
20 pub mod h264;
21 #[cfg(feature = "vaapi")]
22 pub(crate) mod predictor;
23 #[cfg(feature = "vaapi")]
24 pub mod vp9;
25 
26 #[derive(Error, Debug)]
27 pub enum StatelessBackendError {
28     #[error("unsupported profile")]
29     UnsupportedProfile,
30     #[error("unsupported format")]
31     UnsupportedFormat,
32     #[error("not enough resources to proceed with the operation now")]
33     OutOfResources,
34     #[error(transparent)]
35     Other(#[from] anyhow::Error),
36 }
37 
38 pub type StatelessBackendResult<T> = Result<T, StatelessBackendError>;
39 
40 /// Trait for representing pending encoder output.
41 pub trait BackendPromise {
42     type Output;
43 
44     /// Return coded result of the processing. Blocks if processing is not finished yet.
sync(self) -> StatelessBackendResult<Self::Output>45     fn sync(self) -> StatelessBackendResult<Self::Output>;
46 
47     /// Return true whenever the underlaying processing is done
is_ready(&self) -> bool48     fn is_ready(&self) -> bool;
49 }
50 
51 pub struct ReadyPromise<T>(T);
52 
53 impl<T> From<T> for ReadyPromise<T> {
from(value: T) -> Self54     fn from(value: T) -> Self {
55         ReadyPromise(value)
56     }
57 }
58 
59 impl<T> BackendPromise for ReadyPromise<T> {
60     type Output = T;
61 
sync(self) -> StatelessBackendResult<Self::Output>62     fn sync(self) -> StatelessBackendResult<Self::Output> {
63         Ok(self.0)
64     }
65 
is_ready(&self) -> bool66     fn is_ready(&self) -> bool {
67         true
68     }
69 }
70 
71 /// Wrapper type for [`BackendPromise<Output = Vec<u8>>`], with additional
72 /// metadata.
73 pub struct BitstreamPromise<P>
74 where
75     P: BackendPromise<Output = Vec<u8>>,
76 {
77     /// Slice data and reconstructed surface promise
78     bitstream: P,
79 
80     /// Input frame metadata, for [`CodedBitstreamBuffer`]
81     meta: FrameMetadata,
82 }
83 
84 impl<P> BackendPromise for BitstreamPromise<P>
85 where
86     P: BackendPromise<Output = Vec<u8>>,
87 {
88     type Output = CodedBitstreamBuffer;
89 
is_ready(&self) -> bool90     fn is_ready(&self) -> bool {
91         self.bitstream.is_ready()
92     }
93 
sync(self) -> StatelessBackendResult<Self::Output>94     fn sync(self) -> StatelessBackendResult<Self::Output> {
95         let coded_data = self.bitstream.sync()?;
96 
97         log::trace!("synced bitstream size={}", coded_data.len());
98 
99         Ok(CodedBitstreamBuffer::new(self.meta, coded_data))
100     }
101 }
102 
103 /// Internal structure representing all current processing represented using promises and allowing
104 /// polling for finished promises.
105 pub(crate) struct OutputQueue<O>
106 where
107     O: BackendPromise,
108 {
109     /// True if the every single polling call shall be blocking
110     blocking: BlockingMode,
111 
112     /// Queue of currently pending [`BackendPromise`]
113     promises: VecDeque<O>,
114 }
115 
116 impl<O> OutputQueue<O>
117 where
118     O: BackendPromise,
119 {
120     #[allow(dead_code)]
new(blocking: BlockingMode) -> Self121     pub(crate) fn new(blocking: BlockingMode) -> Self {
122         Self { blocking, promises: Default::default() }
123     }
124 
125     /// Add new pending job to the queue. Which will be returned to client if it is done.
126     #[allow(dead_code)]
add_promise(&mut self, pending: O)127     pub(crate) fn add_promise(&mut self, pending: O) {
128         self.promises.push_back(pending);
129     }
130 
131     /// Returns the result of an oldest [`BackendPromise`] if it is done processing. If `force_block`
132     /// is true, then the function will block till processing of the oldest [`BackendPromise`] is
133     /// finished and return it's result.
poll(&mut self, mode: BlockingMode) -> StatelessBackendResult<Option<O::Output>>134     pub(crate) fn poll(&mut self, mode: BlockingMode) -> StatelessBackendResult<Option<O::Output>> {
135         let block = self.blocking == BlockingMode::Blocking || mode == BlockingMode::Blocking;
136 
137         match self.promises.pop_front() {
138             Some(o) if block || o.is_ready() => Ok(Some(o.sync()?)),
139             Some(o) => {
140                 self.promises.push_front(o);
141                 Ok(None)
142             }
143             None => Ok(None),
144         }
145     }
146 
147     /// Returns true if queue is empty ie. no [`BackendPromise`] is pending.
is_empty(&self) -> bool148     pub(crate) fn is_empty(&self) -> bool {
149         self.promises.is_empty()
150     }
151 }
152 
153 /// Predictor is responsible for yielding stream parameter sets and creating requests to backend.
154 /// It accepts the frames and reconstructed frames and returns [`Request`]s for execution. For
155 /// example [`Predictor`] may hold frames from processing until enough is supplied to create a
156 /// specific prediction structure. [`Predictor::drain`] may be called to force predictor to
157 /// yield requests.
158 pub(super) trait Predictor<Picture, Reference, Request> {
159     /// Called by encoder when there is new frame to encode. The predictor may return empty vector
160     /// to postpone processing or a set of requests to process frames (it does not have to be a frame
161     /// specified in parameters)
new_frame( &mut self, backend_pic: Picture, meta: FrameMetadata, ) -> EncodeResult<Vec<Request>>162     fn new_frame(
163         &mut self,
164         backend_pic: Picture,
165         meta: FrameMetadata,
166     ) -> EncodeResult<Vec<Request>>;
167 
168     /// This function is called by the encoder, with reconstructed frame when backend finished
169     /// processing the frame. the [`Predictor`] may choose to return [`Request`]s to submit to
170     /// backend, if reconstructed was required for creating that request.
reconstructed(&mut self, recon: Reference) -> EncodeResult<Vec<Request>>171     fn reconstructed(&mut self, recon: Reference) -> EncodeResult<Vec<Request>>;
172 
173     /// Requests the change of dynamic parameters (aka [`Tunings`]) for the stream. The predictor
174     /// may choose to delay the change until entire or some part of the structure had been encoded.
175     /// However in such case the predictor is responsible for ensuring the change will be
176     /// successful.
tune(&mut self, tunings: Tunings) -> EncodeResult<()>177     fn tune(&mut self, tunings: Tunings) -> EncodeResult<()>;
178 
179     /// Force [`Predictor`] to pop at least one frame from internal queue and return a [`Request`]s
drain(&mut self) -> EncodeResult<Vec<Request>>180     fn drain(&mut self) -> EncodeResult<Vec<Request>>;
181 }
182 
183 /// Generic trait for stateless encoder backends
184 pub trait StatelessVideoEncoderBackend<Codec>: Sized
185 where
186     Codec: StatelessCodec<Self>,
187 {
188     /// Backend's specific representation of the input frame, transformed with [`import_picture`].
189     /// Might be a wrapper of the input handle with additional backend specific data or a copy of
190     /// an input frame in internal backend's representation.
191     ///
192     /// [`import_picture`]: StatelessEncoderBackendImport::import_picture
193     type Picture: 'static;
194 
195     /// Backend's reconstructed frame handle.
196     type Reconstructed: 'static;
197 
198     /// Backend's specific [`BackendPromise`] for bitstream, a result of
199     /// [`StatelessCodec::Request`] submission.
200     type CodedPromise: BackendPromise<Output = Vec<u8>>;
201 
202     /// Backend's specific [`BackendPromise`] for [`StatelessVideoEncoderBackend::Reconstructed`],
203     /// a result of [`StatelessCodec::Request`] submission.
204     type ReconPromise: BackendPromise<Output = Self::Reconstructed>;
205 }
206 
207 pub trait StatelessEncoderBackendImport<Handle, Picture> {
208     /// Imports the input `handle` from client and transforms into `Picture`
import_picture( &mut self, metadata: &FrameMetadata, handle: Handle, ) -> StatelessBackendResult<Picture>209     fn import_picture(
210         &mut self,
211         metadata: &FrameMetadata,
212         handle: Handle,
213     ) -> StatelessBackendResult<Picture>;
214 }
215 
216 /// Trait helping contain all codec specific and backend specific types
217 pub trait StatelessCodec<Backend>: Sized
218 where
219     Backend: StatelessVideoEncoderBackend<Self>,
220 {
221     /// Codec specific representation of frame reference wrapping a backend reference type
222     /// containing a codec specific frame metadata
223     type Reference;
224 
225     /// A request type that will be delivered to codec specific stateless encoder backend
226     type Request;
227 
228     /// Codec specific [`BackendPromise`] for [`CodedBitstreamBuffer`] wrapping a backend specific
229     /// [`StatelessVideoEncoderBackend::CodedPromise`]
230     type CodedPromise: BackendPromise<Output = CodedBitstreamBuffer>;
231 
232     /// Codec specific [`BackendPromise`] for [`StatelessCodec::Reference`] wrapping a
233     /// backend speficic [`StatelessVideoEncoderBackend::ReconPromise`]
234     type ReferencePromise: BackendPromise<Output = Self::Reference>;
235 }
236 
237 /// Helper aliases for codec and backend specific types
238 type Picture<C, B> = <B as StatelessVideoEncoderBackend<C>>::Picture;
239 
240 type Reference<C, B> = <C as StatelessCodec<B>>::Reference;
241 
242 type Request<C, B> = <C as StatelessCodec<B>>::Request;
243 
244 type CodedPromise<C, B> = <C as StatelessCodec<B>>::CodedPromise;
245 
246 type ReferencePromise<C, B> = <C as StatelessCodec<B>>::ReferencePromise;
247 
248 type BoxPredictor<C, B> = Box<dyn Predictor<Picture<C, B>, Reference<C, B>, Request<C, B>>>;
249 
250 pub struct StatelessEncoder<Codec, Handle, Backend>
251 where
252     Backend: StatelessVideoEncoderBackend<Codec>,
253     Codec: StatelessCodec<Backend>,
254 {
255     /// Pending frame output promise queue
256     output_queue: OutputQueue<CodedPromise<Codec, Backend>>,
257 
258     /// Pending reconstructed pictures promise queue
259     recon_queue: OutputQueue<ReferencePromise<Codec, Backend>>,
260 
261     /// [`Predictor`] instance responsible for the encoder decision making
262     predictor: BoxPredictor<Codec, Backend>,
263 
264     // predictor: Box<dyn Predictor<B::Picture, B::Reference>>,
265     coded_queue: VecDeque<CodedBitstreamBuffer>,
266 
267     /// Number of the currently held frames by the predictor
268     predictor_frame_count: usize,
269 
270     /// [`StatelessVideoEncoderBackend`] instance to delegate work to
271     backend: Backend,
272 
273     _phantom: std::marker::PhantomData<Handle>,
274 }
275 
276 /// A bridge trait between [`StatelessEncoder`] and codec specific backend trait (eg.
277 /// [`h264::StatelessH264EncoderBackend`] or [`vp9::StatelessVP9EncoderBackend`]). Accepts
278 /// `Request` and is responsible for adding resutling [`BackendPromise`] to [`StatelessEncoder`]
279 /// internal queues and  decrementing the internal predictor frame counter if the backend moved the
280 /// frame outside predictor ownership.
281 pub trait StatelessEncoderExecute<Codec, Handle, Backend>
282 where
283     Backend: StatelessVideoEncoderBackend<Codec>,
284     Codec: StatelessCodec<Backend>,
285 {
execute(&mut self, request: Request<Codec, Backend>) -> EncodeResult<()>286     fn execute(&mut self, request: Request<Codec, Backend>) -> EncodeResult<()>;
287 }
288 
289 impl<Codec, Handle, Backend> StatelessEncoder<Codec, Handle, Backend>
290 where
291     Codec: StatelessCodec<Backend>,
292     Backend: StatelessVideoEncoderBackend<Codec>,
293     Self: StatelessEncoderExecute<Codec, Handle, Backend>,
294 {
295     #[allow(dead_code)]
new( backend: Backend, mode: BlockingMode, predictor: BoxPredictor<Codec, Backend>, ) -> EncodeResult<Self>296     fn new(
297         backend: Backend,
298         mode: BlockingMode,
299         predictor: BoxPredictor<Codec, Backend>,
300     ) -> EncodeResult<Self> {
301         Ok(Self {
302             backend,
303             predictor,
304             predictor_frame_count: 0,
305             coded_queue: Default::default(),
306             output_queue: OutputQueue::new(mode),
307             recon_queue: OutputQueue::new(mode),
308             _phantom: Default::default(),
309         })
310     }
311 
poll_pending(&mut self, mode: BlockingMode) -> EncodeResult<()>312     fn poll_pending(&mut self, mode: BlockingMode) -> EncodeResult<()> {
313         // Poll the output queue once and then continue polling while new promise is submitted
314         while let Some(coded) = self.output_queue.poll(mode)? {
315             self.coded_queue.push_back(coded);
316         }
317 
318         while let Some(recon) = self.recon_queue.poll(mode)? {
319             let requests = self.predictor.reconstructed(recon)?;
320             if requests.is_empty() {
321                 // No promise was submitted, therefore break
322                 break;
323             }
324 
325             for request in requests {
326                 self.execute(request)?;
327             }
328         }
329 
330         Ok(())
331     }
332 }
333 
334 impl<Codec, Handle, Backend> VideoEncoder<Handle> for StatelessEncoder<Codec, Handle, Backend>
335 where
336     Codec: StatelessCodec<Backend>,
337     Backend: StatelessVideoEncoderBackend<Codec>,
338     Backend: StatelessEncoderBackendImport<Handle, Backend::Picture>,
339     Self: StatelessEncoderExecute<Codec, Handle, Backend>,
340 {
tune(&mut self, tunings: Tunings) -> EncodeResult<()>341     fn tune(&mut self, tunings: Tunings) -> EncodeResult<()> {
342         self.predictor.tune(tunings)
343     }
344 
encode(&mut self, metadata: FrameMetadata, handle: Handle) -> EncodeResult<()>345     fn encode(&mut self, metadata: FrameMetadata, handle: Handle) -> EncodeResult<()> {
346         log::trace!("encode: timestamp={} layout={:?}", metadata.timestamp, metadata.layout);
347 
348         // Import `handle` to backends representation
349         let backend_pic = self.backend.import_picture(&metadata, handle)?;
350 
351         // Increase the number of frames that predictor holds, before handing one to it
352         self.predictor_frame_count += 1;
353 
354         // Ask predictor to decide on the next move and execute it
355         let requests = self.predictor.new_frame(backend_pic, metadata)?;
356         for request in requests {
357             self.execute(request)?;
358         }
359 
360         Ok(())
361     }
362 
drain(&mut self) -> EncodeResult<()>363     fn drain(&mut self) -> EncodeResult<()> {
364         log::trace!("currently predictor holds {}", self.predictor_frame_count);
365 
366         // Drain the predictor
367         while self.predictor_frame_count > 0 || !self.recon_queue.is_empty() {
368             if self.output_queue.is_empty() && self.recon_queue.is_empty() {
369                 // The OutputQueue is empty and predictor holds frames, force it to yield a request
370                 // to empty it's internal queue.
371                 let requests = self.predictor.drain()?;
372                 if requests.is_empty() {
373                     log::error!("failed to drain predictor, no request was returned");
374                     return Err(EncodeError::InvalidInternalState);
375                 }
376 
377                 for request in requests {
378                     self.execute(request)?;
379                 }
380             }
381 
382             self.poll_pending(BlockingMode::Blocking)?;
383         }
384 
385         // There are still some requests being processed. Continue on polling them.
386         while !self.output_queue.is_empty() {
387             self.poll_pending(BlockingMode::Blocking)?;
388         }
389 
390         Ok(())
391     }
392 
poll(&mut self) -> EncodeResult<Option<CodedBitstreamBuffer>>393     fn poll(&mut self) -> EncodeResult<Option<CodedBitstreamBuffer>> {
394         // Poll on output queue without blocking and try to dueue from coded queue
395         self.poll_pending(BlockingMode::NonBlocking)?;
396         Ok(self.coded_queue.pop_front())
397     }
398 }
399