• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
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::btree_map::Entry;
6 use std::collections::BTreeMap;
7 use std::fs::File;
8 
9 use libvda::encode::{EncodeCapabilities, VeaImplType, VeaInstance};
10 
11 use base::{error, warn, IntoRawDescriptor};
12 
13 use crate::virtio::video::encoder::encoder::*;
14 use crate::virtio::video::format::{Format, FormatDesc, FormatRange, FrameFormat, Level, Profile};
15 
16 pub struct LibvdaEncoder {
17     instance: VeaInstance,
18     capabilities: EncoderCapabilities,
19 }
20 
21 impl LibvdaEncoder {
new() -> Result<Self>22     pub fn new() -> Result<Self> {
23         let instance = VeaInstance::new(VeaImplType::Gavea)
24             .map_err(|e| EncoderError::Implementation(Box::new(e)))?;
25 
26         let EncodeCapabilities {
27             input_formats,
28             output_formats,
29         } = instance.get_capabilities();
30 
31         if input_formats.len() == 0 || output_formats.len() == 0 {
32             error!("No input or output formats.");
33             return Err(EncoderError::PlatformFailure);
34         }
35 
36         let input_format_descs: Vec<FormatDesc> = input_formats
37             .iter()
38             .map(|input_format| {
39                 let format = match input_format {
40                     libvda::PixelFormat::NV12 => Format::NV12,
41                     libvda::PixelFormat::YV12 => Format::YUV420,
42                 };
43 
44                 // VEA's GetSupportedProfiles does not return resolution information.
45                 // The input formats are retrieved by querying minigbm.
46                 // TODO(alexlau): Populate this with real information.
47 
48                 FormatDesc {
49                     mask: !(u64::MAX << output_formats.len()),
50                     format,
51                     frame_formats: vec![FrameFormat {
52                         width: FormatRange {
53                             min: 2,
54                             max: 4096,
55                             step: 1,
56                         },
57                         height: FormatRange {
58                             min: 2,
59                             max: 4096,
60                             step: 1,
61                         },
62                         bitrates: vec![FormatRange {
63                             min: 0,
64                             max: 8000,
65                             step: 1,
66                         }],
67                     }],
68                 }
69             })
70             .collect();
71 
72         if input_format_descs
73             .iter()
74             .find(|fd| fd.format == Format::NV12)
75             .is_none()
76         {
77             // NV12 is currently the only supported pixel format for libvda.
78             error!("libvda encoder does not support NV12.");
79             return Err(EncoderError::PlatformFailure);
80         }
81 
82         struct ParsedFormat {
83             profiles: Vec<Profile>,
84             max_width: u32,
85             max_height: u32,
86         }
87         let mut parsed_formats: BTreeMap<Format, ParsedFormat> = BTreeMap::new();
88 
89         for output_format in output_formats.iter() {
90             // TODO(alexlau): Consider using `max_framerate_numerator` and `max_framerate_denominator`.
91             let libvda::encode::OutputProfile {
92                 profile: libvda_profile,
93                 max_width,
94                 max_height,
95                 ..
96             } = output_format;
97 
98             let profile = match Profile::from_libvda_profile(*libvda_profile) {
99                 Some(p) => p,
100                 None => {
101                     warn!("Skipping unsupported libvda profile: {:?}", libvda_profile);
102                     continue;
103                 }
104             };
105 
106             match parsed_formats.entry(profile.to_format()) {
107                 Entry::Occupied(mut occupied_entry) => {
108                     let parsed_format = occupied_entry.get_mut();
109                     parsed_format.profiles.push(profile);
110                     // If we get different libvda profiles of the same VIRTIO_VIDEO_FORMAT
111                     // (Format) that have different max resolutions or bitrates, take the
112                     // minimum between all of the different profiles.
113                     parsed_format.max_width = std::cmp::min(*max_width, parsed_format.max_width);
114                     parsed_format.max_height = std::cmp::min(*max_height, parsed_format.max_height);
115                 }
116                 Entry::Vacant(vacant_entry) => {
117                     vacant_entry.insert(ParsedFormat {
118                         profiles: vec![profile],
119                         max_width: *max_width,
120                         max_height: *max_height,
121                     });
122                 }
123             }
124         }
125 
126         let mut output_format_descs = vec![];
127         let mut coded_format_profiles = BTreeMap::new();
128         for (format, parsed_format) in parsed_formats.into_iter() {
129             let ParsedFormat {
130                 mut profiles,
131                 max_width,
132                 max_height,
133             } = parsed_format;
134 
135             output_format_descs.push(FormatDesc {
136                 mask: !(u64::MAX << output_formats.len()),
137                 format,
138                 frame_formats: vec![FrameFormat {
139                     width: FormatRange {
140                         min: 2,
141                         max: max_width,
142                         step: 1,
143                     },
144                     height: FormatRange {
145                         min: 2,
146                         max: max_height,
147                         step: 1,
148                     },
149                     bitrates: vec![FormatRange {
150                         min: 0,
151                         max: 8000,
152                         step: 1,
153                     }],
154                 }],
155             });
156 
157             profiles.sort_unstable();
158             coded_format_profiles.insert(format, profiles);
159         }
160 
161         Ok(LibvdaEncoder {
162             instance,
163             capabilities: EncoderCapabilities {
164                 input_format_descs,
165                 output_format_descs,
166                 coded_format_profiles,
167             },
168         })
169     }
170 }
171 
172 impl<'a> Encoder for &'a LibvdaEncoder {
173     type Session = LibvdaEncoderSession<'a>;
174 
query_capabilities(&self) -> Result<EncoderCapabilities>175     fn query_capabilities(&self) -> Result<EncoderCapabilities> {
176         Ok(self.capabilities.clone())
177     }
178 
start_session(&mut self, config: SessionConfig) -> Result<LibvdaEncoderSession<'a>>179     fn start_session(&mut self, config: SessionConfig) -> Result<LibvdaEncoderSession<'a>> {
180         if config.dst_params.format.is_none() {
181             return Err(EncoderError::InvalidArgument);
182         }
183 
184         let input_format = match config
185             .src_params
186             .format
187             .ok_or(EncoderError::InvalidArgument)?
188         {
189             Format::NV12 => libvda::PixelFormat::NV12,
190             Format::YUV420 => libvda::PixelFormat::YV12,
191             unsupported_format => {
192                 error!("Unsupported libvda format: {}", unsupported_format);
193                 return Err(EncoderError::InvalidArgument);
194             }
195         };
196 
197         let output_profile = match config.dst_profile.to_libvda_profile() {
198             Some(p) => p,
199             None => {
200                 error!("Unsupported libvda profile");
201                 return Err(EncoderError::InvalidArgument);
202             }
203         };
204 
205         let config = libvda::encode::Config {
206             input_format,
207             input_visible_width: config.src_params.frame_width,
208             input_visible_height: config.src_params.frame_height,
209             output_profile,
210             initial_bitrate: config.dst_bitrate,
211             initial_framerate: if config.frame_rate == 0 {
212                 None
213             } else {
214                 Some(config.frame_rate)
215             },
216             h264_output_level: config.dst_h264_level.map(|level| {
217                 // This value is aligned to the H264 standard definition of SPS.level_idc.
218                 match level {
219                     Level::H264_1_0 => 10,
220                     Level::H264_1_1 => 11,
221                     Level::H264_1_2 => 12,
222                     Level::H264_1_3 => 13,
223                     Level::H264_2_0 => 20,
224                     Level::H264_2_1 => 21,
225                     Level::H264_2_2 => 22,
226                     Level::H264_3_0 => 30,
227                     Level::H264_3_1 => 31,
228                     Level::H264_3_2 => 32,
229                     Level::H264_4_0 => 40,
230                     Level::H264_4_1 => 41,
231                     Level::H264_4_2 => 42,
232                     Level::H264_5_0 => 50,
233                     Level::H264_5_1 => 51,
234                 }
235             }),
236         };
237 
238         let session = self
239             .instance
240             .open_session(config)
241             .map_err(|e| EncoderError::Implementation(Box::new(e)))?;
242 
243         Ok(LibvdaEncoderSession {
244             session,
245             next_input_buffer_id: 1,
246             next_output_buffer_id: 1,
247         })
248     }
249 
stop_session(&mut self, _session: LibvdaEncoderSession) -> Result<()>250     fn stop_session(&mut self, _session: LibvdaEncoderSession) -> Result<()> {
251         // Resources will be freed when `_session` is dropped.
252         Ok(())
253     }
254 }
255 
256 pub struct LibvdaEncoderSession<'a> {
257     session: libvda::encode::Session<'a>,
258     next_input_buffer_id: InputBufferId,
259     next_output_buffer_id: OutputBufferId,
260 }
261 
262 impl<'a> EncoderSession for LibvdaEncoderSession<'a> {
encode( &mut self, resource: File, planes: &[VideoFramePlane], timestamp: u64, force_keyframe: bool, ) -> Result<InputBufferId>263     fn encode(
264         &mut self,
265         resource: File,
266         planes: &[VideoFramePlane],
267         timestamp: u64,
268         force_keyframe: bool,
269     ) -> Result<InputBufferId> {
270         let input_buffer_id = self.next_input_buffer_id;
271 
272         let libvda_planes = planes
273             .iter()
274             .map(|plane| libvda::FramePlane {
275                 offset: plane.offset as i32,
276                 stride: plane.stride as i32,
277             })
278             .collect::<Vec<_>>();
279 
280         self.session
281             .encode(
282                 input_buffer_id as i32,
283                 resource.into_raw_descriptor(),
284                 &libvda_planes,
285                 timestamp as i64,
286                 force_keyframe,
287             )
288             .map_err(|e| EncoderError::Implementation(Box::new(e)))?;
289 
290         self.next_input_buffer_id = self.next_input_buffer_id.wrapping_add(1);
291 
292         Ok(input_buffer_id)
293     }
294 
use_output_buffer(&mut self, file: File, offset: u32, size: u32) -> Result<OutputBufferId>295     fn use_output_buffer(&mut self, file: File, offset: u32, size: u32) -> Result<OutputBufferId> {
296         let output_buffer_id = self.next_output_buffer_id;
297         self.next_output_buffer_id = self.next_output_buffer_id.wrapping_add(1);
298 
299         self.session
300             .use_output_buffer(
301                 output_buffer_id as i32,
302                 file.into_raw_descriptor(),
303                 offset,
304                 size,
305             )
306             .map_err(|e| EncoderError::Implementation(Box::new(e)))?;
307 
308         Ok(output_buffer_id)
309     }
310 
flush(&mut self) -> Result<()>311     fn flush(&mut self) -> Result<()> {
312         self.session
313             .flush()
314             .map_err(|e| EncoderError::Implementation(Box::new(e)))
315     }
316 
request_encoding_params_change(&mut self, bitrate: u32, framerate: u32) -> Result<()>317     fn request_encoding_params_change(&mut self, bitrate: u32, framerate: u32) -> Result<()> {
318         self.session
319             .request_encoding_params_change(bitrate, framerate)
320             .map_err(|e| EncoderError::Implementation(Box::new(e)))
321     }
322 
event_pipe(&self) -> &File323     fn event_pipe(&self) -> &File {
324         self.session.pipe()
325     }
326 
read_event(&mut self) -> Result<EncoderEvent>327     fn read_event(&mut self) -> Result<EncoderEvent> {
328         let event = self
329             .session
330             .read_event()
331             .map_err(|e| EncoderError::Implementation(Box::new(e)))?;
332 
333         use libvda::encode::Event::*;
334         let encoder_event = match event {
335             RequireInputBuffers {
336                 input_count,
337                 input_frame_width,
338                 input_frame_height,
339                 output_buffer_size,
340             } => EncoderEvent::RequireInputBuffers {
341                 input_count,
342                 input_frame_width,
343                 input_frame_height,
344                 output_buffer_size,
345             },
346             ProcessedInputBuffer(id) => EncoderEvent::ProcessedInputBuffer { id: id as u32 },
347             ProcessedOutputBuffer {
348                 output_buffer_id,
349                 payload_size,
350                 key_frame,
351                 timestamp,
352                 ..
353             } => EncoderEvent::ProcessedOutputBuffer {
354                 id: output_buffer_id as u32,
355                 bytesused: payload_size,
356                 keyframe: key_frame,
357                 timestamp: timestamp as u64,
358             },
359             FlushResponse { flush_done } => EncoderEvent::FlushResponse { flush_done },
360             NotifyError(err) => EncoderEvent::NotifyError {
361                 error: EncoderError::Implementation(Box::new(err)),
362             },
363         };
364 
365         Ok(encoder_event)
366     }
367 }
368