1# Trying out virtio-media 2 3This document demonstrates how to quickly try virtio-media by controlling a 4virtual host device through a Debian guest image using the 5[crosvm](https://crosvm.dev/book/) VMM. 6 7Through this document, we will build and run the following components: 8 9- A guest Linux kernel with virtio-media support enabled 10- The virtio-media guest kernel module 11- A Debian guest image with v4l-utils installed 12- Crosvm with virtio-media support 13 14## Prerequisites 15 16- A C compiler toolchain 17- The [Rust toolchain](https://rustup.rs/) version 1.75 or later 18- The `virt-builder utility` (usually available in the `libguestfs-tools` 19 package) 20 21## Directory Setup 22 23Create a workspace directory and get into it: 24 25```console 26mkdir virtio_media_playground 27cd virtio_media_playground 28``` 29 30This directory can be erased in order to remove everything we will build here. 31 32## Guest Kernel Image 33 34The virtio-media guest driver works with a regular mainline Linux kernel, as 35long as the required virtio and V4L2 options are enabled. 36 371. Clone the kernel repository: 38 39 ```console 40 git clone --branch virtio-media --depth=2 https://github.com/Gnurou/linux 41 cd linux 42 ``` 43 44 This branch is just a regular Linux mainline release with a commit on top 45 that adds the configuration we will use. 46 472. Build the kernel: 48 49 ```console 50 mkdir build_virtio_media 51 make O=build_virtio_media virtio_crosvm_defconfig 52 make O=build_virtio_media -j16 bzImage modules 53 ``` 54 55 (Adjust `-j16` to match your number of CPU cores) 56 57## Virtio-media Guest Kernel Module 58 591. Clone the virtio-media repository: 60 61 ```console 62 cd .. # Back to the workspace root 63 git clone https://github.com/chromeos/virtio-media 64 cd virtio-media/driver 65 ``` 66 672. Build the module: 68 69 ```console 70 make -C ../../linux/build_virtio_media/ M=$PWD 71 ``` 72 73## Guest System Image 74 75Create the Debian image: 76 77```console 78cd ../.. # Back to the workspace root 79virt-builder debian-12 \ 80 --install v4l-utils \ 81 --root-password password:"" \ 82 --mkdir /root/vmedia \ 83 --append-line '/etc/fstab:vmedia /root/vmedia virtiofs' 84``` 85 86This command does the following: 87 88- Download a Debian 12 image, 89- Install the `v4l-utils` package into it, 90- Set the root password to be empty, 91- Ensures that the shared virtiofs filesystem labeled `vmedia` (that we will use 92 to share the host directory containing the virtio-media kernel module) is 93 mounted into `/root/vmedia`. 94 95## Crosvm 96 971. Clone and checkout the crosvm branch containing the work-in-progress 98 virtio-media support: 99 100 ```console 101 git clone --depth=1 https://chromium.googlesource.com/crosvm/crosvm 102 cd crosvm 103 git fetch --depth=10 origin refs/changes/29/5065329/9 104 git checkout FETCH_HEAD 105 git submodule update --init 106 ``` 107 1082. Build the crosvm binary: 109 110 ```console 111 cargo build --release --features "media" 112 ``` 113 114If everything goes well, the binary should be in `target/release/crosvm`, and we 115now are ready to run our VM and try out some virtual media devices! 116 117## Start the VM 118 119```console 120cd .. # Back to the workspace root 121./crosvm/target/release/crosvm run \ 122 linux/build_virtio_media/arch/x86/boot/bzImage \ 123 --rwdisk debian-12.img \ 124 -p "root=/dev/vda1" \ 125 --shared-dir "$PWD/virtio-media:vmedia:type=fs" \ 126 --simple-media 127``` 128 129This command does the following: 130 131- Start the kernel image we built, 132- Adds the Debian guest image as a virtual disk, 133- Passes the kernel parameter to use this virtual disk as root partition, 134- Shares the folder containing the virtio-media kernel module as a virtiofs 135 filesystem labeled `vmedia`, 136- Adds a simple, dummy virtio-media test device that is entirely emulated in 137 crosvm. 138 139You should see the system booting. After a few seconds, press `<enter>` to get 140the login prompt. Login as `root` with an empty password. 141 142We will now want to insert the `virtio-media` kernel module: 143 144```console 145insmod /root/vmedia/driver/virtio-media.ko 146``` 147 148## Test the Virtual Device 149 150The simple virtio-media device should have been detected and become visible as 151`/dev/video0`. Let's see if it works: 152 153```console 154v4l2-compliance -d0 -s 155``` 156 157This should display a long list of tests ending with: 158 159```console 160... 161Total for virtio_media device /dev/video0: 54, Succeeded: 54, Failed: 0, Warnings: 1 162``` 163 164We can also check its supported capture formats: 165 166```console 167v4l2-ctl -d0 --list-formats 168``` 169 170Which informs us that our device only supports `RGB3`: 171 172```console 173ioctl: VIDIOC_ENUM_FMT 174 Type: Video Capture 175 176 [0]: 'RGB3' (24-bit RGB 8-8-8) 177``` 178 179And we can also capture frames from it: 180 181```console 182v4l2-ctl -d0 --stream-mmap --stream-count 30 --stream-to /root/vmedia/simple.rgb 183``` 184 185This writes 30 640x480 RGB frames (all filled with a single color) into the 186`simple.rgb` file of our `virtio-media` directory on the host. You can visualize 187the output using a dedicated tool like [YUView](https://github.com/IENT/YUView). 188 189That's enough for this simple example. Next we will see how to proxy a V4L2 190device on the host into the guest. Let's exit the guest: 191 192```console 193poweroff 194``` 195 196## Proxy a host V4L2 device into a guest 197 198This next example uses virtio-media's V4L2 proxy device to make a host V4L2 199device visible almost as-is into a guest. We will need a working V4L2 device on 200the host, for this example we will assume a regular USB camera using the 201`uvcvideo` driver. With the camera plugged, use `v4l2-ctl` on the host to find 202out the number of the device: 203 204```console 205v4l2-ctl -d0 --info 206``` 207 208If the output lines look something like 209 210```console 211Driver Info: 212 Driver name : uvcvideo 213 Card type : <Camera name> 214``` 215 216Then you have found the correct device. If not, replace `-d0` with `-d1`, `-d2`, 217... until you find a device which driver name is `uvcvideo`. 218 219Now that we have found the device, we can start `crosvm` with a proxy device for 220it: 221 222```console 223./crosvm/target/release/crosvm run \ 224 linux/build_virtio_media/arch/x86/boot/bzImage \ 225 --rwdisk debian-12.img \ 226 -p "root=/dev/vda1" \ 227 --shared-dir "$PWD/virtio-media:vmedia:type=fs" \ 228 --v4l2-proxy /dev/video0 229``` 230 231The `/dev/video0` assumes that the `-d0` argument of `v4l2-ctl` returned the 232right device - adjust the argument for the actual device on your host. 233 234With the guest booted, we can insert the `v4l2-media` module again: 235 236```console 237insmod /root/vmedia/driver/virtio-media.ko 238``` 239 240And check that our device is indeed recognized: 241 242```console 243v4l2-ctl -d0 --info 244``` 245 246This should return sensibly the same output as when the command was run on the 247host, with the exception that the driver name is now `virtio_media`. 248 249Most USB cameras support streaming into motion-JPEG, so let's try to capture a 250stream: 251 252```console 253v4l2-ctl -d0 --stream-mmap --set-fmt-video pixelformat=MJPG --stream-to /root/vmedia/out.mpg 254``` 255 256Use `Ctrl-C` to stop the capture. The stream has been recorded into the 257directory shared with the host, so let's exit the guest in order to check it 258out: 259 260```console 261poweroff 262``` 263 264Then on the host, use your media player of choice to view the captured file: 265 266```console 267ffplay virtio-media/out.mpg 268``` 269