-
Notifications
You must be signed in to change notification settings - Fork 6.6k
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
base: main
Are you sure you want to change the base?
Conversation
I am grateful for the work on the USB and Video stacks of Zephyr, as well as the entire Zephyr tree, on the shoulder of which this is built. |
Force push:
|
Force-push:
|
.dwMinBitRate = sys_cpu_to_le32(15360000), \ | ||
.dwMaxBitRate = sys_cpu_to_le32(15360000), \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where are these values coming from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are chosen arbitrarily, and I need to think about what should I do here: pick reasonable defaults? Deduce from other values? Let the user figure out by exposing a devicetree option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In future work, it will be possible to ask the sensor for VIDEO_CID_PIXEL_RATE
in combination with video_bits_per_pixel()
to generate this field.
.bLength = sizeof(struct usb_ep_descriptor), \ | ||
.bDescriptorType = USB_DESC_ENDPOINT, \ | ||
.bEndpointAddress = 0x81, \ | ||
.bmAttributes = USB_EP_TYPE_BULK, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe UVC can be BULK or ISO.... but I only see BULK supported here. Do you plan to have a way to select which type of EP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot to mention that only BULK is supported through this early version. I will need to spend more time investigating the device_next
APIs for how ISO is implemented.
I cannot guarantee ETAs as I would do this feature on free time, but will add it to the roadmap: this will be needed at some point.
Very grateful for your reviews @XenuIsWatching I will force-push with the changes as soon as I get a chance to do so. |
Force-push:
|
182ac7c
to
cec26cc
Compare
02c1087
to
4bdc1ea
Compare
force push: rebased on |
force push: changed the way descriptors are declared and introduce video controls at the descriptor level (no support for controls commands yet) |
force push: implemented the UVC controls for the supported Video class controls. I did not test this yet with the samples, but on the internal fork, we could get an IMX219 sensor with exposure and gain control from the host, format selection at startup (but not runtime, see [1]). I believe that the last step for me is to test the sample on several boards that support |
Known limitations:[1]: there is currently no [2]: [3]: [4]: [5]: There are missing implementations for selector unit, extensions unit, encoding unit. TODO. [6]: UVC introduces dependencies between some controls, i.e. auto-expopsure needs to be off for exposure to be accepted. TODO. [7]: [8]: [9]: [10]: Supports custom header size, but not passing custom header data yet. [11]: Still image capture (capturing one frame at full resolution) not supported. [12]: USB3CV compliance tests not all passing since last rebase. TODO. [13]: Announcing different resolutions/FPS for different connection speed not supported. [14]: Asynchronous controls (the host setting a control, and a notification interrupt alert of completion) not supported. Supported features:[A]: Class API and enumeration [B]: [C]: [D]: [E]: Handling of control commands end-to-end from host to Zephyr video device [F]: Zephyr native Video API that allows to enqueue/dequeue frames like any other Zephyr video device. [G]: Supports fragmented frames as discussed in #66994 and #72827 [H]: [I]: Supports querying the min/max/current values of every controls end-to-end from host to Zephyr video driver. |
a7cd6cb
to
ea60ec0
Compare
@josuah Thanks for considering my comments. They are all strictly optional of course (as you have treated them) because I know virtually nothing about UVC. Happy that there were a few useful things among my misunderstandings. ;-)
I understand your dilemma. These are application configuration properties which we do not (yet) have a good place for (although we're actively working on it). From a dogmatic viewpoint some of these settings are obviously not hardware properties (as they change with application requirements not with hardware). But as we don't have a good alternative for such settings right now, you're not the first to encounter such a dilemma. I'd be inclined to have those properties (lowercased and as closely modeled around the standard UVC data structures) in DT for the moment being as we'll have to migrate several DT properties to software settings anyway once the config infrastructure is in place. This will be easier if we migrate from DT rather than from macros. @decsny In the end it is of course entirely your call. Just thinking out loudly. I'll be presenting my software settings poc in the upcoming arch WG probably. This would be one of the first things I'd write a configuration handler for. |
Given #77638 it might be interesting to provide a temporary solution that upgrades gracefully to a dedicated configuration system.
Linux also uses an extra userspace library to abstract the USB protocol which fills ⭕ this grid almost completely. Here is the Rosetta Stone between Linux, UVC and this PR:
See the configurationuvc.0 |- streaming/ | |- class | | |- h | | |- hs | | | '- h | | |- fs | | | '- h | | |- ss | | | '- h | | '- ... | |- color_matching | | '- ... | |- header | | '- h | |- mjpeg format_mjpeg {...}; | | | '- uncompressed format_uncompressed { | |- u | |- bAspectRatioX /* not used */ | |- bAspectRatioY /* not used */ | |- bBitsPerPixel bits-per-pixel = <2>; | |- bDefaultFrameIndex | |- bmInterfaceFlags /* not used */ | |- bmaControls /* not used */ | |- guidFormat | | [v4l2-ctl -d /dev/videoX ...] fourcc = "YUY2"; | | | '- 360p 360p { | |- bmCapabilities | |- dwDefaultFrameInterval | |- dwFrameInterval max-fps = <30 60>; | |- dwMaxBitRate | |- dwMaxVideoFrameBufferSize | |- dwMinBitRate | |- wHeight size = <480 360>; | '- wWidth | }; | }; '- control/ |- h |- ct.0 uvc0_ct0: camera_terminal { | |- bmControls [1] control-exposure-time-absolute; | | control-ae-mode; | | ... | | [v4l2 event] control-target = <&imx219>; | '- baSourceID | }; |- pu.0 uvc0_pu0: processing_unit { | |- bmControls [1] control-gain; | | control-hue; | | control-saturation; | | control-brightness; | | ... | '- baSourceID source-entity = <&uvc0_ct0>; | [v4l2 event] control-target = <&imx219>; | }; | '- ot.0 uvc0_ot0: processing_unit { | '- baSourceID source-entity = <&uvc0_pu0>; [v4l2 event] control-target = <&mipi0>; }; [1]: The USB standard is tricky about it: the control IDs and the control enable flags are shuffled for just a few items, so easy to get mistaken. In the current PR, the bitmap is decoded, every field described, and WIP mapped to native Zephyr video controls. [2]: UVC controls (i.e. tune the exposure) are not yet supported in the current Linux user-space utility, but are still possible with a custom format. The current Zephyr implementation brings a good leap in reducing the amount of duplicated configuration between the drivers and the protocol. It is possible to reduce it further if using run-time configuration:
[EDIT: wording, typos] |
My first impression to something called "software settings" is that the component would be handling the non-volatile settings. But here the UVC bindings, just like UAC2 bindings are pretty much read-only descriptions. These do describe what is possible and can offer a choice, but the choice is volatile. The choice (e.g. selected sample rate in UAC2 case) lifetime is entirely controlled by host (can be abruptly terminated by user pulling the USB cable) and essentially is no longer valid after USB bus reset. |
Not exactly. Some consensus seems to build in the arch WG around a combination of read-only (build-time), provisioning (end-of-production-line/OTA) and runtime configuration closely related to macros (for build-time) and the settings subsystem (for provisioning/runtime and optionally build-time, too). The three use cases tied together through a common data model. The best metaphor I encountered so far would be a combination of sysfs and configfs which is more or less what the settings subsys API already exposes.
Still seems to be a match for the planned config system (see Linux' use of configfs to define USB gadgets on-the-run) but I'm not deep enough into USB to know for sure. I'd say, though, that keeping the same compromise as the one found for UAC2 would be ok from my perspective. I looked at those bindings and I didn't see anything especially problematic with those if we ensure that we re-use every bit of existing structure that we can find in Linux and elsewhere. |
bf701cc
to
a70b411
Compare
force-push: several features, still WIP, and a few known bugs (cannot play again after closing the client application)
The devicetree bindings addition are not USB-specific but USB is the first to need them. New configuration syntax:uvc.0 uvc: uvc { | compatible = "zephyr,uvc-device"; | |- streaming/ port { | |- class uvc_in: endpoint { | | | remote-endpoint-label = "mipi0_ep_out"; | | |- h | | |- hs | | | '- h | | |- fs | | | '- h | | |- ss /* empty */ | | | '- h | | '- ... | |- color_matching | | '- ... | |- header | | '- h | |- mjpeg | | '- ... | '- uncompressed | |- u | |- bAspectRatioX | |- bAspectRatioY | |- bBitsPerPixel | |- bDefaultFrameIndex | |- bmInterfaceFlags | |- bmaControls | |- guidFormat | | [v4l2-ctl -d /dev/videoX ...] | '- 360p | |- bmCapabilities | |- dwDefaultFrameInterval | |- dwFrameInterval | |- dwMaxBitRate | |- dwMaxVideoFrameBufferSize | |- dwMinBitRate | |- wHeight | '- wWidth '- control/ |- h |- ct.0 /* empty */ | |- bmControls [1] | | [v4l2 event] | '- baSourceID |- pu.0 | |- bmControls [1] | '- baSourceID | [v4l2 event] '- ot.0 '- baSourceID [v4l2 event] }; }; New feature comparison table
I hope I could have been introducing this the first time, to save everyone review time. |
The intended usage is now:
[EDIT: updated as per latest commit] |
d58ad01
to
1b71b2e
Compare
force-push:
Tested on STM32H743, Raspberry Pi Pico, and WIP FRDM-MCXN947 (UDC error messages... maybe buffer alignment). The only requirement is USB
Known quirks:
In hope this version goes in the right direction from previous review, and that it costs few time to reviewers in this form. |
@josuah could you share your test setup for this PR? I'm intending to use my Arduino NIcla Vision for that. |
Yes sure! The only requirement is having an USB driver compatible with device-next. This board uses a similar chip as the Nicla.
This shows how to convert an STM32H743 board from using Do feel free to discuss this on Discord or this discussion. |
3ca9db4
to
8912f85
Compare
force-push:
|
59824ea
to
b3bdb56
Compare
force-push:
|
1b76274
to
f5c6a99
Compare
The video_get_ctrl() API permits to retrieve a value from a device using standard CIDs from <zephyr/drivers/video-controls.h>. The CIDs do not come with a range information, and to know which value to apply to a video driver, knowing the minimum and maximum value before-hand is required. This prevents building generic layers that handle any video devices, such as protocols such as USB UVC, GigE Vision, or anything making use of "zephyr,camera" chosen node. This commit introduces extra flags added to the CIDs that indicates to the target device that instead of returning the current value, they should return the minimum, maximum, or default value instead, with the same type as the current value. The GET_CUR operation having a flag of 0x00, this makes all drivers implicitly support this new API, with an opt-in migration to also support the extra controls, correctly rejecting the unsupported extra operations by default. Signed-off-by: Josuah Demangeon <[email protected]>
PR zephyrproject-rtos#79482 is where this commit would be added Signed-off-by: Josuah Demangeon <[email protected]>
Introduce a new USB Video Class (UVC) implementation from scratch. It exposes a native Zephyr Video driver interface, allowing to call the video_enqueue()/video_dequeue() interface. It will query the attached video device to learn about the pipeline capabilities, and use this to configure the USB descriptors. At runtime, this UVC implementation will send this device all the control requests, which it can then dispatch to the rest of the pipeline. The application can poll the format currently selected by the host, but will not be alerted when the host configures a new format, as there is no video.h API for it yet. Signed-off-by: Josuah Demangeon <[email protected]>
force-push:
P.S.: support for other operating system is planned but WIP. |
Dependencies:
drivers: video: introduce "GET" sub-operations #78603replaced by something else to comedrivers: video: allow allocation with a header preceding the buffer #79168not required anymoreThis is a preview of an USB Video Class implementation for Zephyr that was only tested on custom devices insofar.
Proper Zephyr samples will be provided on upcoming commits. The API is simply to submit frames to the UVC device like to any Zephyr video device.
There is an unsolved challenge around the Video API: there is no
set_format
because the Zephyr application cannot decide what the host uses, onlyget_format
for what the host does support. But there is a missing video API to allow the driver to warn the application about a forced format change requested by the host. I thought of maybe reusingset_signal()
to also warn about format changes and not just buffer events.I will now work on building examples for existing Zephyr devices, as this was built for a custom USB3 board.
Here is the devicetree configuration used insofar:
The sizes and FPS are to be selected by the developer. The USB descriptors get configured as described above, and the host will request a particular format. Once that is done, the USB Video Class driver can let the application know which of these was selected through the video.hget_format()
API.This is still a draft PR, but I am grateful for comments and suggestions. I am willing to do the work of refactoring this as much as needed.
[EDIT: see this comment for latest description]