nxp-mcuxpresso / mcux-sdk

MCUXpresso SDK
BSD 3-Clause "New" or "Revised" License
339 stars 148 forks source link

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

Open Joao-Peterson opened 2 months ago

Joao-Peterson commented 2 months ago

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:

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.