1 // Copyright 2022 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 #![deny(missing_docs)] 6 7 use std::collections::btree_map::Entry; 8 use std::collections::BTreeMap; 9 use std::collections::VecDeque; 10 use std::os::fd::FromRawFd; 11 use std::os::fd::OwnedFd; 12 use std::rc::Rc; 13 14 use anyhow::anyhow; 15 use anyhow::Result; 16 use base::IntoRawDescriptor; 17 use base::MappedRegion; 18 use base::MemoryMappingArena; 19 use cros_codecs::decoder::stateless::h264::H264; 20 use cros_codecs::decoder::stateless::h265::H265; 21 use cros_codecs::decoder::stateless::vp8::Vp8; 22 use cros_codecs::decoder::stateless::vp9::Vp9; 23 use cros_codecs::decoder::stateless::DecodeError; 24 use cros_codecs::decoder::stateless::StatelessVideoDecoder; 25 use cros_codecs::decoder::DecodedHandle; 26 use cros_codecs::libva; 27 use cros_codecs::libva::Display; 28 use cros_codecs::multiple_desc_type; 29 use cros_codecs::utils::DmabufFrame; 30 use cros_codecs::DecodedFormat; 31 use cros_codecs::FrameLayout; 32 use cros_codecs::PlaneLayout; 33 34 use crate::virtio::video::decoder::Capability; 35 use crate::virtio::video::decoder::DecoderBackend; 36 use crate::virtio::video::decoder::DecoderEvent; 37 use crate::virtio::video::decoder::DecoderSession; 38 use crate::virtio::video::error::VideoError; 39 use crate::virtio::video::error::VideoResult; 40 use crate::virtio::video::format::Format; 41 use crate::virtio::video::format::FormatDesc; 42 use crate::virtio::video::format::FormatRange; 43 use crate::virtio::video::format::FrameFormat; 44 use crate::virtio::video::format::Level; 45 use crate::virtio::video::format::Profile; 46 use crate::virtio::video::format::Rect; 47 use crate::virtio::video::resource::BufferHandle; 48 use crate::virtio::video::resource::GuestMemHandle; 49 use crate::virtio::video::resource::GuestResource; 50 use crate::virtio::video::resource::GuestResourceHandle; 51 use crate::virtio::video::utils::EventQueue; 52 53 /// A guest memory descriptor that uses a managed buffer as a shadow that will be copied into the 54 /// guest memory once decoding is over. 55 struct GuestMemDescriptor(GuestMemHandle); 56 57 impl libva::SurfaceMemoryDescriptor for GuestMemDescriptor { add_attrs( &mut self, attrs: &mut Vec<libva::VASurfaceAttrib>, ) -> Option<Box<dyn std::any::Any>>58 fn add_attrs( 59 &mut self, 60 attrs: &mut Vec<libva::VASurfaceAttrib>, 61 ) -> Option<Box<dyn std::any::Any>> { 62 // Decode into a managed buffer. 63 ().add_attrs(attrs) 64 } 65 } 66 67 multiple_desc_type! { 68 enum BufferDescriptor { 69 GuestMem(GuestMemDescriptor), 70 Dmabuf(DmabufFrame), 71 } 72 } 73 74 struct BufferDescWithPicId { 75 desc: BufferDescriptor, 76 picture_buffer_id: i32, 77 } 78 79 impl libva::SurfaceMemoryDescriptor for BufferDescWithPicId { add_attrs( &mut self, attrs: &mut Vec<libva::VASurfaceAttrib>, ) -> Option<Box<dyn std::any::Any>>80 fn add_attrs( 81 &mut self, 82 attrs: &mut Vec<libva::VASurfaceAttrib>, 83 ) -> Option<Box<dyn std::any::Any>> { 84 self.desc.add_attrs(attrs) 85 } 86 } 87 88 /// Represents a buffer we have not yet sent to the accelerator. 89 struct PendingJob { 90 resource_id: u32, 91 timestamp: u64, 92 resource: GuestResourceHandle, 93 offset: usize, 94 bytes_used: usize, 95 remaining: usize, 96 } 97 98 impl TryFrom<DecodedFormat> for Format { 99 type Error = anyhow::Error; 100 try_from(value: DecodedFormat) -> Result<Self, Self::Error>101 fn try_from(value: DecodedFormat) -> Result<Self, Self::Error> { 102 match value { 103 DecodedFormat::NV12 => Ok(Format::NV12), 104 _ => Err(anyhow!("Unsupported format")), 105 } 106 } 107 } 108 109 impl TryFrom<Format> for DecodedFormat { 110 type Error = anyhow::Error; 111 try_from(value: Format) -> Result<Self, Self::Error>112 fn try_from(value: Format) -> Result<Self, Self::Error> { 113 match value { 114 Format::NV12 => Ok(DecodedFormat::NV12), 115 _ => Err(anyhow!("Unsupported format")), 116 } 117 } 118 } 119 120 impl TryFrom<libva::VAProfile::Type> for Profile { 121 type Error = anyhow::Error; 122 try_from(value: libva::VAProfile::Type) -> Result<Self, Self::Error>123 fn try_from(value: libva::VAProfile::Type) -> Result<Self, Self::Error> { 124 match value { 125 libva::VAProfile::VAProfileH264Baseline => Ok(Self::H264Baseline), 126 libva::VAProfile::VAProfileH264Main => Ok(Self::H264Main), 127 libva::VAProfile::VAProfileH264High => Ok(Self::H264High), 128 libva::VAProfile::VAProfileH264StereoHigh => Ok(Self::H264StereoHigh), 129 libva::VAProfile::VAProfileH264MultiviewHigh => Ok(Self::H264MultiviewHigh), 130 libva::VAProfile::VAProfileHEVCMain => Ok(Self::HevcMain), 131 libva::VAProfile::VAProfileHEVCMain10 => Ok(Self::HevcMain10), 132 libva::VAProfile::VAProfileVP8Version0_3 => Ok(Self::VP8Profile0), 133 libva::VAProfile::VAProfileVP9Profile0 => Ok(Self::VP9Profile0), 134 libva::VAProfile::VAProfileVP9Profile1 => Ok(Self::VP9Profile1), 135 libva::VAProfile::VAProfileVP9Profile2 => Ok(Self::VP9Profile2), 136 libva::VAProfile::VAProfileVP9Profile3 => Ok(Self::VP9Profile3), 137 _ => Err(anyhow!( 138 "Conversion failed for unexpected VAProfile: {}", 139 value 140 )), 141 } 142 } 143 } 144 145 /// The state for the output queue containing the buffers that will receive the 146 /// decoded data. 147 enum OutputQueueState { 148 /// Waiting for the client to call `set_output_buffer_count`. 149 AwaitingBufferCount, 150 /// Codec is capable of decoding frames. 151 Decoding, 152 /// Dynamic Resolution Change - we can still accept buffers in the old 153 /// format, but are waiting for new parameters before doing any decoding. 154 Drc, 155 } 156 157 ///A safe decoder abstraction over libva for a single vaContext 158 pub struct VaapiDecoder { 159 /// The capabilities for the decoder 160 caps: Capability, 161 } 162 163 // The VA capabilities for the coded side 164 struct CodedCap { 165 profile: libva::VAProfile::Type, 166 max_width: u32, 167 max_height: u32, 168 } 169 170 // The VA capabilities for the raw side 171 struct RawCap { 172 fourcc: u32, 173 min_width: u32, 174 min_height: u32, 175 max_width: u32, 176 max_height: u32, 177 } 178 179 impl VaapiDecoder { 180 // Query the capabilities for the coded format get_coded_cap( display: &libva::Display, profile: libva::VAProfile::Type, ) -> Result<CodedCap>181 fn get_coded_cap( 182 display: &libva::Display, 183 profile: libva::VAProfile::Type, 184 ) -> Result<CodedCap> { 185 let mut attrs = vec![ 186 libva::VAConfigAttrib { 187 type_: libva::VAConfigAttribType::VAConfigAttribMaxPictureWidth, 188 value: 0, 189 }, 190 libva::VAConfigAttrib { 191 type_: libva::VAConfigAttribType::VAConfigAttribMaxPictureHeight, 192 value: 0, 193 }, 194 ]; 195 196 display.get_config_attributes(profile, libva::VAEntrypoint::VAEntrypointVLD, &mut attrs)?; 197 198 let mut max_width = 1u32; 199 let mut max_height = 1u32; 200 201 for attr in &attrs { 202 if attr.value == libva::constants::VA_ATTRIB_NOT_SUPPORTED { 203 continue; 204 } 205 206 match attr.type_ { 207 libva::VAConfigAttribType::VAConfigAttribMaxPictureWidth => max_width = attr.value, 208 libva::VAConfigAttribType::VAConfigAttribMaxPictureHeight => { 209 max_height = attr.value 210 } 211 212 _ => panic!("Unexpected VAConfigAttribType {}", attr.type_), 213 } 214 } 215 216 Ok(CodedCap { 217 profile, 218 max_width, 219 max_height, 220 }) 221 } 222 223 // Query the capabilities for the raw format get_raw_caps(display: Rc<libva::Display>, coded_cap: &CodedCap) -> Result<Vec<RawCap>>224 fn get_raw_caps(display: Rc<libva::Display>, coded_cap: &CodedCap) -> Result<Vec<RawCap>> { 225 let mut raw_caps = Vec::new(); 226 227 let mut config = display.create_config( 228 vec![], 229 coded_cap.profile, 230 libva::VAEntrypoint::VAEntrypointVLD, 231 )?; 232 233 let fourccs = config.query_surface_attributes_by_type( 234 libva::VASurfaceAttribType::VASurfaceAttribPixelFormat, 235 )?; 236 237 for fourcc in fourccs { 238 let fourcc = match fourcc { 239 libva::GenericValue::Integer(i) => i as u32, 240 other => panic!("Unexpected VAGenericValue {:?}", other), 241 }; 242 243 let min_width = config.query_surface_attributes_by_type( 244 libva::VASurfaceAttribType::VASurfaceAttribMinWidth, 245 )?; 246 247 let min_width = match min_width.first() { 248 Some(libva::GenericValue::Integer(i)) => *i as u32, 249 Some(other) => panic!("Unexpected VAGenericValue {:?}", other), 250 None => 1, 251 }; 252 253 let min_height = config.query_surface_attributes_by_type( 254 libva::VASurfaceAttribType::VASurfaceAttribMinHeight, 255 )?; 256 let min_height = match min_height.first() { 257 Some(libva::GenericValue::Integer(i)) => *i as u32, 258 Some(other) => panic!("Unexpected VAGenericValue {:?}", other), 259 None => 1, 260 }; 261 262 let max_width = config.query_surface_attributes_by_type( 263 libva::VASurfaceAttribType::VASurfaceAttribMaxWidth, 264 )?; 265 let max_width = match max_width.first() { 266 Some(libva::GenericValue::Integer(i)) => *i as u32, 267 Some(other) => panic!("Unexpected VAGenericValue {:?}", other), 268 None => coded_cap.max_width, 269 }; 270 271 let max_height = config.query_surface_attributes_by_type( 272 libva::VASurfaceAttribType::VASurfaceAttribMaxHeight, 273 )?; 274 let max_height = match max_height.first() { 275 Some(libva::GenericValue::Integer(i)) => *i as u32, 276 Some(other) => panic!("Unexpected VAGenericValue {:?}", other), 277 None => coded_cap.max_height, 278 }; 279 280 raw_caps.push(RawCap { 281 fourcc, 282 min_width, 283 min_height, 284 max_width, 285 max_height, 286 }); 287 } 288 289 Ok(raw_caps) 290 } 291 292 /// Creates a new instance of the Vaapi decoder. new() -> Result<Self>293 pub fn new() -> Result<Self> { 294 let display = libva::Display::open().ok_or_else(|| anyhow!("failed to open VA display"))?; 295 296 let va_profiles = display.query_config_profiles()?; 297 298 let mut in_fmts = Vec::new(); 299 let mut out_fmts = Vec::new(); 300 let mut profiles_map: BTreeMap<Format, Vec<Profile>> = Default::default(); 301 302 // VA has no API for querying the levels supported by the driver. 303 // vaQueryProcessingRate is close, but not quite a solution here 304 // for all codecs. 305 let levels: BTreeMap<Format, Vec<Level>> = Default::default(); 306 307 for va_profile in va_profiles { 308 let mut profiles = Vec::new(); 309 310 let entrypoints = display.query_config_entrypoints(va_profile)?; 311 if !entrypoints 312 .iter() 313 .any(|e| *e == libva::VAEntrypoint::VAEntrypointVLD) 314 { 315 // All formats we are aiming to support require 316 // VAEntrypointVLD. 317 continue; 318 } 319 320 let profile = match Profile::try_from(va_profile) { 321 Ok(p) => p, 322 // Skip if we cannot convert to a valid virtio format 323 Err(_) => continue, 324 }; 325 326 // Manually push all VP8 profiles, since VA exposes only a single 327 // VP8 profile for all of these 328 if va_profile == libva::VAProfile::VAProfileVP8Version0_3 { 329 profiles.push(Profile::VP8Profile0); 330 profiles.push(Profile::VP8Profile1); 331 profiles.push(Profile::VP8Profile2); 332 profiles.push(Profile::VP8Profile3); 333 } else { 334 profiles.push(profile); 335 } 336 337 let coded_cap = VaapiDecoder::get_coded_cap(display.as_ref(), va_profile)?; 338 let raw_caps = VaapiDecoder::get_raw_caps(Rc::clone(&display), &coded_cap)?; 339 340 let coded_frame_fmt = FrameFormat { 341 width: FormatRange { 342 min: 1, 343 max: coded_cap.max_width, 344 step: 1, 345 }, 346 347 height: FormatRange { 348 min: 1, 349 max: coded_cap.max_height, 350 step: 1, 351 }, 352 353 bitrates: Default::default(), 354 }; 355 356 let coded_format = profile.to_format(); 357 match profiles_map.entry(coded_format) { 358 Entry::Vacant(e) => { 359 e.insert(profiles); 360 } 361 Entry::Occupied(mut ps) => { 362 ps.get_mut().push(profile); 363 } 364 } 365 366 let mut n_out = 0; 367 for raw_cap in raw_caps { 368 if raw_cap.fourcc != libva::constants::VA_FOURCC_NV12 { 369 // Apparently only NV12 is currently supported by virtio video 370 continue; 371 } 372 373 let raw_frame_fmt = FrameFormat { 374 width: FormatRange { 375 min: raw_cap.min_width, 376 max: raw_cap.max_width, 377 step: 1, 378 }, 379 380 height: FormatRange { 381 min: raw_cap.min_height, 382 max: raw_cap.max_height, 383 step: 1, 384 }, 385 386 bitrates: Default::default(), 387 }; 388 389 out_fmts.push(FormatDesc { 390 mask: 0, 391 format: Format::NV12, 392 frame_formats: vec![raw_frame_fmt], 393 plane_align: 1, 394 }); 395 396 n_out += 1; 397 } 398 399 let mask = !(u64::MAX << n_out) << (out_fmts.len() - n_out); 400 401 if mask != 0 { 402 in_fmts.push(FormatDesc { 403 mask, 404 format: coded_format, 405 frame_formats: vec![coded_frame_fmt], 406 plane_align: 1, 407 }); 408 } 409 } 410 411 Ok(Self { 412 caps: Capability::new(in_fmts, out_fmts, profiles_map, levels), 413 }) 414 } 415 } 416 417 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] 418 pub struct Resolution { 419 width: u32, 420 height: u32, 421 } 422 423 trait AsBufferHandle { 424 type BufferHandle: BufferHandle; as_buffer_handle(&self) -> &Self::BufferHandle425 fn as_buffer_handle(&self) -> &Self::BufferHandle; 426 } 427 428 impl AsBufferHandle for GuestResource { 429 type BufferHandle = GuestResourceHandle; 430 as_buffer_handle(&self) -> &Self::BufferHandle431 fn as_buffer_handle(&self) -> &Self::BufferHandle { 432 &self.handle 433 } 434 } 435 436 impl AsBufferHandle for GuestMemHandle { 437 type BufferHandle = Self; 438 as_buffer_handle(&self) -> &Self::BufferHandle439 fn as_buffer_handle(&self) -> &Self::BufferHandle { 440 self 441 } 442 } 443 444 impl AsBufferHandle for GuestResourceHandle { 445 type BufferHandle = Self; 446 as_buffer_handle(&self) -> &Self::BufferHandle447 fn as_buffer_handle(&self) -> &Self::BufferHandle { 448 self 449 } 450 } 451 452 /// A convenience type implementing persistent slice access for BufferHandles. 453 struct BufferMapping<'a, T: AsBufferHandle> { 454 #[allow(dead_code)] 455 /// The underlying resource. Must be kept so as not to drop the BufferHandle 456 resource: &'a T, 457 /// The mapping that backs the underlying slices returned by AsRef and AsMut 458 mapping: MemoryMappingArena, 459 } 460 461 impl<'a, T: AsBufferHandle> BufferMapping<'a, T> { 462 /// Creates a new BufferMap new(resource: &'a T, offset: usize, size: usize) -> Result<Self>463 pub fn new(resource: &'a T, offset: usize, size: usize) -> Result<Self> { 464 let mapping = resource.as_buffer_handle().get_mapping(offset, size)?; 465 466 Ok(Self { resource, mapping }) 467 } 468 } 469 470 impl<'a, T: AsBufferHandle> AsRef<[u8]> for BufferMapping<'a, T> { as_ref(&self) -> &[u8]471 fn as_ref(&self) -> &[u8] { 472 let mapping = &self.mapping; 473 // SAFETY: 474 // Safe because the mapping is linear and we own it, so it will not be unmapped during 475 // the lifetime of this slice. 476 unsafe { std::slice::from_raw_parts(mapping.as_ptr(), mapping.size()) } 477 } 478 } 479 480 impl<'a, T: AsBufferHandle> AsMut<[u8]> for BufferMapping<'a, T> { as_mut(&mut self) -> &mut [u8]481 fn as_mut(&mut self) -> &mut [u8] { 482 let mapping = &self.mapping; 483 // SAFETY: 484 // Safe because the mapping is linear and we own it, so it will not be unmapped during 485 // the lifetime of this slice. 486 unsafe { std::slice::from_raw_parts_mut(mapping.as_ptr(), mapping.size()) } 487 } 488 } 489 490 /// A frame that is currently not available for being decoded into, either because it has been 491 /// decoded and is waiting for us to release it (`Decoded`), or because we temporarily removed it 492 /// from the decoder pool after a reset and are waiting for the client to tell us we can use it 493 /// (`Held`). 494 #[allow(dead_code)] // TODO: b/344974550 495 enum BorrowedFrame { 496 Decoded(Box<dyn DecodedHandle<Descriptor = BufferDescWithPicId>>), 497 Held(Box<dyn AsRef<BufferDescWithPicId>>), 498 } 499 500 /// A decoder session for the libva backend 501 pub struct VaapiDecoderSession { 502 /// The implementation for the codec specific logic. 503 codec: Box<dyn StatelessVideoDecoder<BufferDescWithPicId>>, 504 /// The state for the output queue. Updated when `set_output_buffer_count` 505 /// is called or when we detect a dynamic resolution change. 506 output_queue_state: OutputQueueState, 507 /// Frames currently held by us, indexed by `picture_buffer_id`. 508 held_frames: BTreeMap<i32, BorrowedFrame>, 509 /// Queue containing the buffers we have not yet submitted to the codec. 510 submit_queue: VecDeque<PendingJob>, 511 /// The event queue we can use to signal new events. 512 event_queue: EventQueue<DecoderEvent>, 513 /// Whether the decoder is currently flushing. 514 flushing: bool, 515 } 516 517 impl VaapiDecoderSession { 518 /// Copy raw decoded data from `image` into the output buffer output_picture( decoded_frame: &dyn DecodedHandle<Descriptor = BufferDescWithPicId>, event_queue: &mut EventQueue<DecoderEvent>, ) -> Result<()>519 fn output_picture( 520 decoded_frame: &dyn DecodedHandle<Descriptor = BufferDescWithPicId>, 521 event_queue: &mut EventQueue<DecoderEvent>, 522 ) -> Result<()> { 523 let timestamp = decoded_frame.timestamp(); 524 525 let buffer_desc = decoded_frame.resource(); 526 let picture_buffer_id = buffer_desc.picture_buffer_id; 527 528 // Sync the frame if it is in guest memory, as we are going to map and read it. 529 // This statement is in its own block so we can drop the `buffer_desc` reference 530 // before calling `sync`, which does a mutable borrow. 531 if let BufferDescriptor::GuestMem(_) = &buffer_desc.desc { 532 drop(buffer_desc); 533 decoded_frame.sync()?; 534 } 535 536 // Copy guest memory buffers into their destination. 537 if let BufferDescriptor::GuestMem(handle) = &decoded_frame.resource().desc { 538 let picture = decoded_frame.dyn_picture(); 539 let mut backend_handle = picture.dyn_mappable_handle()?; 540 let buffer_size = backend_handle.image_size(); 541 542 // Get a mapping from the start of the buffer to the size of the 543 // underlying decoded data in the Image. 544 let mut output_map = BufferMapping::new(&handle.0, 0, buffer_size)?; 545 let output_bytes = output_map.as_mut(); 546 547 backend_handle.read(output_bytes)?; 548 } 549 550 // Say that we are done decoding this picture. 551 event_queue 552 .queue_event(DecoderEvent::PictureReady { 553 picture_buffer_id, 554 timestamp, 555 }) 556 .map_err(|e| { 557 VideoError::BackendFailure(anyhow!("Can't queue the PictureReady event {}", e)) 558 })?; 559 560 Ok(()) 561 } 562 try_emit_flush_completed(&mut self) -> Result<()>563 fn try_emit_flush_completed(&mut self) -> Result<()> { 564 if self.submit_queue.is_empty() { 565 self.flushing = false; 566 567 let event_queue = &mut self.event_queue; 568 569 event_queue 570 .queue_event(DecoderEvent::FlushCompleted(Ok(()))) 571 .map_err(|e| anyhow!("Can't queue the PictureReady event {}", e)) 572 } else { 573 Ok(()) 574 } 575 } 576 drain_submit_queue(&mut self) -> VideoResult<()>577 fn drain_submit_queue(&mut self) -> VideoResult<()> { 578 while let Some(job) = self.submit_queue.front_mut() { 579 let bitstream_map = BufferMapping::new(&job.resource, job.offset, job.bytes_used) 580 .map_err(VideoError::BackendFailure)?; 581 582 let slice_start = job.bytes_used - job.remaining; 583 match self 584 .codec 585 .decode(job.timestamp, &bitstream_map.as_ref()[slice_start..]) 586 { 587 Ok(processed) => { 588 job.remaining = job.remaining.saturating_sub(processed); 589 // We have completed the buffer. 590 if job.remaining == 0 { 591 // We are always done with the input buffer after decode returns. 592 self.event_queue 593 .queue_event(DecoderEvent::NotifyEndOfBitstreamBuffer(job.resource_id)) 594 .map_err(|e| { 595 VideoError::BackendFailure(anyhow!( 596 "Can't queue the NotifyEndOfBitstream event {}", 597 e 598 )) 599 })?; 600 self.submit_queue.pop_front(); 601 } 602 } 603 Err(DecodeError::CheckEvents) => { 604 self.process_decoder_events()?; 605 break; 606 } 607 // We will succeed once buffers are returned by the client. This could be optimized 608 // to only retry decoding once buffers are effectively returned. 609 Err(DecodeError::NotEnoughOutputBuffers(_)) => break, 610 // TODO add an InvalidInput error to cros-codecs so we can detect these cases and 611 // just throw a warning instead of a fatal error? 612 Err(e) => { 613 self.event_queue 614 .queue_event(DecoderEvent::NotifyError(VideoError::BackendFailure( 615 anyhow!("Decoding buffer {} failed", job.resource_id), 616 ))) 617 .map_err(|e| { 618 VideoError::BackendFailure(anyhow!( 619 "Can't queue the NotifyError event {}", 620 e 621 )) 622 })?; 623 return Err(VideoError::BackendFailure(e.into())); 624 } 625 } 626 } 627 628 Ok(()) 629 } 630 process_decoder_events(&mut self) -> VideoResult<()>631 fn process_decoder_events(&mut self) -> VideoResult<()> { 632 while let Some(event) = self.codec.next_event() { 633 match event { 634 cros_codecs::decoder::DecoderEvent::FrameReady(frame) => { 635 Self::output_picture(frame.as_ref(), &mut self.event_queue) 636 .map_err(VideoError::BackendFailure)?; 637 let picture_id = frame.resource().picture_buffer_id; 638 self.held_frames 639 .insert(picture_id, BorrowedFrame::Decoded(frame)); 640 } 641 cros_codecs::decoder::DecoderEvent::FormatChanged(mut format) => { 642 let coded_resolution = format.stream_info().coded_resolution; 643 let display_resolution = format.stream_info().display_resolution; 644 645 // Ask the client for new buffers. 646 self.event_queue 647 .queue_event(DecoderEvent::ProvidePictureBuffers { 648 min_num_buffers: format.stream_info().min_num_frames as u32, 649 width: coded_resolution.width as i32, 650 height: coded_resolution.height as i32, 651 visible_rect: Rect { 652 left: 0, 653 top: 0, 654 right: display_resolution.width as i32, 655 bottom: display_resolution.height as i32, 656 }, 657 }) 658 .map_err(|e| VideoError::BackendFailure(e.into()))?; 659 660 format.frame_pool().clear(); 661 662 // Drop our output queue and wait for the new number of output buffers. 663 self.output_queue_state = match &self.output_queue_state { 664 // If this is part of the initialization step, then do not switch states. 665 OutputQueueState::AwaitingBufferCount => { 666 OutputQueueState::AwaitingBufferCount 667 } 668 OutputQueueState::Decoding => OutputQueueState::Drc, 669 OutputQueueState::Drc => { 670 return Err(VideoError::BackendFailure(anyhow!( 671 "Invalid state during DRC." 672 ))) 673 } 674 }; 675 } 676 } 677 } 678 679 Ok(()) 680 } 681 try_make_progress(&mut self) -> VideoResult<()>682 fn try_make_progress(&mut self) -> VideoResult<()> { 683 self.process_decoder_events()?; 684 self.drain_submit_queue()?; 685 686 Ok(()) 687 } 688 } 689 690 impl DecoderSession for VaapiDecoderSession { set_output_parameters(&mut self, _: usize, _: Format) -> VideoResult<()>691 fn set_output_parameters(&mut self, _: usize, _: Format) -> VideoResult<()> { 692 let output_queue_state = &mut self.output_queue_state; 693 694 // This logic can still be improved, in particular it needs better 695 // support at the virtio-video protocol level. 696 // 697 // We must ensure that set_output_parameters is only called after we are 698 // sure that we have processed some stream metadata, which currently is 699 // not the case. In particular, the {SET|GET}_PARAMS logic currently 700 // takes place *before* we had a chance to parse any stream metadata at 701 // all. 702 // 703 // This can lead to a situation where we accept a format (say, NV12), 704 // but then discover we are unable to decode it after processing some 705 // buffers (because the stream indicates that the bit depth is 10, for 706 // example). Note that there is no way to reject said stream as of right 707 // now unless we hardcode NV12 in cros-codecs itself. 708 // 709 // Nevertheless, the support is already in place in cros-codecs: the 710 // decoders will queue buffers until they read some metadata. At this 711 // point, it will allow for the negotiation of the decoded format until 712 // a new call to decode() is made. At the crosvm level, we can use this 713 // window of time to try different decoded formats with .try_format(). 714 // 715 // For now, we accept the default format chosen by cros-codecs instead. 716 // In practice, this means NV12 if it the stream can be decoded into 717 // NV12 and if the hardware can do so. 718 719 match output_queue_state { 720 OutputQueueState::AwaitingBufferCount | OutputQueueState::Drc => { 721 // Accept the default format chosen by cros-codecs instead. 722 // 723 // if let Some(backend_format) = self.backend.backend().format() { 724 // let backend_format = Format::try_from(backend_format); 725 726 // let format_matches = match backend_format { 727 // Ok(backend_format) => backend_format != format, 728 // Err(_) => false, 729 // }; 730 731 // if !format_matches { 732 // let format = 733 // DecodedFormat::try_from(format).map_err(VideoError::BackendFailure)?; 734 735 // self.backend.backend().try_format(format).map_err(|e| { 736 // VideoError::BackendFailure(anyhow!( 737 // "Failed to set the codec backend format: {}", 738 // e 739 // )) 740 // })?; 741 // } 742 // } 743 744 *output_queue_state = OutputQueueState::Decoding; 745 746 Ok(()) 747 } 748 OutputQueueState::Decoding => { 749 // Covers the slightly awkward ffmpeg v4l2 stateful 750 // implementation for the capture queue setup. 751 // 752 // ffmpeg will queue a single OUTPUT buffer and immediately 753 // follow up with a VIDIOC_G_FMT call on the CAPTURE queue. 754 // This leads to a race condition, because it takes some 755 // appreciable time for the real resolution to propagate back to 756 // the guest as the virtio machinery processes and delivers the 757 // event. 758 // 759 // In the event that VIDIOC_G_FMT(capture) returns the default 760 // format, ffmpeg allocates buffers of the default resolution 761 // (640x480) only to immediately reallocate as soon as it 762 // processes the SRC_CH v4l2 event. Otherwise (if the resolution 763 // has propagated in time), this path will not be taken during 764 // the initialization. 765 // 766 // This leads to the following workflow in the virtio video 767 // worker: 768 // RESOURCE_QUEUE -> QUEUE_CLEAR -> RESOURCE_QUEUE 769 // 770 // Failing to accept this (as we previously did), leaves us 771 // with bad state and completely breaks the decoding process. We 772 // should replace the queue even if this is not 100% according 773 // to spec. 774 // 775 // On the other hand, this branch still exists to highlight the 776 // fact that we should assert that we have emitted a buffer with 777 // the LAST flag when support for buffer flags is implemented in 778 // a future CL. If a buffer with the LAST flag hasn't been 779 // emitted, it's technically a mistake to be here because we 780 // still have buffers of the old resolution to deliver. 781 *output_queue_state = OutputQueueState::Decoding; 782 783 // TODO: check whether we have emitted a buffer with the LAST 784 // flag before returning. 785 Ok(()) 786 } 787 } 788 } 789 decode( &mut self, resource_id: u32, timestamp: u64, resource: GuestResourceHandle, offset: u32, bytes_used: u32, ) -> VideoResult<()>790 fn decode( 791 &mut self, 792 resource_id: u32, 793 timestamp: u64, 794 resource: GuestResourceHandle, 795 offset: u32, 796 bytes_used: u32, 797 ) -> VideoResult<()> { 798 let job = PendingJob { 799 resource_id, 800 timestamp, 801 resource, 802 offset: offset as usize, 803 bytes_used: bytes_used as usize, 804 remaining: bytes_used as usize, 805 }; 806 807 self.submit_queue.push_back(job); 808 self.try_make_progress()?; 809 810 Ok(()) 811 } 812 flush(&mut self) -> VideoResult<()>813 fn flush(&mut self) -> VideoResult<()> { 814 self.flushing = true; 815 816 self.try_make_progress()?; 817 818 if !self.submit_queue.is_empty() { 819 return Ok(()); 820 } 821 822 // Retrieve ready frames from the codec, if any. 823 self.codec 824 .flush() 825 .map_err(|e| VideoError::BackendFailure(e.into()))?; 826 self.process_decoder_events()?; 827 828 self.try_emit_flush_completed() 829 .map_err(VideoError::BackendFailure) 830 } 831 reset(&mut self) -> VideoResult<()>832 fn reset(&mut self) -> VideoResult<()> { 833 self.submit_queue.clear(); 834 835 // Make sure the codec is not active. 836 self.codec 837 .flush() 838 .map_err(|e| VideoError::BackendFailure(e.into()))?; 839 840 self.process_decoder_events()?; 841 842 // Drop the queued output buffers. 843 self.clear_output_buffers()?; 844 845 self.event_queue 846 .queue_event(DecoderEvent::ResetCompleted(Ok(()))) 847 .map_err(|e| { 848 VideoError::BackendFailure(anyhow!("Can't queue the ResetCompleted event {}", e)) 849 })?; 850 851 Ok(()) 852 } 853 clear_output_buffers(&mut self) -> VideoResult<()>854 fn clear_output_buffers(&mut self) -> VideoResult<()> { 855 // Cancel any ongoing flush. 856 self.flushing = false; 857 858 // Drop all decoded frames signaled as ready and cancel any reported flush. 859 self.event_queue.retain(|event| { 860 !matches!( 861 event, 862 DecoderEvent::PictureReady { .. } | DecoderEvent::FlushCompleted(_) 863 ) 864 }); 865 866 // Now hold all the imported frames until reuse_output_buffer is called on them. 867 let frame_pool = self.codec.frame_pool(); 868 while let Some(frame) = frame_pool.take_free_frame() { 869 let picture_id = (*frame).as_ref().picture_buffer_id; 870 self.held_frames 871 .insert(picture_id, BorrowedFrame::Held(frame)); 872 } 873 874 Ok(()) 875 } 876 event_pipe(&self) -> &dyn base::AsRawDescriptor877 fn event_pipe(&self) -> &dyn base::AsRawDescriptor { 878 &self.event_queue 879 } 880 use_output_buffer( &mut self, picture_buffer_id: i32, resource: GuestResource, ) -> VideoResult<()>881 fn use_output_buffer( 882 &mut self, 883 picture_buffer_id: i32, 884 resource: GuestResource, 885 ) -> VideoResult<()> { 886 let output_queue_state = &mut self.output_queue_state; 887 if let OutputQueueState::Drc = output_queue_state { 888 // Reusing buffers during DRC is valid, but we won't use them and can just drop them. 889 return Ok(()); 890 } 891 892 let desc = match resource.handle { 893 GuestResourceHandle::GuestPages(handle) => { 894 BufferDescriptor::GuestMem(GuestMemDescriptor(handle)) 895 } 896 GuestResourceHandle::VirtioObject(handle) => { 897 // SAFETY: descriptor is expected to be valid 898 let fd = unsafe { OwnedFd::from_raw_fd(handle.desc.into_raw_descriptor()) }; 899 let modifier = handle.modifier; 900 901 let frame = DmabufFrame { 902 fds: vec![fd], 903 layout: FrameLayout { 904 format: (cros_codecs::Fourcc::from(b"NV12"), modifier), 905 size: cros_codecs::Resolution::from((resource.width, resource.height)), 906 planes: resource 907 .planes 908 .iter() 909 .map(|p| PlaneLayout { 910 buffer_index: 0, 911 offset: p.offset, 912 stride: p.stride, 913 }) 914 .collect(), 915 }, 916 }; 917 918 BufferDescriptor::Dmabuf(frame) 919 } 920 }; 921 922 let desc_with_pic_id = BufferDescWithPicId { 923 desc, 924 picture_buffer_id, 925 }; 926 927 self.codec 928 .frame_pool() 929 .add_frames(vec![desc_with_pic_id]) 930 .map_err(VideoError::BackendFailure)?; 931 932 self.try_make_progress() 933 } 934 reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()>935 fn reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()> { 936 let output_queue_state = &mut self.output_queue_state; 937 if let OutputQueueState::Drc = output_queue_state { 938 // Reusing buffers during DRC is valid, but we won't use them and can just drop them. 939 return Ok(()); 940 } 941 942 self.held_frames.remove(&picture_buffer_id); 943 944 self.try_make_progress()?; 945 946 if self.flushing { 947 // Try flushing again now that we have a new buffer. This might let 948 // us progress further in the flush operation. 949 self.flush()?; 950 } 951 Ok(()) 952 } 953 read_event(&mut self) -> VideoResult<DecoderEvent>954 fn read_event(&mut self) -> VideoResult<DecoderEvent> { 955 self.event_queue 956 .dequeue_event() 957 .map_err(|e| VideoError::BackendFailure(anyhow!("Can't read event {}", e))) 958 } 959 } 960 961 impl DecoderBackend for VaapiDecoder { 962 type Session = VaapiDecoderSession; 963 get_capabilities(&self) -> Capability964 fn get_capabilities(&self) -> Capability { 965 self.caps.clone() 966 } 967 new_session(&mut self, format: Format) -> VideoResult<Self::Session>968 fn new_session(&mut self, format: Format) -> VideoResult<Self::Session> { 969 let display = Display::open() 970 .ok_or_else(|| VideoError::BackendFailure(anyhow!("failed to open VA display")))?; 971 972 let codec: Box<dyn StatelessVideoDecoder<BufferDescWithPicId>> = match format { 973 Format::VP8 => Box::new( 974 cros_codecs::decoder::stateless::StatelessDecoder::<Vp8, _>::new_vaapi( 975 display, 976 cros_codecs::decoder::BlockingMode::NonBlocking, 977 ), 978 ), 979 Format::VP9 => Box::new( 980 cros_codecs::decoder::stateless::StatelessDecoder::<Vp9, _>::new_vaapi( 981 display, 982 cros_codecs::decoder::BlockingMode::NonBlocking, 983 ), 984 ), 985 Format::H264 => Box::new( 986 cros_codecs::decoder::stateless::StatelessDecoder::<H264, _>::new_vaapi( 987 display, 988 cros_codecs::decoder::BlockingMode::NonBlocking, 989 ), 990 ), 991 Format::Hevc => Box::new( 992 cros_codecs::decoder::stateless::StatelessDecoder::<H265, _>::new_vaapi( 993 display, 994 cros_codecs::decoder::BlockingMode::NonBlocking, 995 ), 996 ), 997 _ => return Err(VideoError::InvalidFormat), 998 }; 999 1000 Ok(VaapiDecoderSession { 1001 codec, 1002 output_queue_state: OutputQueueState::AwaitingBufferCount, 1003 held_frames: Default::default(), 1004 submit_queue: Default::default(), 1005 event_queue: EventQueue::new().map_err(|e| VideoError::BackendFailure(anyhow!(e)))?, 1006 flushing: Default::default(), 1007 }) 1008 } 1009 } 1010 1011 #[cfg(test)] 1012 mod tests { 1013 use super::super::tests::*; 1014 use super::*; 1015 1016 #[test] 1017 // Ignore this test by default as it requires libva-compatible hardware. 1018 #[ignore] test_get_capabilities()1019 fn test_get_capabilities() { 1020 let decoder = VaapiDecoder::new().unwrap(); 1021 let caps = decoder.get_capabilities(); 1022 assert!(!caps.input_formats().is_empty()); 1023 assert!(!caps.output_formats().is_empty()); 1024 } 1025 1026 // Decode using guest memory input and output buffers. 1027 #[test] 1028 // Ignore this test by default as it requires libva-compatible hardware. 1029 #[ignore] test_decode_h264_guestmem_to_guestmem()1030 fn test_decode_h264_guestmem_to_guestmem() { 1031 decode_h264_generic( 1032 &mut VaapiDecoder::new().unwrap(), 1033 build_guest_mem_handle, 1034 build_guest_mem_handle, 1035 ); 1036 } 1037 } 1038