• 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 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