mcux-sdk icon indicating copy to clipboard operation
mcux-sdk copied to clipboard

Failed to query (130) UVC probe control - Implement GETMIN for UVC PROVE_CONTROL

Open Joao-Peterson opened this issue 5 months ago • 0 comments

While attempting to compile and flash the usb_device_video_virtual_camera example, my Linux system did recognize the camera but while attempting to use it (stream in mpv player), an error popped occurred, viewing dmesg output we see: Failed to query (130) UVC probe control.

To Reproduce:

  • Environment:
    • Host OS: ArcoLinux, Kernel: 6.9.2-arch1-1
    • SDK: MCUX_2.16.000
    • Toolchain: ARMGCC 14.1.0 (arch repository)
    • Board/SoC: EVKBIMXRT1050
    • Example usb_device_video_virtual_camera
  • Steps to reproduce the behavior:
    1. Flash example.
    2. Connect USB OTG to machine.
    3. Verify that the system recognizes the demo camera.
    4. Open dmesg: sudo dmesg -w.
    5. Try streaming from camera with any app. Example with mpv: mpv av://v4l2:/dev/video#, where # is the video interface of the camera.

Reproducing yields to:

[456436.604665] usb 1-8: new high-speed USB device number 35 using xhci_hcd
[456436.748879] usb 1-8: New USB device found, idVendor=1fc9, idProduct=0099, bcdDevice= 1.01
[456436.748892] usb 1-8: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[456436.748896] usb 1-8: Product: VIDEO DEMO
[456436.748899] usb 1-8: Manufacturer: NXP SEMICONDUCTORS
[456436.750429] usb 1-8: Found UVC 1.00 device VIDEO DEMO (1fc9:0099)
[456436.750649] usb 1-8: UVC non compliance - GET_DEF(PROBE) not supported. Enabling workaround.
[456467.652504] uvcvideo 1-8:1.1: Failed to query (130) UVC probe control : -32 (exp. 26).
[456538.014794] uvcvideo 1-8:1.1: Failed to query (130) UVC probe control : -32 (exp. 26).
[456664.713807] uvcvideo 1-8:1.1: Failed to query (130) UVC probe control : -32 (exp. 26).
[456671.440197] uvcvideo 1-8:1.1: Failed to query (130) UVC probe control : -32 (exp. 26).

We would expect no errors/warnings!

Query 130 Probe control refers to 0x82 (GET_MIN) of the VS_PROBE_CONTROL UVC class request.

My current fix for this is just to implement a switch case on the US callback handle to return a default usb_device_video_probe_and_commit_controls_struct_t *probeStruct for the USB_DEVICE_VIDEO_GET_MIN_VS_PROBE_CONTROL and USB_DEVICE_VIDEO_GET_MAX_VS_PROBE_CONTROL events.

Code example:

sdk/examples/evkbimxrt1050/usb_examples/usb_device_video_virtual_camera/bm/virtual_camera.c:

// Create min and max prove struct values (justa copy from the default example)
static void InitProbeStruct(
    usb_device_video_probe_and_commit_controls_struct_t *probeStructMin,
    usb_device_video_probe_and_commit_controls_struct_t *probeStructMax
){
    probeStructMin->bFormatIndex = USB_VIDEO_VIRTUAL_CAMERA_MJPEG_FORMAT_INDEX;
    probeStructMin->bFrameIndex  = USB_VIDEO_VIRTUAL_CAMERA_MJPEG_FRAME_INDEX;
    
    USB_LONG_TO_LITTLE_ENDIAN_DATA(
        USB_VIDEO_VIRTUAL_CAMERA_MJPEG_FRAME_DEFAULT_INTERVAL,
        probeStructMin->dwFrameInterval
    );
    
    USB_LONG_TO_LITTLE_ENDIAN_DATA(
        g_UsbDeviceVideoVirtualCamera.currentMaxPacketSize,
        probeStructMin->dwMaxPayloadTransferSize
    );
    
    USB_LONG_TO_LITTLE_ENDIAN_DATA(
        USB_VIDEO_VIRTUAL_CAMERA_MJPEG_FRAME_MAX_FRAME_SIZE,
        probeStructMin->dwMaxVideoFrameSize
    );

    probeStructMax->bFormatIndex = USB_VIDEO_VIRTUAL_CAMERA_MJPEG_FORMAT_INDEX;
    probeStructMax->bFrameIndex  = USB_VIDEO_VIRTUAL_CAMERA_MJPEG_FRAME_INDEX;
    
    USB_LONG_TO_LITTLE_ENDIAN_DATA(
        USB_VIDEO_VIRTUAL_CAMERA_MJPEG_FRAME_DEFAULT_INTERVAL,
        probeStructMax->dwFrameInterval
    );
    
    USB_LONG_TO_LITTLE_ENDIAN_DATA(
        g_UsbDeviceVideoVirtualCamera.currentMaxPacketSize,
        probeStructMax->dwMaxPayloadTransferSize
    );
    
    USB_LONG_TO_LITTLE_ENDIAN_DATA(
        USB_VIDEO_VIRTUAL_CAMERA_MJPEG_FRAME_MAX_FRAME_SIZE,
        probeStructMax->dwMaxVideoFrameSize
    );
}

// On callback, added the cases for min and max
static usb_status_t USB_DeviceVideoRequest(class_handle_t handle, uint32_t event, void *param){
	...
	
	case USB_DEVICE_VIDEO_GET_MIN_VS_PROBE_CONTROL:
		request->buffer = (uint8_t *)(&probeStructMin);
		request->length = g_UsbDeviceVideoVirtualCamera.probeLength;
	break;
	
	case USB_DEVICE_VIDEO_GET_MAX_VS_PROBE_CONTROL:
		request->buffer = (uint8_t *)(&probeStructMax);
		request->length = g_UsbDeviceVideoVirtualCamera.probeLength;
	break;
	
	...
}

I know this isn't critical or anything, but for newcomers like me, it's really hard to go around without a solid example. Also, this might be a Linux thing only for my version, still, hope this helps somebody XD.

Joao-Peterson avatar Sep 09 '24 20:09 Joao-Peterson