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 //! This module implements the virtio video encoder and decoder devices. 6 //! The current implementation uses [v3 RFC] of the virtio-video protocol. 7 //! 8 //! [v3 RFC]: https://markmail.org/thread/wxdne5re7aaugbjg 9 10 use std::fmt::{self, Display}; 11 use std::thread; 12 13 use base::{error, AsRawDescriptor, Error as SysError, Event, RawDescriptor, Tube}; 14 use data_model::{DataInit, Le32}; 15 use vm_memory::GuestMemory; 16 17 use crate::virtio::virtio_device::VirtioDevice; 18 use crate::virtio::{self, copy_config, DescriptorError, Interrupt}; 19 20 #[macro_use] 21 mod macros; 22 mod async_cmd_desc_map; 23 mod command; 24 mod control; 25 mod decoder; 26 mod device; 27 mod encoder; 28 mod error; 29 mod event; 30 mod format; 31 mod params; 32 mod protocol; 33 mod response; 34 mod worker; 35 36 use command::ReadCmdError; 37 use worker::Worker; 38 39 const QUEUE_SIZE: u16 = 256; 40 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE]; 41 42 /// An error indicating something went wrong in virtio-video's worker. 43 #[derive(Debug)] 44 pub enum Error { 45 /// Creating WaitContext failed. 46 WaitContextCreationFailed(SysError), 47 /// A DescriptorChain contains invalid data. 48 InvalidDescriptorChain(DescriptorError), 49 /// No available descriptor in which an event is written to. 50 DescriptorNotAvailable, 51 /// Error while polling for events. 52 WaitError(SysError), 53 /// Failed to read a virtio-video command. 54 ReadFailure(ReadCmdError), 55 /// Failed to write an event into the event queue. 56 WriteEventFailure { 57 event: event::VideoEvt, 58 error: std::io::Error, 59 }, 60 } 61 62 impl Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result63 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 64 use Error::*; 65 match self { 66 WaitContextCreationFailed(e) => write!(f, "failed to create WaitContext: {}", e), 67 InvalidDescriptorChain(e) => write!(f, "DescriptorChain contains invalid data: {}", e), 68 DescriptorNotAvailable => { 69 write!(f, "no available descriptor in which an event is written to") 70 } 71 WaitError(err) => write!(f, "failed to wait for events: {}", err), 72 ReadFailure(e) => write!(f, "failed to read a command from the guest: {}", e), 73 WriteEventFailure { event, error } => write!( 74 f, 75 "failed to write an event {:?} into event queue: {}", 76 event, error 77 ), 78 } 79 } 80 } 81 82 impl std::error::Error for Error {} 83 pub type Result<T> = std::result::Result<T, Error>; 84 85 #[derive(Debug)] 86 pub enum VideoDeviceType { 87 Decoder, 88 Encoder, 89 } 90 91 pub struct VideoDevice { 92 device_type: VideoDeviceType, 93 kill_evt: Option<Event>, 94 resource_bridge: Option<Tube>, 95 base_features: u64, 96 } 97 98 impl VideoDevice { new( base_features: u64, device_type: VideoDeviceType, resource_bridge: Option<Tube>, ) -> VideoDevice99 pub fn new( 100 base_features: u64, 101 device_type: VideoDeviceType, 102 resource_bridge: Option<Tube>, 103 ) -> VideoDevice { 104 VideoDevice { 105 device_type, 106 kill_evt: None, 107 resource_bridge, 108 base_features, 109 } 110 } 111 } 112 113 impl Drop for VideoDevice { drop(&mut self)114 fn drop(&mut self) { 115 if let Some(kill_evt) = self.kill_evt.take() { 116 // Ignore the result because there is nothing we can do about it. 117 let _ = kill_evt.write(1); 118 } 119 } 120 } 121 122 impl VirtioDevice for VideoDevice { keep_rds(&self) -> Vec<RawDescriptor>123 fn keep_rds(&self) -> Vec<RawDescriptor> { 124 let mut keep_rds = Vec::new(); 125 if let Some(resource_bridge) = &self.resource_bridge { 126 keep_rds.push(resource_bridge.as_raw_descriptor()); 127 } 128 keep_rds 129 } 130 device_type(&self) -> u32131 fn device_type(&self) -> u32 { 132 match &self.device_type { 133 VideoDeviceType::Decoder => virtio::TYPE_VIDEO_DEC, 134 VideoDeviceType::Encoder => virtio::TYPE_VIDEO_ENC, 135 } 136 } 137 queue_max_sizes(&self) -> &[u16]138 fn queue_max_sizes(&self) -> &[u16] { 139 QUEUE_SIZES 140 } 141 features(&self) -> u64142 fn features(&self) -> u64 { 143 self.base_features 144 | 1u64 << protocol::VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG 145 | 1u64 << protocol::VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT 146 } 147 read_config(&self, offset: u64, data: &mut [u8])148 fn read_config(&self, offset: u64, data: &mut [u8]) { 149 let mut cfg = protocol::virtio_video_config { 150 version: Le32::from(0), 151 max_caps_length: Le32::from(1024), // Set a big number 152 max_resp_length: Le32::from(1024), // Set a big number 153 }; 154 copy_config(data, 0, cfg.as_mut_slice(), offset); 155 } 156 activate( &mut self, mem: GuestMemory, interrupt: Interrupt, mut queues: Vec<virtio::queue::Queue>, mut queue_evts: Vec<Event>, )157 fn activate( 158 &mut self, 159 mem: GuestMemory, 160 interrupt: Interrupt, 161 mut queues: Vec<virtio::queue::Queue>, 162 mut queue_evts: Vec<Event>, 163 ) { 164 if queues.len() != QUEUE_SIZES.len() { 165 error!( 166 "wrong number of queues are passed: expected {}, actual {}", 167 queues.len(), 168 QUEUE_SIZES.len() 169 ); 170 return; 171 } 172 if queue_evts.len() != QUEUE_SIZES.len() { 173 error!( 174 "wrong number of events are passed: expected {}, actual {}", 175 queue_evts.len(), 176 QUEUE_SIZES.len() 177 ); 178 } 179 180 let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) { 181 Ok(v) => v, 182 Err(e) => { 183 error!("failed to create kill Event pair: {:?}", e); 184 return; 185 } 186 }; 187 self.kill_evt = Some(self_kill_evt); 188 189 let cmd_queue = queues.remove(0); 190 let cmd_evt = queue_evts.remove(0); 191 let event_queue = queues.remove(0); 192 let event_evt = queue_evts.remove(0); 193 let resource_bridge = match self.resource_bridge.take() { 194 Some(r) => r, 195 None => { 196 error!("no resource bridge is passed"); 197 return; 198 } 199 }; 200 let mut worker = Worker { 201 interrupt, 202 mem, 203 cmd_evt, 204 event_evt, 205 kill_evt, 206 resource_bridge, 207 }; 208 let worker_result = match &self.device_type { 209 VideoDeviceType::Decoder => thread::Builder::new() 210 .name("virtio video decoder".to_owned()) 211 .spawn(move || { 212 let vda = match libvda::decode::VdaInstance::new( 213 libvda::decode::VdaImplType::Gavda, 214 ) { 215 Ok(vda) => vda, 216 Err(e) => { 217 error!("Failed to initialize vda: {}", e); 218 return; 219 } 220 }; 221 let device = decoder::Decoder::new(&vda); 222 if let Err(e) = worker.run(cmd_queue, event_queue, device) { 223 error!("Failed to start decoder worker: {}", e); 224 }; 225 // Don't return any information since the return value is never checked. 226 }), 227 VideoDeviceType::Encoder => thread::Builder::new() 228 .name("virtio video encoder".to_owned()) 229 .spawn(move || { 230 let encoder = match encoder::LibvdaEncoder::new() { 231 Ok(vea) => vea, 232 Err(e) => { 233 error!("Failed to initialize vea: {}", e); 234 return; 235 } 236 }; 237 let device = match encoder::EncoderDevice::new(&encoder) { 238 Ok(d) => d, 239 Err(e) => { 240 error!("Failed to create encoder device: {}", e); 241 return; 242 } 243 }; 244 if let Err(e) = worker.run(cmd_queue, event_queue, device) { 245 error!("Failed to start encoder worker: {}", e); 246 } 247 }), 248 }; 249 if let Err(e) = worker_result { 250 error!( 251 "failed to spawn virtio_video worker for {:?}: {}", 252 &self.device_type, e 253 ); 254 return; 255 } 256 } 257 } 258