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