Skip to content

Commit aa77647

Browse files
committed
video: initial skeleton
Initial skeleton for virtio-video crate. This crate is based on the v3 of the virtio-video specs patch[1]. It has a big part of the infrastructure required, although not all commands are implemented, and does not have any backend available. Includes support for async responses to the driver (through VIDEO_EVENT) to QueueResource messages. [1] - https://lists.oasis-open.org/archives/virtio-dev/202002/msg00002.html Related: #364 Signed-off-by: Albert Esteve <aesteve@redhat.com>
1 parent 38caab2 commit aa77647

15 files changed

Lines changed: 2583 additions & 0 deletions

Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ members = [
77
"crates/rng",
88
"crates/scsi",
99
"crates/scmi",
10+
"crates/video",
1011
"crates/vsock",
1112
]

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Here is the list of device backends that we support:
1313
- [RNG](https://github.com/rust-vmm/vhost-device/blob/main/crates/rng/README.md)
1414
- [SCMI](https://github.com/rust-vmm/vhost-device/blob/main/crates/scmi/README.md)
1515
- [SCSI](https://github.com/rust-vmm/vhost-device/blob/main/crates/scsi/README.md)
16+
- [VIDEO](https://github.com/rust-vmm/vhost-device/blob/main/crates/video/README.md)
1617
- [VSOCK](https://github.com/rust-vmm/vhost-device/blob/main/crates/vsock/README.md)
1718

1819
## Testing and Code Coverage

crates/video/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Changelog
2+
## [Unreleased]
3+
4+
### Added
5+
6+
### Changed
7+
8+
### Fixed
9+
10+
### Deprecated
11+
12+
## [0.1.0]
13+
14+
First release
15+

crates/video/Cargo.toml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[package]
2+
name = "vhost-user-video"
3+
version = "0.1.0"
4+
authors = ["Albert Esteve <aesteve@redhat.com>"]
5+
description = "A virtio-video device using the vhost-user protocol."
6+
repository = "https://github.com/rust-vmm/vhost-device"
7+
readme = "README.md"
8+
keywords = ["vhost", "video", "virt", "backend"]
9+
edition = "2021"
10+
11+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
12+
13+
[features]
14+
default = []
15+
16+
[dependencies]
17+
bitflags = "2.3.3"
18+
clap = { version = "4.3", features = ["derive"] }
19+
env_logger = "0.10"
20+
epoll = "4.3"
21+
num_enum = "0.7"
22+
log = "0.4"
23+
libc = "0.2.147"
24+
thiserror = "1.0"
25+
futures-executor = { version = "0.3", features = ["thread-pool"] }
26+
vhost = { version = "0.8", features = ["vhost-user-slave"] }
27+
vhost-user-backend = "0.10"
28+
virtio-bindings = "0.2.1"
29+
virtio-queue = "0.9"
30+
vm-memory = "0.12"
31+
vmm-sys-util = "0.11"
32+
33+
[dev-dependencies]
34+
virtio-queue = { version = "0.9", features = ["test-utils"] }
35+
vm-memory = { version = "0.12", features = ["backend-mmap", "backend-atomic"] }

crates/video/LICENSE-APACHE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../LICENSE-APACHE

crates/video/LICENSE-BSD-3-Clause

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../LICENSE-BSD-3-Clause

crates/video/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# vhost-user-video
2+
3+
## Design
4+
5+
## Usage
6+
7+
## Working example
8+
9+
## License
10+
11+
This project is licensed under either of
12+
13+
- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0
14+
- [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause)

crates/video/src/main.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
2+
mod stream;
3+
mod vhu_video;
4+
mod vhu_video_thread;
5+
mod video;
6+
mod video_backends;
7+
8+
use std::path::PathBuf;
9+
use std::sync::{Arc, RwLock};
10+
11+
use clap::Parser;
12+
use log::{info, warn};
13+
use thiserror::Error as ThisError;
14+
use vhost::{vhost_user, vhost_user::Listener};
15+
use vhost_user_backend::VhostUserDaemon;
16+
use vhu_video::{BackendType, VuVideoBackend};
17+
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
18+
19+
pub(crate) type Result<T> = std::result::Result<T, Error>;
20+
21+
#[derive(Debug, ThisError)]
22+
pub(crate) enum Error {
23+
#[error("Could not create backend: {0}")]
24+
CouldNotCreateBackend(vhu_video::VuVideoError),
25+
#[error("Could not create daemon: {0}")]
26+
CouldNotCreateDaemon(vhost_user_backend::Error),
27+
#[error("Failed creating listener: {0}")]
28+
FailedCreatingListener(vhost_user::Error),
29+
}
30+
31+
#[derive(Clone, Parser, Debug)]
32+
#[clap(author, version, about, long_about = None)]
33+
struct VideoArgs {
34+
/// Unix socket to which a hypervisor connects to and sets up the control path with the device.
35+
#[clap(short, long)]
36+
socket_path: PathBuf,
37+
38+
/// Path to the video device file. Defaults to /dev/video0.
39+
#[clap(short = 'd', long, default_value = "/dev/video0")]
40+
v4l2_device: PathBuf,
41+
42+
/// Video backend to be used.
43+
#[clap(short, long)]
44+
#[clap(value_enum)]
45+
backend: BackendType,
46+
}
47+
48+
#[derive(Debug, Eq, PartialEq)]
49+
pub(crate) struct VuVideoConfig {
50+
pub socket_path: PathBuf,
51+
pub v4l2_device: PathBuf,
52+
pub backend: BackendType,
53+
}
54+
55+
impl From<VideoArgs> for VuVideoConfig {
56+
fn from(args: VideoArgs) -> Self {
57+
// Divide available bandwidth by the number of threads in order
58+
// to avoid overwhelming the HW.
59+
Self {
60+
socket_path: args.socket_path.to_owned(),
61+
v4l2_device: args.v4l2_device.to_owned(),
62+
backend: args.backend,
63+
}
64+
}
65+
}
66+
67+
pub(crate) fn start_backend(config: VuVideoConfig) -> Result<()> {
68+
loop {
69+
info!("Starting backend");
70+
let vu_video_backend = Arc::new(RwLock::new(
71+
VuVideoBackend::new(config.v4l2_device.as_path(), config.backend.to_owned())
72+
.map_err(Error::CouldNotCreateBackend)?,
73+
));
74+
75+
let mut daemon = VhostUserDaemon::new(
76+
String::from("vhost-device-video"),
77+
vu_video_backend.clone(),
78+
GuestMemoryAtomic::new(GuestMemoryMmap::new()),
79+
)
80+
.map_err(Error::CouldNotCreateDaemon)?;
81+
82+
let mut vring_workers = daemon.get_epoll_handlers();
83+
for thread in vu_video_backend.read().unwrap().threads.iter() {
84+
thread
85+
.lock()
86+
.unwrap()
87+
.set_vring_workers(vring_workers.remove(0));
88+
}
89+
90+
daemon
91+
.start(Listener::new(&config.socket_path, true).map_err(Error::FailedCreatingListener)?)
92+
.expect("Stargin daemon");
93+
94+
match daemon.wait() {
95+
Ok(()) => {
96+
info!("Stopping cleanly");
97+
}
98+
Err(vhost_user_backend::Error::HandleRequest(vhost_user::Error::PartialMessage)) => {
99+
info!(
100+
"vhost-user connection closed with partial message.
101+
If the VM is shutting down, this is expected behavior;
102+
otherwise, it might be a bug."
103+
);
104+
}
105+
Err(e) => {
106+
warn!("Error running daemon: {:?} -> {}", e, e.to_string());
107+
}
108+
}
109+
110+
vu_video_backend
111+
.read()
112+
.unwrap()
113+
.exit_event
114+
.write(1)
115+
.expect("Shutting down worker thread");
116+
}
117+
}
118+
119+
fn main() -> Result<()> {
120+
env_logger::init();
121+
122+
start_backend(VuVideoConfig::try_from(VideoArgs::parse()).unwrap())
123+
}

0 commit comments

Comments
 (0)