As previously mentioned in our RFC, we at 9elements were working
on a new video subsystem for QEMU.

This subsystem includes a USB Video Class (UVC) frontend that exposes
a virtual camera device to the guest OS, backed by host-side
video sources like v4l2, GStreamer and libcamera.

The patch series is split into three parts

    - the first patch introduces the video subsystem with its
      first backend (v4l2) and implements the UVC device logic
    - the second patch adds the GStreamer backend
    - the third and final patch implements libcamera support

Currently we are able to:

    - stream frames (currently YUYV only)
    - dynamically enumerate supported camera modes (pixelformat, ...)
    - discover and access camera controls (brightness, ...)

The patch series was tested on two different host devices and in
combination with several guests

    1. Fedora39 as host with ubuntu-24.04, Fedora41 and Fedora42 as guests
    2. Fedora42 as host with Fedora42 as guest

Video streaming was successfully tested with, for example guvcview,
v4l2-ctl, gst-launch-1.0 (v4l2src, pipewiresrc), cheese, snapshot, vlc,
and Google Meet (from within Firefox) using the internal camera
and several external USB cameras.

v4l2-ctl and qv4l2 were used to test camera controls.

Known issues:

We currently do not always achieve the target fps. Higher frame resolutions
tend to reduce the fps observed in the guest. The following values were
recorded using the v4l2 backend and guvcview

internal webcam (HP EliteBook):
  640x360@30fps: 17.52fps
  320x180@30fps: 30.00fps
  320x240@30fps: 30.00fps
  424x240@30fps: 30.00fps
  640x480@30fps: 13.14fps

jiga webcam
  1920x1080@5fps: 2.01fps
  800x600@20fps:  8.44fps

I attempted to improve streaming performance by implementing a
producer-consumer model. The idea was for the producer
to fetch frames from the backend and enqueue them, while the
consumer (USBDeviceClass.handle_data) would dequeue and process them.
However, I'm not very familiar with QEMU's threading model, and I likely
didn’t implement it correctly - the producer and consumer are probably
still running in the same event loop

The experimental async version can be found here:
https://github.com/9elements/qemu/tree/nlnet/qemu-video/dev-async

Another issue is that v4l2-ctl fails to stream certain video resolutions,
even though other tools handle the same resolutions without problems. For
some resolutions, v4l2-ctl only receives frames marked with the
V4L2_BUF_FLAG_ERROR flag. This behavior requires further investigation.

Any help is very welcome!

RFC: https://lists.gnu.org/archive/html/qemu-devel/2025-03/msg02804.html
nlnet: https://nlnet.nl/project/Qemu-Camera/

Best regards,
David Milosevic

David Milosevic (3):
  video: introduce video subsystem with inital v4l2 backend
  video: add GStreamer backend
  video: add libcamera backend extension

 hw/core/qdev-properties-system.c    |   52 ++
 hw/usb/Kconfig                      |    5 +
 hw/usb/dev-video.c                  | 1333 +++++++++++++++++++++++++++
 hw/usb/meson.build                  |    1 +
 hw/usb/trace-events                 |   10 +
 include/hw/qdev-properties-system.h |    4 +
 include/hw/usb.h                    |    2 +
 include/hw/usb/video.h              |  322 +++++++
 meson.build                         |   31 +
 meson_options.txt                   |    5 +
 qemu-options.hx                     |    9 +
 scripts/meson-buildoptions.sh       |    6 +
 system/vl.c                         |   39 +-
 video/gstreamer-common.h            |   49 +
 video/gstreamer.c                   |  642 +++++++++++++
 video/libcamera.c                   |  148 +++
 video/meson.build                   |   24 +
 video/v4l2.c                        |  619 +++++++++++++
 video/video.c                       |  450 +++++++++
 video/video.h                       |  298 ++++++
 20 files changed, 4048 insertions(+), 1 deletion(-)
 create mode 100644 hw/usb/dev-video.c
 create mode 100644 include/hw/usb/video.h
 create mode 100644 video/gstreamer-common.h
 create mode 100644 video/gstreamer.c
 create mode 100644 video/libcamera.c
 create mode 100644 video/meson.build
 create mode 100644 video/v4l2.c
 create mode 100644 video/video.c
 create mode 100644 video/video.h

-- 
2.47.0


Reply via email to