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