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 crate::codec::h264::parser::Pps; 8 use crate::codec::h264::parser::SliceHeader; 9 use crate::codec::h264::parser::Sps; 10 use crate::encoder::h264::EncoderConfig; 11 use crate::encoder::h264::H264; 12 use crate::encoder::stateless::h264::predictor::LowDelayH264; 13 use crate::encoder::stateless::BackendPromise; 14 use crate::encoder::stateless::BitstreamPromise; 15 use crate::encoder::stateless::FrameMetadata; 16 use crate::encoder::stateless::Predictor; 17 use crate::encoder::stateless::StatelessBackendResult; 18 use crate::encoder::stateless::StatelessCodec; 19 use crate::encoder::stateless::StatelessEncoderBackendImport; 20 use crate::encoder::stateless::StatelessEncoderExecute; 21 use crate::encoder::stateless::StatelessVideoEncoderBackend; 22 use crate::encoder::EncodeResult; 23 use crate::encoder::PredictionStructure; 24 use crate::encoder::Tunings; 25 use crate::BlockingMode; 26 27 mod predictor; 28 29 #[cfg(feature = "vaapi")] 30 pub mod vaapi; 31 32 #[derive(Copy, Clone, PartialEq, Eq, Debug)] 33 pub enum IsReference { 34 No, 35 ShortTerm, 36 LongTerm, 37 } 38 39 #[derive(Clone, Debug)] 40 pub struct DpbEntryMeta { 41 /// Picture order count 42 poc: u16, 43 frame_num: u32, 44 is_reference: IsReference, 45 } 46 47 /// Frame structure used in the backend representing currently encoded frame or references used 48 /// for its encoding. 49 pub struct DpbEntry<R> { 50 /// Reconstructed picture 51 recon_pic: R, 52 /// Decoded picture buffer entry metadata 53 meta: DpbEntryMeta, 54 } 55 56 /// Stateless H.264 encoder backend input. 57 pub struct BackendRequest<P, R> { 58 sps: Rc<Sps>, 59 pps: Rc<Pps>, 60 header: SliceHeader, 61 62 /// Input frame to be encoded 63 input: P, 64 65 /// Input frame metadata 66 input_meta: FrameMetadata, 67 68 /// DPB entry metadata 69 dpb_meta: DpbEntryMeta, 70 71 /// Reference lists 72 ref_list_0: Vec<Rc<DpbEntry<R>>>, 73 ref_list_1: Vec<Rc<DpbEntry<R>>>, 74 75 /// Period between intra frames 76 intra_period: u32, 77 78 /// Period between intra frame and P frame 79 ip_period: u32, 80 81 /// Number of macroblock to be encoded in slice 82 num_macroblocks: usize, 83 84 /// True whenever the result is IDR 85 is_idr: bool, 86 87 /// [`Tunings`] for the frame 88 tunings: Tunings, 89 90 /// Container for the request output. [`StatelessH264EncoderBackend`] impl shall move it and 91 /// append the slice data to it. This prevents unnecessary copying of bitstream around. 92 coded_output: Vec<u8>, 93 } 94 95 /// Wrapper type for [`BackendPromise<Output = R>`], with additional 96 /// metadata. 97 pub struct ReferencePromise<P> 98 where 99 P: BackendPromise, 100 { 101 /// Slice data and reconstructed surface promise 102 recon: P, 103 104 /// [`DpbEntryMeta`] of reconstructed surface 105 dpb_meta: DpbEntryMeta, 106 } 107 108 impl<P> BackendPromise for ReferencePromise<P> 109 where 110 P: BackendPromise, 111 { 112 type Output = DpbEntry<P::Output>; 113 is_ready(&self) -> bool114 fn is_ready(&self) -> bool { 115 self.recon.is_ready() 116 } 117 sync(self) -> StatelessBackendResult<Self::Output>118 fn sync(self) -> StatelessBackendResult<Self::Output> { 119 let recon_pic = self.recon.sync()?; 120 121 log::trace!("synced recon picture frame_num={}", self.dpb_meta.frame_num); 122 123 Ok(DpbEntry { recon_pic, meta: self.dpb_meta }) 124 } 125 } 126 127 impl<Backend> StatelessCodec<Backend> for H264 128 where 129 Backend: StatelessVideoEncoderBackend<H264>, 130 { 131 type Reference = DpbEntry<Backend::Reconstructed>; 132 133 type Request = BackendRequest<Backend::Picture, Backend::Reconstructed>; 134 135 type CodedPromise = BitstreamPromise<Backend::CodedPromise>; 136 137 type ReferencePromise = ReferencePromise<Backend::ReconPromise>; 138 } 139 140 /// Trait for stateless encoder backend for H.264 141 pub trait StatelessH264EncoderBackend: StatelessVideoEncoderBackend<H264> { 142 /// Submit a [`BackendRequest`] to the backend. This operation returns both a 143 /// [`StatelessVideoEncoderBackend::CodedPromise`] and a 144 /// [`StatelessVideoEncoderBackend::ReconPromise`] with resulting slice data. encode_slice( &mut self, request: BackendRequest<Self::Picture, Self::Reconstructed>, ) -> StatelessBackendResult<(Self::ReconPromise, Self::CodedPromise)>145 fn encode_slice( 146 &mut self, 147 request: BackendRequest<Self::Picture, Self::Reconstructed>, 148 ) -> StatelessBackendResult<(Self::ReconPromise, Self::CodedPromise)>; 149 } 150 151 pub type StatelessEncoder<Handle, Backend> = 152 crate::encoder::stateless::StatelessEncoder<H264, Handle, Backend>; 153 154 impl<Handle, Backend> StatelessEncoderExecute<H264, Handle, Backend> 155 for StatelessEncoder<Handle, Backend> 156 where 157 Backend: StatelessH264EncoderBackend, 158 { execute( &mut self, request: BackendRequest<Backend::Picture, Backend::Reconstructed>, ) -> EncodeResult<()>159 fn execute( 160 &mut self, 161 request: BackendRequest<Backend::Picture, Backend::Reconstructed>, 162 ) -> EncodeResult<()> { 163 let meta = request.input_meta.clone(); 164 let dpb_meta = request.dpb_meta.clone(); 165 166 // The [`BackendRequest`] has a frame from predictor. Decreasing internal counter. 167 self.predictor_frame_count -= 1; 168 169 log::trace!("submitting new request"); 170 let (recon, bitstream) = self.backend.encode_slice(request)?; 171 172 // Wrap promise from backend with headers and metadata 173 let slice_promise = BitstreamPromise { bitstream, meta }; 174 175 self.output_queue.add_promise(slice_promise); 176 177 let ref_promise = ReferencePromise { recon, dpb_meta }; 178 179 self.recon_queue.add_promise(ref_promise); 180 181 Ok(()) 182 } 183 } 184 185 impl<Handle, Backend> StatelessEncoder<Handle, Backend> 186 where 187 Backend: StatelessH264EncoderBackend, 188 Backend: StatelessEncoderBackendImport<Handle, Backend::Picture>, 189 { new_h264(backend: Backend, config: EncoderConfig, mode: BlockingMode) -> EncodeResult<Self>190 fn new_h264(backend: Backend, config: EncoderConfig, mode: BlockingMode) -> EncodeResult<Self> { 191 let predictor: Box<dyn Predictor<_, _, _>> = match config.pred_structure { 192 PredictionStructure::LowDelay { limit } => Box::new(LowDelayH264::new(config, limit)), 193 }; 194 195 Self::new(backend, mode, predictor) 196 } 197 } 198