Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/video/command.rs
5394 views
1
// Copyright 2020 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
//! Data structures for commands of virtio video devices.
6
7
use std::convert::TryFrom;
8
use std::convert::TryInto;
9
use std::io;
10
11
use base::error;
12
use data_model::Le32;
13
use enumn::N;
14
use remain::sorted;
15
use thiserror::Error as ThisError;
16
17
use crate::virtio::video::control::*;
18
use crate::virtio::video::format::*;
19
use crate::virtio::video::params::Params;
20
use crate::virtio::video::protocol::*;
21
use crate::virtio::video::resource::ResourceType;
22
use crate::virtio::video::resource::UnresolvedResourceEntry;
23
use crate::virtio::Reader;
24
25
/// An error indicating a failure while reading a request from the guest.
26
#[sorted]
27
#[derive(Debug, ThisError)]
28
pub enum ReadCmdError {
29
/// Invalid argument is passed.
30
#[error("invalid argument passed to command")]
31
InvalidArgument,
32
/// The type of the command was invalid.
33
#[error("invalid command type: {0}")]
34
InvalidCmdType(u32),
35
/// Failed to read an object.
36
#[error("failed to read object: {0}")]
37
IoError(#[from] io::Error),
38
/// The type of the requested control was unsupported.
39
#[error("unsupported control type: {0}")]
40
UnsupportedCtrlType(u32),
41
}
42
43
#[derive(PartialEq, Eq, PartialOrd, Ord, N, Clone, Copy, Debug)]
44
#[repr(u32)]
45
pub enum QueueType {
46
Input = VIRTIO_VIDEO_QUEUE_TYPE_INPUT,
47
Output = VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT,
48
}
49
impl_try_from_le32_for_enumn!(QueueType, "queue_type");
50
51
#[derive(Debug)]
52
pub enum VideoCmd {
53
QueryCapability {
54
queue_type: QueueType,
55
},
56
StreamCreate {
57
stream_id: u32,
58
coded_format: Format,
59
input_resource_type: ResourceType,
60
output_resource_type: ResourceType,
61
},
62
StreamDestroy {
63
stream_id: u32,
64
},
65
StreamDrain {
66
stream_id: u32,
67
},
68
ResourceCreate {
69
stream_id: u32,
70
queue_type: QueueType,
71
resource_id: u32,
72
plane_offsets: Vec<u32>,
73
/// The outer vector contains one entry per memory plane, whereas the inner vector contains
74
/// all the memory entries that make a single plane (i.e. one for virtio objects, one or
75
/// more for guest pages).
76
plane_entries: Vec<Vec<UnresolvedResourceEntry>>,
77
},
78
ResourceQueue {
79
stream_id: u32,
80
queue_type: QueueType,
81
resource_id: u32,
82
timestamp: u64,
83
data_sizes: Vec<u32>,
84
},
85
ResourceDestroyAll {
86
stream_id: u32,
87
queue_type: QueueType,
88
},
89
QueueClear {
90
stream_id: u32,
91
queue_type: QueueType,
92
},
93
GetParams {
94
stream_id: u32,
95
queue_type: QueueType,
96
/// `true` if this command has been created from the GET_PARAMS_EXT guest command.
97
is_ext: bool,
98
},
99
SetParams {
100
stream_id: u32,
101
queue_type: QueueType,
102
params: Params,
103
/// `true` if this command has been created from the SET_PARAMS_EXT guest command.
104
is_ext: bool,
105
},
106
QueryControl {
107
query_ctrl_type: QueryCtrlType,
108
},
109
GetControl {
110
stream_id: u32,
111
ctrl_type: CtrlType,
112
},
113
SetControl {
114
stream_id: u32,
115
ctrl_val: CtrlVal,
116
},
117
}
118
119
impl VideoCmd {
120
/// Reads a request on virtqueue and construct a VideoCmd value.
121
pub fn from_reader(r: &mut Reader) -> Result<Self, ReadCmdError> {
122
use self::ReadCmdError::*;
123
use self::VideoCmd::*;
124
125
// Unlike structs in virtio_video.h in the kernel, our command structs in protocol.rs don't
126
// have a field of `struct virtio_video_cmd_hdr`. So, we first read the header here and
127
// a body below.
128
let hdr = r.read_obj::<virtio_video_cmd_hdr>()?;
129
130
Ok(match hdr.type_.into() {
131
VIRTIO_VIDEO_CMD_QUERY_CAPABILITY => {
132
let virtio_video_query_capability { queue_type, .. } = r.read_obj()?;
133
QueryCapability {
134
queue_type: queue_type.try_into()?,
135
}
136
}
137
VIRTIO_VIDEO_CMD_STREAM_CREATE => {
138
let virtio_video_stream_create {
139
in_mem_type,
140
out_mem_type,
141
coded_format,
142
..
143
} = r.read_obj()?;
144
145
let input_resource_type = match in_mem_type.into() {
146
VIRTIO_VIDEO_MEM_TYPE_VIRTIO_OBJECT => ResourceType::VirtioObject,
147
VIRTIO_VIDEO_MEM_TYPE_GUEST_PAGES => ResourceType::GuestPages,
148
m => {
149
error!("Unsupported input resource memory type 0x{:x}!", m);
150
return Err(InvalidArgument);
151
}
152
};
153
154
let output_resource_type = match out_mem_type.into() {
155
VIRTIO_VIDEO_MEM_TYPE_VIRTIO_OBJECT => ResourceType::VirtioObject,
156
VIRTIO_VIDEO_MEM_TYPE_GUEST_PAGES => ResourceType::GuestPages,
157
m => {
158
error!("Unsupported output resource memory type 0x{:x}!", m);
159
return Err(InvalidArgument);
160
}
161
};
162
163
StreamCreate {
164
stream_id: hdr.stream_id.into(),
165
coded_format: coded_format.try_into()?,
166
input_resource_type,
167
output_resource_type,
168
}
169
}
170
VIRTIO_VIDEO_CMD_STREAM_DESTROY => {
171
let virtio_video_stream_destroy { .. } = r.read_obj()?;
172
StreamDestroy {
173
stream_id: hdr.stream_id.into(),
174
}
175
}
176
VIRTIO_VIDEO_CMD_STREAM_DRAIN => {
177
let virtio_video_stream_drain { .. } = r.read_obj()?;
178
StreamDrain {
179
stream_id: hdr.stream_id.into(),
180
}
181
}
182
VIRTIO_VIDEO_CMD_RESOURCE_CREATE => {
183
let virtio_video_resource_create {
184
queue_type,
185
resource_id,
186
planes_layout,
187
num_planes,
188
plane_offsets,
189
num_entries,
190
} = r.read_obj()?;
191
192
// Assume ChromeOS-specific requirements.
193
let planes_layout = Into::<u32>::into(planes_layout);
194
if planes_layout != VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER {
195
error!("Only single-planar formats are supported for now");
196
return Err(InvalidArgument);
197
}
198
199
let num_planes = Into::<u32>::into(num_planes) as usize;
200
if num_planes > plane_offsets.len() {
201
error!(
202
"num_planes is {} but shall not exceed {}",
203
num_planes,
204
plane_offsets.len(),
205
);
206
return Err(InvalidArgument);
207
}
208
if planes_layout == VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER && num_planes != 1 {
209
error!(
210
"Single-planar format specified but num_planes is {}",
211
num_planes
212
);
213
return Err(InvalidArgument);
214
}
215
216
let plane_offsets = plane_offsets[0..num_planes]
217
.iter()
218
.map(|x| Into::<u32>::into(*x))
219
.collect::<Vec<u32>>();
220
221
// Read all the entries for all the planes.
222
let plane_entries = (0..num_planes)
223
.map(|i| {
224
let num_entries: u32 = num_entries[i].into();
225
(0..num_entries)
226
.map(|_| r.read_obj::<UnresolvedResourceEntry>())
227
.collect::<Result<Vec<_>, _>>()
228
})
229
.collect::<Result<Vec<_>, _>>()?;
230
231
ResourceCreate {
232
stream_id: hdr.stream_id.into(),
233
queue_type: queue_type.try_into()?,
234
resource_id: resource_id.into(),
235
plane_offsets,
236
plane_entries,
237
}
238
}
239
VIRTIO_VIDEO_CMD_RESOURCE_QUEUE => {
240
let virtio_video_resource_queue {
241
queue_type,
242
resource_id,
243
timestamp,
244
num_data_sizes,
245
data_sizes,
246
..
247
} = r.read_obj()?;
248
249
let num_data_sizes: u32 = num_data_sizes.into();
250
if num_data_sizes as usize > data_sizes.len() {
251
return Err(InvalidArgument);
252
}
253
let data_sizes = data_sizes[0..num_data_sizes as usize]
254
.iter()
255
.map(|x| Into::<u32>::into(*x))
256
.collect::<Vec<u32>>();
257
ResourceQueue {
258
stream_id: hdr.stream_id.into(),
259
queue_type: queue_type.try_into()?,
260
resource_id: resource_id.into(),
261
timestamp: timestamp.into(),
262
data_sizes,
263
}
264
}
265
VIRTIO_VIDEO_CMD_RESOURCE_DESTROY_ALL => {
266
let virtio_video_resource_destroy_all { queue_type, .. } = r.read_obj()?;
267
ResourceDestroyAll {
268
stream_id: hdr.stream_id.into(),
269
queue_type: queue_type.try_into()?,
270
}
271
}
272
VIRTIO_VIDEO_CMD_QUEUE_CLEAR => {
273
let virtio_video_queue_clear { queue_type, .. } = r.read_obj()?;
274
QueueClear {
275
stream_id: hdr.stream_id.into(),
276
queue_type: queue_type.try_into()?,
277
}
278
}
279
VIRTIO_VIDEO_CMD_GET_PARAMS => {
280
let virtio_video_get_params { queue_type, .. } = r.read_obj()?;
281
GetParams {
282
stream_id: hdr.stream_id.into(),
283
queue_type: queue_type.try_into()?,
284
is_ext: false,
285
}
286
}
287
VIRTIO_VIDEO_CMD_SET_PARAMS => {
288
let virtio_video_set_params { params } = r.read_obj()?;
289
SetParams {
290
stream_id: hdr.stream_id.into(),
291
queue_type: params.queue_type.try_into()?,
292
params: params.try_into()?,
293
is_ext: false,
294
}
295
}
296
VIRTIO_VIDEO_CMD_QUERY_CONTROL => {
297
let body = r.read_obj::<virtio_video_query_control>()?;
298
let query_ctrl_type = match body.control.into() {
299
VIRTIO_VIDEO_CONTROL_PROFILE => QueryCtrlType::Profile(
300
r.read_obj::<virtio_video_query_control_profile>()?
301
.format
302
.try_into()?,
303
),
304
VIRTIO_VIDEO_CONTROL_LEVEL => QueryCtrlType::Level(
305
r.read_obj::<virtio_video_query_control_level>()?
306
.format
307
.try_into()?,
308
),
309
t => {
310
return Err(ReadCmdError::UnsupportedCtrlType(t));
311
}
312
};
313
QueryControl { query_ctrl_type }
314
}
315
VIRTIO_VIDEO_CMD_GET_CONTROL => {
316
let virtio_video_get_control { control, .. } = r.read_obj()?;
317
let ctrl_type = match control.into() {
318
VIRTIO_VIDEO_CONTROL_BITRATE => CtrlType::Bitrate,
319
VIRTIO_VIDEO_CONTROL_BITRATE_PEAK => CtrlType::BitratePeak,
320
VIRTIO_VIDEO_CONTROL_BITRATE_MODE => CtrlType::BitrateMode,
321
VIRTIO_VIDEO_CONTROL_PROFILE => CtrlType::Profile,
322
VIRTIO_VIDEO_CONTROL_LEVEL => CtrlType::Level,
323
VIRTIO_VIDEO_CONTROL_FORCE_KEYFRAME => CtrlType::ForceKeyframe,
324
VIRTIO_VIDEO_CONTROL_PREPEND_SPSPPS_TO_IDR => CtrlType::PrependSpsPpsToIdr,
325
t => {
326
return Err(ReadCmdError::UnsupportedCtrlType(t));
327
}
328
};
329
GetControl {
330
stream_id: hdr.stream_id.into(),
331
ctrl_type,
332
}
333
}
334
VIRTIO_VIDEO_CMD_SET_CONTROL => {
335
let virtio_video_set_control { control, .. } = r.read_obj()?;
336
let ctrl_val = match control.into() {
337
VIRTIO_VIDEO_CONTROL_BITRATE => CtrlVal::Bitrate(
338
r.read_obj::<virtio_video_control_val_bitrate>()?
339
.bitrate
340
.into(),
341
),
342
VIRTIO_VIDEO_CONTROL_BITRATE_PEAK => CtrlVal::BitratePeak(
343
r.read_obj::<virtio_video_control_val_bitrate_peak>()?
344
.bitrate_peak
345
.into(),
346
),
347
VIRTIO_VIDEO_CONTROL_BITRATE_MODE => CtrlVal::BitrateMode(
348
r.read_obj::<virtio_video_control_val_bitrate_mode>()?
349
.bitrate_mode
350
.try_into()?,
351
),
352
VIRTIO_VIDEO_CONTROL_PROFILE => CtrlVal::Profile(
353
r.read_obj::<virtio_video_control_val_profile>()?
354
.profile
355
.try_into()?,
356
),
357
VIRTIO_VIDEO_CONTROL_LEVEL => CtrlVal::Level(
358
r.read_obj::<virtio_video_control_val_level>()?
359
.level
360
.try_into()?,
361
),
362
VIRTIO_VIDEO_CONTROL_FORCE_KEYFRAME => CtrlVal::ForceKeyframe,
363
VIRTIO_VIDEO_CONTROL_PREPEND_SPSPPS_TO_IDR => CtrlVal::PrependSpsPpsToIdr(
364
r.read_obj::<virtio_video_control_val_prepend_spspps_to_idr>()?
365
.prepend_spspps_to_idr
366
!= 0,
367
),
368
t => {
369
return Err(ReadCmdError::UnsupportedCtrlType(t));
370
}
371
};
372
SetControl {
373
stream_id: hdr.stream_id.into(),
374
ctrl_val,
375
}
376
}
377
VIRTIO_VIDEO_CMD_GET_PARAMS_EXT => {
378
let virtio_video_get_params_ext { queue_type, .. } = r.read_obj()?;
379
GetParams {
380
stream_id: hdr.stream_id.into(),
381
queue_type: queue_type.try_into()?,
382
is_ext: true,
383
}
384
}
385
VIRTIO_VIDEO_CMD_SET_PARAMS_EXT => {
386
let virtio_video_set_params_ext { params } = r.read_obj()?;
387
SetParams {
388
stream_id: hdr.stream_id.into(),
389
queue_type: params.base.queue_type.try_into()?,
390
params: params.try_into()?,
391
is_ext: true,
392
}
393
}
394
_ => return Err(ReadCmdError::InvalidCmdType(hdr.type_.into())),
395
})
396
}
397
}
398
399