Skip to content

Commit d42f8bd

Browse files
committed
Port virtio media simple device as a vhost user media device.
Port virtio media reference device `simple_device` as a vhost user implementation. First iteration of `simple_device/src/simple_device.rs` is the same as in virtio-media upstream https://github.com/chromeos/virtio-media/blob/main/device/src/devices/simple_device.rs. ``` cargo run --bin simple_device -- --socket-path /tmp/simple_device.sock ``` ``` cargo run --features "media" -- --log-level=debug run --cpus 4 --mem 4096 \ --rwdisk /path/to/debian-12.img \ --params "root=/dev/vda1" \ --vhost-user media,socket=/tmp/simple_device.sock \ /path/to/bzImage v4l2-compliance -d0 -s ``` Bug: 445229097
1 parent e4cabf1 commit d42f8bd

6 files changed

Lines changed: 1277 additions & 0 deletions

File tree

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[workspace]
2+
resolver = "3"
3+
members = ["simple_device", "vhu_media"]
4+
5+
[workspace.dependencies]
6+
vhu_media = { path = "vhu_media" }
7+
8+
# External dependencies
9+
anyhow = { version = "1.0.97", features = [ "default", "std" ] }
10+
clap = { version = "4.5", features = ["derive"] }
11+
env_logger = "0.11"
12+
libc = "0.2"
13+
log = "0.4"
14+
thiserror = "2.0"
15+
vhost = { version = "0.14", features = ["vhost-user-backend"] }
16+
vhost-user-backend = "0.20"
17+
virtio-bindings = "0.2.6"
18+
virtio-media = "0.0.7"
19+
virtio-queue = "0.16.0"
20+
vm-allocator = "0.1.3"
21+
vm-memory = "0.16.2"
22+
vmm-sys-util = "0.15.0"
23+
v4l2r = { version = "0.0.6", features = ["arch64"] }
24+
uuid = { version = "1.8.0", features=["v4"] }
25+
zerocopy = { version = "0.8.13", features = ["derive"] }
26+
bitflags = "2.3"
27+
serde = { version = "1.0", features = ["derive"] }
28+
serde_json = "1"
29+
30+
[patch.crates-io]
31+
vhost = { path = "/usr/local/google/home/sorama/code/github.com/forks/vhost/vhost" }
32+
vhost-user-backend = { path = "/usr/local/google/home/sorama/code/github.com/forks/vhost/vhost-user-backend" }
33+
virtio-media = { path = "/usr/local/google/home/sorama/code/github.com/virtio-media/device" }
34+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "simple_device"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
clap = { workspace = true }
8+
env_logger = { workspace = true }
9+
libc = { workspace = true }
10+
log = { workspace = true }
11+
thiserror = { workspace = true }
12+
v4l2r = { workspace = true }
13+
vhost-user-backend = { workspace = true }
14+
virtio-media = { workspace = true }
15+
vm-memory = { workspace = true }
16+
vhu_media = { workspace = true }
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//! simple_device
2+
3+
use std::{
4+
path::PathBuf,
5+
process::exit,
6+
sync::{Arc, RwLock},
7+
thread::{JoinHandle, spawn},
8+
};
9+
10+
use clap::Parser;
11+
use log::error;
12+
use thiserror::Error;
13+
use vhost_user_backend::VhostUserDaemon;
14+
use vhu_media::VhuMediaBackend;
15+
use virtio_media::protocol::VirtioMediaDeviceConfig;
16+
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
17+
18+
mod simple_device;
19+
20+
#[derive(Debug, Error)]
21+
pub(crate) enum Error {
22+
#[error("Could not create daemon: {0}")]
23+
CouldNotCreateDaemon(vhost_user_backend::Error),
24+
#[error("Fatal error: {0}")]
25+
ServeFailed(vhost_user_backend::Error),
26+
}
27+
28+
type Result<T> = std::result::Result<T, Error>;
29+
30+
#[derive(Parser, Debug)]
31+
#[clap(author, version, about, long_about = None)]
32+
struct CmdLineArgs {
33+
/// Location of vhost-user Unix domain socket.
34+
#[clap(short, long, value_name = "SOCKET")]
35+
socket_path: PathBuf,
36+
}
37+
38+
#[derive(PartialEq, Debug)]
39+
struct Config {
40+
socket_path: PathBuf,
41+
}
42+
43+
impl TryFrom<CmdLineArgs> for Config {
44+
type Error = Error;
45+
46+
fn try_from(args: CmdLineArgs) -> Result<Self> {
47+
Ok(Config {
48+
socket_path: args.socket_path,
49+
})
50+
}
51+
}
52+
53+
fn start_backend(args: CmdLineArgs) -> Result<()> {
54+
let config = Config::try_from(args)?;
55+
let socket_path = config.socket_path.clone();
56+
let handle: JoinHandle<Result<()>> = spawn(move || {
57+
loop {
58+
let mut card = [0u8; 32];
59+
let card_name = "simple_device";
60+
card[0..card_name.len()].copy_from_slice(card_name.as_bytes());
61+
use virtio_media::v4l2r::ioctl::Capabilities;
62+
let config = VirtioMediaDeviceConfig {
63+
device_caps: (Capabilities::VIDEO_CAPTURE | Capabilities::STREAMING).bits(),
64+
// VFL_TYPE_VIDEO
65+
device_type: 0,
66+
card,
67+
};
68+
let backend = Arc::new(RwLock::new(VhuMediaBackend::new(
69+
config,
70+
|event_queue, host_mapper| {
71+
simple_device::SimpleCaptureDevice::new(event_queue, host_mapper)
72+
},
73+
)));
74+
let mut daemon = VhostUserDaemon::new(
75+
String::from("vhost-user-media-backend"),
76+
backend,
77+
GuestMemoryAtomic::new(GuestMemoryMmap::new()),
78+
)
79+
.map_err(Error::CouldNotCreateDaemon)?;
80+
daemon.serve(&socket_path).map_err(Error::ServeFailed)?;
81+
}
82+
});
83+
84+
handle.join().map_err(std::panic::resume_unwind).unwrap()
85+
}
86+
87+
fn main() {
88+
env_logger::init();
89+
90+
if let Err(e) = start_backend(CmdLineArgs::parse()) {
91+
error!("{e}");
92+
exit(1);
93+
}
94+
}

0 commit comments

Comments
 (0)