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