Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usb: device_next: new USB Video Class (UVC) implementation #76798

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions dts/bindings/video/zephyr,uvc-device.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright (c) 2024 tinyVision.ai Inc.
# SPDX-License-Identifier: Apache-2.0

description: |
USB Video Class instance

The Video Class will present a video endpoint to interconnect with any video
device. It supports multiple endpoints, each becoming its own video streaming
interface to the host.

The devices that are connected will receive calls to all query and configure
the formats, frame intervals, video controls, and get the feed started via
their video API. Some of this information is used to generate the USB device
descriptors sent to the host, with the supported format and controls listed.

Example for single endpoint connected to mipi0:

uvc0: uvc {
compatible = "zephyr,uvc-device";
port {
uvc0_ep_in: endpoint {
remote-endpoint-label = "mipi0_ep_out";
};
};
};

Example for multiple endpoints connected to mipi0 and mipi1:

uvc0: uvc {
compatible = "zephyr,uvc-device";
port {
#address-cells = <1>;
#size-cells = <0>;

uvc0_ep0_in: endpoint@0 {
reg = <0x0>;
remote-endpoint-label = "mipi0_ep_out";
};

uvc0_ep1_in: endpoint@1 {
reg = <0x1>;
remote-endpoint-label = "mipi1_ep_out";
};
};
};

compatible: "zephyr,uvc-device"

include: base.yaml

on-bus: usb

child-binding:
child-binding:
include: video-interfaces.yaml
3 changes: 2 additions & 1 deletion samples/subsys/usb/common/sample_usbd_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ static void sample_fix_code_triple(struct usbd_context *uds_ctx,
if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) ||
IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS) ||
IS_ENABLED(CONFIG_USBD_CDC_NCM_CLASS) ||
IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS)) {
IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS) ||
IS_ENABLED(CONFIG_USBD_VIDEO_CLASS)) {
/*
* Class with multiple interfaces have an Interface
* Association Descriptor available, use an appropriate triple
Expand Down
8 changes: 8 additions & 0 deletions samples/subsys/usb/uvc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(usb_video)

include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)
target_sources(app PRIVATE src/main.c)
9 changes: 9 additions & 0 deletions samples/subsys/usb/uvc/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nordic ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a Kconfig copy-pasted from Nordic unchanged:

# Copyright (c) 2023-2024 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
# Source common USB sample options used to initialize new experimental USB
# device stack. The scope of these options is limited to USB samples in project
# tree, you cannot use them in your own application.
source "samples/subsys/usb/common/Kconfig.sample_usbd"
source "Kconfig.zephyr"

# SPDX-License-Identifier: Apache-2.0

# Source common USB sample options used to initialize new experimental USB
# device stack. The scope of these options is limited to USB samples in project
# tree, you cannot use them in your own application.
source "samples/subsys/usb/common/Kconfig.sample_usbd"

source "Kconfig.zephyr"
143 changes: 143 additions & 0 deletions samples/subsys/usb/uvc/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
.. zephyr:code-sample:: uvc
:name: USB Video sample
:relevant-api: usbd_api video_interface

USB Video sample sending frames over USB.

Overview
********

This sample demonstrates how to use an USB Video Class instance to
send video data over USB.

Upon connection, a video interface would show-up in the operating system,
using the same protocol as most webcams, and be detected as such.

Any software application to read and process video would then be able
to access the stream.

Requirements
************

USB is the only requirement for this sensor, as an emulated image
sensor and MIPI receiver is used to provide a test pattern from
software.

The USB descriptor configuration is extracted from these drivers, and
the user does not need to provide them.

Building and Running
********************

Build the sample application and flash the resulting binaries.

.. zephyr-app-commands::
:zephyr-app: samples/subsys/usb/uvc
:board: nrf52840dongle
:goals: build flash
:compact:

.. zephyr-app-commands::
:zephyr-app: samples/subsys/usb/uvc
:board: mini_stm32h734
:goals: build flash
:compact:

.. zephyr-app-commands::
:zephyr-app: samples/subsys/usb/uvc
:board: rpi_pico
:goals: build flash
:compact:

Upon reboot, the device is expected to be detected by the operating
system.

On Linux, OSX and BSDs this is visible using the ``dmesg`` and ``lsusb`` commands.

On Windows, this is visible using the "Windows Device Manager" application.

Playing the Stream
==================

Some example of client to open the video stream on a Linux
environment, assuming ``/dev/video2`` is your Zephyr demo freshly
attached.

Play it using `FFplay <https://ffmpeg.org/ffplay.html>`_

.. code-block:: console

ffplay /dev/video2

Play it using `GStramer <https://gstreamer.freedesktop.org/>`_:

.. code-block:: console

gst-launch-1.0 v4l2src device=/dev/video2 ! videoconvert ! autovideosink

Play it using `MPV <https://mpv.io/>`_:

.. code-block:: console

mpv /dev/video2

Play it using `VLC <https://www.videolan.org/vlc/>`_:

.. code-block:: console

vlc v4l2:///dev/video2

The video device can also be used by web applications and video
conferencing systems, as it is recognized by the system as a native
webcam.

On Windows, accessing the video can be done with the default "Camera" application,
by switching the camera source.

Android and iPad (but not yet iOS) are also expected to work via
dedicated applications.

Accessing the Video Controls
============================

On Linux, the ``v4l2-ctl`` command permits to list the supported controls:

.. code-block:: console

$ v4l2-ctl --device /dev/video2 --list-ctrls

Camera Controls

auto_exposure 0x009a0901 (menu) : min=0 max=3 default=1 value=1 (Manual Mode)
exposure_dynamic_framerate 0x009a0903 (bool) : default=0 value=0
exposure_time_absolute 0x009a0902 (int) : min=10 max=2047 step=1 default=384 value=384 flags=inactive

$ v4l2-ctl --device /dev/video2 --set-ctrl auto_exposure=1
$ v4l2-ctl --device /dev/video2 --set-ctrl exposure_time_absolute=1500

On Windows, the `VLC <https://www.videolan.org/vlc/>`_ client and `Pot Player <https://potplayer.tv/>`_
client permit to further access the video controls.

Software Processing
===================

Software processing tools can also use the video interface directly.

Here is an example with OpenCV:

.. code-block:: python

import cv2

# Number of the /dev/video# interface
devnum = 2

cv2.namedWindow("preview")
vc = cv2.VideoCapture(devnum)

while (val := vc.read())[0]:
cv2.waitKey(20)
cv2.imshow("preview", val[1])

cv2.destroyWindow("preview")
vc.release()
48 changes: 48 additions & 0 deletions samples/subsys/usb/uvc/app.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 tinyVision.ai Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

/ {
imager0: emul_imager_0 {
compatible = "zephyr,video-emul-imager";

port {
imager0_ep_out: endpoint {
remote-endpoint-label = "mipi0_ep_in";
};
};
};

mipi0: video_emul_rx_0 {
compatible = "zephyr,video-emul-rx";

port {
#address-cells = <1>;
#size-cells = <0>;

mipi0_ep_in: endpoint@0 {
reg = <0x0>;
remote-endpoint-label = "imager0_ep_out";
};

mipi0_ep_out: endpoint@1 {
reg = <0x1>;
remote-endpoint-label = "uvc_ep_in";
};
};
};
};

&zephyr_udc0 {
uvc: uvc {
compatible = "zephyr,uvc-device";

port {
uvc_ep_in: endpoint {
remote-endpoint-label = "mipi0_ep_out";
};
};
};
};
5 changes: 5 additions & 0 deletions samples/subsys/usb/uvc/boards/frdm_mcxn947_mcxn947_cpu0.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Temporary workaround a build-time incompatibility
CONFIG_VIDEO_OV7670=n
CONFIG_DMA_MCUX_SMARTDMA=n
CONFIG_VIDEO_MCUX_SDMA=n
CONFIG_USBD_LOG_LEVEL_DBG=y
8 changes: 8 additions & 0 deletions samples/subsys/usb/uvc/boards/mini_stm32h743.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Switch from CDC ACM to UART
CONFIG_USB_DEVICE_STACK=n
CONFIG_USBD_CDC_ACM_CLASS=n
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y

# Avoid --- 1113 messages dropped --- when debugging
CONFIG_LOG_MODE_MINIMAL=y
26 changes: 26 additions & 0 deletions samples/subsys/usb/uvc/boards/mini_stm32h743.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 tinyVision.ai Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "../app.overlay"

/* Do not use the CDC-ACM based logger to avoid interfering in the logs */

/ {
chosen {
zephyr,console = &usart3;
zephyr,shell-uart = &usart3;
};
};

&usb_cdc_acm_uart {
status = "disabled";
};

&usart3 {
pinctrl-0 = <&usart3_tx_pb10 &usart3_rx_pb11>;
pinctrl-names = "default";
status = "okay";
};
5 changes: 5 additions & 0 deletions samples/subsys/usb/uvc/boards/nrf52840dongle.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Switch from CDC ACM to UART
CONFIG_USB_DEVICE_STACK=n
CONFIG_USBD_CDC_ACM_CLASS=n
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y
24 changes: 24 additions & 0 deletions samples/subsys/usb/uvc/boards/nrf52840dongle.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2024 tinyVision.ai Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "../app.overlay"

/* Do not use the CDC-ACM based logger to avoid interfering in the logs */

/ {
chosen {
zephyr,console = &uart0;
zephyr,shell-uart = &uart0;
};
};

&cdc_acm_uart {
status = "disabled";
};

&uart0 {
status = "okay";
};
14 changes: 14 additions & 0 deletions samples/subsys/usb/uvc/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
CONFIG_LOG=y
CONFIG_LOG_MODE_MINIMAL=y
CONFIG_VIDEO=y
CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=4
CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=7300
CONFIG_VIDEO_EMUL_IMAGER=y
CONFIG_VIDEO_EMUL_RX=y
CONFIG_VIDEO_LOG_LEVEL_DBG=y
CONFIG_USB_DEVICE_STACK=n
CONFIG_USB_DEVICE_STACK_NEXT=y
CONFIG_USBD_VIDEO_CLASS=y
CONFIG_USBD_VIDEO_LOG_LEVEL_DBG=y
CONFIG_SAMPLE_USBD_PID=0x000B
CONFIG_SAMPLE_USBD_PRODUCT="UVC sample"
13 changes: 13 additions & 0 deletions samples/subsys/usb/uvc/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
sample:
name: USB Video sample
tests:
sample.subsys.usb.uvc:
depends_on:
- usbd
- video
tags: usb video
platform_allow:
- nrf52840dongle
- mini_stm32h743
- rpi_pico
harness: TBD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBD ?

Copy link
Collaborator Author

@josuah josuah Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBD for "To Be Done", TODO would have been more conventional...

I need to add a proper test harness for this sample.
This might require the user to quickly react to start the stream on the host computer before a test timeout is reached...
I can take inspiration on the other video tests maybe.

Loading
Loading