Name Date Size #Lines LOC

..--

device/H25-Apr-2025-6,7255,287

driver/H25-Apr-2025-3,2762,153

extras/ffmpeg-decoder/H25-Apr-2025-3,2702,371

.clangdH A D25-Apr-202570 43

.gitignoreH A D25-Apr-202595 1110

.prettierrcH A D25-Apr-202548 54

CONTRIBUTING.mdH A D25-Apr-20251.1 KiB3422

LICENSEH A D25-Apr-202519.2 KiB369303

METADATAH A D25-Apr-2025595 2119

MODULE_LICENSE_BSDHD25-Apr-20250

MODULE_LICENSE_GPLHD25-Apr-20250

OWNERSH A D25-Apr-202569 32

README.mdH A D25-Apr-202518.8 KiB468365

TRY_IT_OUT.mdH A D25-Apr-20256.9 KiB269193

README.md

1# Virtio-media
2
3This is a virtio protocol definition, companion Linux guest kernel driver, and
4set of host-side devices for virtualizing media devices using virtio, following
5the same model (and structures) as V4L2. It can be used to virtualize cameras,
6codec devices, or any other device supported by V4L2.
7
8Want to try it? See the [TRY_IT_OUT document](/TRY_IT_OUT.md).
9
10V4L2 is a UAPI that allows a less privileged entity (user-space) to use video
11hardware exposed by a more privileged entity (the kernel). Virtio-media is an
12encapsulation of this API into virtio, turning it into a virtualization API for
13all classes of video devices supported by V4L2, where the host plays the role of
14the kernel and the guest the role of user-space.
15
16The host is therefore responsible for presenting a virtual device that behaves
17like an actual V4L2 device, which the guest can control.
18
19This repository includes a simple guest Linux kernel module supporting this
20protocol. On the host side, devices can be implemented in several ways:
21
221. By forwarding a V4L2 device from the host into a guest. This works if the
23   device is already supported by V4L2 on the host.
242. By emulating a V4L2 device on the host, from the actual interface that the
25   device provides.
26
27Note that virtio-media does not require the use of a V4L2 device driver or of
28Linux on the host or guest side - V4L2 is only used as a host-guest protocol,
29and both sides are free to convert it from/to any model that they wish to use.
30
31The complete definition of V4L2 structures and ioctls can be found under the
32[V4L2 UAPI documentation](https://www.kernel.org/doc/html/latest/userspace-api/media/index.html),
33which should be referred to alongside this document.
34
35## Driver status
36
37The driver (in the `driver/` directory) should be working and supporting most
38V4L2 features, with the exception of the following:
39
40- [Read/Write API](https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/rw.html),
41  which is obsolete and inefficient.
42- Overlay interface and associated ioctls, i.e.
43  - `VIDIOC_OVERLAY`
44  - `VIDIOC_G/S_FBUF`
45- `DMABUF` buffers (this will be supported at least for virtio objects, other
46  kinds of DMABUFs may or may not be usable)
47- `VIDIOC_EXPBUF` (to be implemented)
48- `VIDIOC_G/S_EDID` (to be implemented if it makes sense in a virtual context)
49- Media API and requests. This will probably be supported in the future behind a
50  feature flag.
51
52## Devices status
53
54The `devices/` directory contains a Rust crate implementing helper functions to
55parse the protocol, interfaces to easily implement devices, and a couple of
56device implementations. It is written to be easily pluggable on any VMM. See the
57rustdoc in the `devices/` directory for more information.
58
59Implemented devices are:
60
61- A simple video capture device generating a pattern (`simple_device.rs`),
62  purely software-based and thus not requiring any kind of hardware. This is
63  here for reference and testing purposes.
64- A proxy device for host V4L2 devices, i.e. a device allowing to expose a host
65  V4L2 device to the guest almost as-is (`v4l2_device_proxy.rs`).
66
67* A FFmpeg-based video decoder device as a separate crate in
68  `extras/ffmpeg-decoder`.
69
70## Virtio device ID
71
72Virtio-media uses device ID `49`.
73
74## Virtqueues
75
76There are two queues in use:
77
780 : commandq - queue for driver commands and device responses to these commands.
79The device MUST return the descriptor chains it receives as soon as possible,
80and must never hold to them for indefinite periods of time.
81
821 : eventq - queue for events sent by the device to the driver. The driver MUST
83re-queue the descriptor chains returned by the device as soon as possible, and
84must never hold on them for indefinite periods of time.
85
86## Configuration area
87
88The configuration area contains the following information:
89
90```c
91struct virtio_v4l2_config {
92    /// The device_caps field of struct video_device.
93    u32 device_caps;
94    /// The vfl_devnode_type of the device.
95    u32 device_type;
96    /// The `card` field of v4l2_capability.
97    u8 card[32];
98}
99```
100
101## Shared memory regions
102
103Shared memory region `0` is used to map `MMAP` buffers into the guest using the
104`VIRTIO_MEDIA_CMD_MMAP` command. If the host does not provide it, then `MMAP`
105buffers cannot be mapped into the guest.
106
107## Protocol
108
109All structures managing the virtio protocol are defined and documented in
110`protocol.h`. Please refer to this file whenever a `virtio_media_cmd_*` or
111`virtio_media_resp_*` structure is mentioned.
112
113Commands are queued on the `commandq` by the driver for the device to process.
114They all start by an instance of `struct virtio_media_cmd_header` and include
115device-writable descriptors for the device to write the result of the command in
116a `struct virtio_media_resp_header`.
117
118The errors returned by each command are standard Linux kernel error codes. For
119instance, a command that contains invalid options will return `EINVAL`.
120
121Events are sent on the `eventq` by the device for the driver to handle. They all
122start by an instance of `struct virtio_media_event_header`.
123
124## Session management
125
126In order to use the device, the driver needs to open a session. This act is
127equivalent to opening the `/dev/videoX` device file of the V4L2 device.
128Depending on the type of device, it may be possible to open several sessions
129concurrently.
130
131A session is opened by queueing a `struct virtio_media_cmd_open` along with a
132descriptor to receive a `struct virtio_media_resp_open` to the commandq. An open
133session can be closed with `struct virtio_media_cmd_close`.
134
135While the session is opened, its ID can be used to perform actions on it, most
136commonly V4L2 ioctls.
137
138## Ioctls
139
140Ioctls are the main way to interact with V4L2 devices, and therefore
141virtio-media features a command to perform an ioctl on an open session.
142
143In order to perform an ioctl, the driver queues a
144`struct virtio_media_cmd_ioctl` along with a descriptor to receive a
145`struct virtio_media_resp_ioctl` on the commandq. The code of the ioctl can be
146extracted from the
147[videodev2.h](https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/videodev.html)
148header file, which defines the ioctls' codes, type of payload, and direction.
149For instance, the `VIDIOC_G_FMT` ioctl is defined as follows:
150
151```c
152#define VIDIOC_G_FMT _IOWR('V',  4, struct v4l2_format)
153```
154
155This tells us that its ioctl code is `4`, that its payload is a
156`struct v4l2_format`, and that its direction is `WR`, i.e. the payload is
157written by both the driver and the device.
158
159The payload layout is always a 64-bit representation of the corresponding V4L2
160structure, irrespective of the host and guest architecture.
161
162### Ioctls payload
163
164The payload of an ioctl in the descriptor chain follows the command structure,
165the reponse structure, or both depending on the direction:
166
167- An `_IOR` ioctl is read-only for the driver, meaning the payload follows the
168  response in the device-writable section of the descriptor chain.
169- An `_IOW` ioctl is read-only for the device, meaning the payload follows the
170  command in the driver-writable section of the descriptor chain.
171- An `_IORW` ioctl is writable by both the device and driver, meaning the
172  payload must follow both the command in the driver-writable section of the
173  descriptor chain, and the response in the device-writable section.
174
175For instance, the `VIDIOC_G_STD` ioctl is defined as follows:
176
177```c
178#define VIDIOC_G_STD _IOR('V', 23, v4l2_std_id)
179```
180
181Thus, its layout on the commandq will be:
182
183```text
184+-------------------------------------+
185| struct virtio_media_cmd_ioctl       |
186+=====================================+
187| struct virtio_media_resp_ioctl      |
188+-------------------------------------+
189| v4l2_std_id                         |
190+-------------------------------------+
191```
192
193(in these diagrams, the `====` line signals the delimitation between
194device-readable and device-writable descriptors).
195
196`VIDIOC_SUBSCRIBE_EVENT` is defined as follows:
197
198```c
199#define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription)
200```
201
202Meaning its layout on the commandq will be:
203
204```text
205+-------------------------------------+
206| struct virtio_media_cmd_ioctl       |
207+-------------------------------------+
208| struct v4l2_event_subscription      |
209+=====================================+
210| struct virtio_media_resp_ioctl      |
211+-------------------------------------+
212```
213
214Finally, `VIDIOC_G_FMT` is a `WR` ioctl:
215
216```c
217#define VIDIOC_G_FMT _IOWR('V',  4, struct v4l2_format)
218```
219
220Its layout on the commandq will thus be:
221
222```text
223+-------------------------------------+
224| struct virtio_media_cmd_ioctl       |
225+-------------------------------------+
226| struct v4l2_format                  |
227+=====================================+
228| struct virtio_media_resp_ioctl      |
229+-------------------------------------+
230| struct v4l2_format                  |
231+-------------------------------------+
232```
233
234A common optimization for `WR` ioctls is to provide the payload using
235descriptors that both point to the same buffer. This mimics the behavior of V4L2
236ioctls where the data is only passed once and used as both input and output by
237the kernel.
238
239In case of success, the device MUST always write the payload in the
240device-writable part of the descriptor chain.
241
242In case of failure, the device is free to write the payload in the
243device-writable part of the descriptor chain or not. Some errors may still
244result in the payload being updated, and in this case the device is expected to
245write the updated payload (for instance, `G_EXT_CTRLS` may return `EINVAL` but
246update the `size` member of the requested controls if the provided size was not
247enough). If the device has not written the payload after an error, the driver
248MUST assume that the payload has not been modified.
249
250### Handling of pointers in ioctl payload
251
252A few structures used as ioctl payloads contain pointers the link to further
253data needed for the ioctl. There are notably:
254
255- The `planes` pointer of `struct v4l2_buffer`, which size is determined by the
256  `length` member,
257- The `controls` pointer of `struct v4l2_ext_controls`, which size is determined
258  by the `count` member.
259
260If the size of the pointed area is determined to be non-zero, then the main
261payload is immediately followed by the pointed data in their order of appearance
262in the structure, and the pointer value itself is ignored by the device, which
263must also return the value initially passed by the driver. For instance, for a
264`struct v4l2_ext_controls` which `count` is `16`:
265
266```text
267+--------------------------------------+
268| struct v4l2_ext_controls             |
269+--------------------------------------+
270| struct v4l2_ext_control for plane 0  |
271| struct v4l2_ext_control for plane 1  |
272| ...                                  |
273| struct v4l2_ext_control for plane 15 |
274+--------------------------------------+
275```
276
277Similarly, a multiplanar `struct v4l2_buffer` with its `length` member set to 3
278will be laid out as follows:
279
280```text
281+-------------------------------------+
282| struct v4l2_buffer                  |
283+-------------------------------------+
284| struct v4l2_plane for plane 0       |
285| struct v4l2_plane for plane 1       |
286| struct v4l2_plane for plane 2       |
287+-------------------------------------+
288```
289
290### Handling of pointers to userspace memory
291
292A few pointers are special in that they point to userspace memory. They are:
293
294- The `m.userptr` member of `struct v4l2_buffer` and `struct v4l2_plane`
295  (technically an `unsigned long`, but designated a userspace address),
296- The `ptr` member of `struct v4l2_ext_ctrl`.
297
298These pointers can cover large areas of scattered memory, which has the
299potential to require more descriptors than the virtio queue can provide. For
300these particular pointers only, a list of `struct virtio_media_sg_entry` that
301covers the needed amount of memory for the pointer is used instead of using
302descriptors to map the pointed memory directly.
303
304For each such pointer to read, the device reads as many SG entries as needed to
305cover the length of the pointed buffer, as described by its parent structure
306(`length` member of `struct v4l2_buffer` or `struct v4l2_plane` for buffer
307memory, and `size` member of `struct v4l2_ext_control` for control data).
308
309Since the device never needs to modify the list of SG entries, it is only
310provided by the driver in the device-readable section of the descriptor chain,
311and not repeated in the device-writable section, even for `WR` ioctls.
312
313To illustrate the data layout, here is what the descriptor chain of a
314`VIDIOC_QBUF` ioctl queueing a 3-planar `USERPTR` buffer would look like:
315
316```text
317+---------------------------------------------------+
318| struct virtio_media_cmd_ioctl                     |
319+---------------------------------------------------+
320| struct v4l2_buffer                                |
321+---------------------------------------------------+
322| struct v4l2_plane for plane 0                     |
323| struct v4l2_plane for plane 1                     |
324| struct v4l2_plane for plane 2                     |
325+---------------------------------------------------+
326| array of struct virtio_media_sg_entry for plane 0 |
327+---------------------------------------------------+
328| array of struct virtio_media_sg_entry for plane 1 |
329+---------------------------------------------------+
330| array of struct virtio_media_sg_entry for plane 2 |
331+===================================================+
332| struct virtio_media_resp_ioctl                    |
333+---------------------------------------------------+
334| struct v4l2_buffer                                |
335+---------------------------------------------------+
336| struct v4l2_plane for plane 0                     |
337| struct v4l2_plane for plane 1                     |
338| struct v4l2_plane for plane 2                     |
339+---------------------------------------------------+
340```
341
342Since the ioctl is `RW`, the payload is repeated in both the device-readable and
343device-writable sections of the descriptor chain, but the device-writable
344section does not include the SG lists to guest memory.
345
346### Unsupported ioctls
347
348A few ioctls are replaced by other, more suitable mechanisms. If being requested
349these ioctls, the device must return the same response as it would for an
350unknown ioctl, i.e. `ENOTTY`.
351
352- `VIDIOC_QUERYCAP` is replaced by reading the configuration area.
353- `VIDIOC_DQBUF` is replaced by a dedicated event.
354- `VIDIOC_DQEVENT` is replaced by a dedicated event.
355- `VIDIOC_G_JPEGCOMP` and `VIDIOC_S_JPEGCOMP` are deprecated and replaced by the
356  controls of the JPEG class.
357- `VIDIOC_LOG_STATUS` is a guest-only operation and shall not be implemented by
358  the host.
359
360## Events
361
362Events are a way for the device to inform the driver about asynchronous events
363that it should know about. In virtio-media, they are used as a replacement for
364the `VIDIOC_DQBUF` and `VIDIOC_DQEVENT` ioctls and the polling mechanism, which
365would be impractical to implement on top of virtio.
366
367### Dequeued buffer events
368
369A `struct virtio_media_event_dqbuf` event is queued on the eventq by the device
370every time a buffer previously queued using the `VIDIOC_QBUF` ioctl is done
371being processed and can be used by the driver again. This is like an implicit
372`VIDIOC_DQBUF` ioctl.
373
374Pointer values in the `struct v4l2_buffer` and `struct v4l2_plane` are
375meaningless and must be ignored by the driver. It is recommended that the device
376sets them to `NULL` in order to avoid leaking potential host addresses.
377
378Note that in the case of a `USERPTR` buffer, the `struct v4l2_buffer` used as
379event payload is not followed by the buffer memory: since that memory is the
380same that the driver submitted with the `VIDIOC_QBUF`, it would be redundant to
381have it here.
382
383### Dequeued V4L2 event event
384
385A `struct virtio_media_event_event` event is queued on the eventq by the device
386every time an event the driver previously subscribed to using the
387`VIDIOC_SUBSCRIBE_EVENT` ioctl has been signaled. This is like an implicit
388`VIDIOC_DQEVENT` ioctl.
389
390## Memory types
391
392The semantics of the three V4L2 memory types (`MMAP`, `USERPTR` and `DMABUF`)
393can easily be mapped to a guest/host context.
394
395### MMAP
396
397In virtio-media, `MMAP` buffers are provisioned by the host, just like they are
398by the kernel in regular V4L2. Similarly to how userspace can map a `MMAP`
399buffer into its address space using `mmap` and `munmap`, the virtio-media driver
400can map host buffers into the guest space by queueing the
401`struct virtio_media_cmd_mmap` and `struct virtio_media_cmd_munmap` commands to
402the commandq.
403
404### USERPTR
405
406In virtio-media, `USERPTR` buffers and provisioned by the guest, just like they
407are by userspace in regular V4L2. Instances of `struct v4l2_buffer` and
408`struct v4l2_plane` of this type are followed by a series of descriptors mapping
409the buffer backing memory in guest space.
410
411For the host convenience, the backing memory must start with a new descriptor -
412this allows the host to easily map the buffer memory to render into it instead
413of having to do a copy.
414
415The host must not alter the pointer values provided by the guest, i.e. the
416`m.userptr` member of `struct v4l2_buffer` and `struct v4l2_plane` must be
417returned to the guest with the same value as it was provided.
418
419### DMABUF
420
421In virtio-media, `DMABUF` buffers are provisioned by a virtio object, just like
422they are by a DMABUF in regular V4L2. Virtio objects are 16-bytes UUIDs and do
423not fit in the placeholders for file descriptors, so they follow their embedding
424data structure as needed and the device must leave the V4L2 structure
425placeholder unchanged. For instance, a 3-planar `struct v4l2_buffer` with the
426`V4L2_MEMORY_DMABUF` memory type will have the following layout:
427
428```text
429+-------------------------------------+
430| struct v4l2_buffer                  |
431+-------------------------------------+
432| struct v4l2_plane for plane 0       |
433| struct v4l2_plane for plane 1       |
434| struct v4l2_plane for plane 2       |
435+-------------------------------------+
436| 16 byte UUID for plane 0            |
437+-------------------------------------+
438| 16 byte UUID for plane 1            |
439+-------------------------------------+
440| 16 byte UUID for plane 2            |
441+-------------------------------------+
442```
443
444Contrary to `USERPTR` buffers, virtio objects UUIDs need to be added in both the
445device-readable and device-writable section of the descriptor chain.
446
447Host-allocated buffers with the `V4L2_MEMORY_MMAP` memory type can also be
448exported as virtio objects for use with another virtio device using the
449`VIDIOC_EXPBUF` ioctl. The `fd` placefolder of `v4l2_exportbuffer` means that
450space for the UUID needs to be reserved right after that structure, so the ioctl
451layout will looks as follows:
452
453```text
454+-------------------------------------+
455| struct virtio_media_cmd_ioctl       |
456+-------------------------------------+
457| struct v4l2_exportbuffer            |
458+-------------------------------------+
459| 16 bytes UUID for exported buffer   |
460+=====================================+
461| struct virtio_media_resp_ioctl      |
462+-------------------------------------+
463| struct v4l2_exportbuffer            |
464+-------------------------------------+
465| 16 bytes UUID for exported buffer   |
466+-------------------------------------+
467```
468