Re: [PATCH v2 2/2] media: uvc: limit max bandwidth for HDMI capture

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 6 Jan 2025 at 15:09, Hans de Goede <hdegoede@xxxxxxxxxx> wrote:
>
> From: Mauro Carvalho Chehab <mchehab+huawei@xxxxxxxxxx>
>
> This device:
>         534d:2109 MacroSilicon
>
> Announces that it supports several frame intervals for
> their resolutions for MJPEG compression:
>
>         VideoStreaming Interface Descriptor:
>         bLength                            46
>         bDescriptorType                    36
>         bDescriptorSubtype                  7 (FRAME_MJPEG)
>         bFrameIndex                         1
>         bmCapabilities                   0x00
>           Still image unsupported
>         wWidth                           1920
>         wHeight                          1080
>         dwMinBitRate                   768000
>         dwMaxBitRate                196608000
>         dwMaxVideoFrameBufferSize     4147200
>         dwDefaultFrameInterval         166666
>         bFrameIntervalType                  5
>         dwFrameInterval( 0)            166666
>         dwFrameInterval( 1)            333333
>         dwFrameInterval( 2)            400000
>         dwFrameInterval( 3)            500000
>         dwFrameInterval( 4)           1000000
>
> However, the highest frame interval (166666), which means 60 fps
> is not supported. If set to it, URB packages will be dropped,
> causing JPEG decoding errors and part of the video frames will
> be missed.
>
> Also, as specified at the device's documentation, for such
> resolution, the maximum interval is 30 fps (interval == 333333).
>
> The last format that supports such frame interval is 1280x720.
>
> Add a quirk to estimate a raw bandwidth, by doing:
>         width * height * framerate
> E. g.:
>         1920 * 1080 * 30 = 62208000
>
> if the bandwidth is greater than such threshold, get
> the next value from the dwFrameInterval.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@xxxxxxxxxx>
> Link: https://lore.kernel.org/r/bca0634691cea503c2c5df62b98ba66f0c85bf85.1624350539.git.mchehab+huawei@xxxxxxxxxx
> [hdegoede@xxxxxxxxxx add "pixels per second" comment, use UVC_FIVAL_DENOM]
> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx>
> ---
>  drivers/media/usb/uvc/uvc_driver.c | 14 ++++++++++++++
>  drivers/media/usb/uvc/uvc_video.c  | 29 ++++++++++++++++++++++++++---
>  drivers/media/usb/uvc/uvcvideo.h   |  1 +
>  3 files changed, 41 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index f754640fddf5..6d001d4f0902 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -2491,6 +2491,11 @@ static const struct uvc_device_info uvc_quirk_fix_bandwidth = {
>         .quirks = UVC_QUIRK_FIX_BANDWIDTH,
>  };
>
> +static const struct uvc_device_info uvc_quirk_fix_bw_622 = {
> +       .quirks = UVC_QUIRK_FIX_BANDWIDTH,
> +       .max_bandwidth = 62208000,
> +};
> +
>  static const struct uvc_device_info uvc_quirk_probe_def = {
>         .quirks = UVC_QUIRK_PROBE_DEF,
>  };
> @@ -2794,6 +2799,15 @@ static const struct usb_device_id uvc_ids[] = {
>           .bInterfaceSubClass   = 1,
>           .bInterfaceProtocol   = 0,
>           .driver_info          = (kernel_ulong_t)&uvc_quirk_fix_bandwidth },
> +       /* MacroSilicon HDMI capture */
> +       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
> +                               | USB_DEVICE_ID_MATCH_INT_INFO,
> +         .idVendor             = 0x534d,
> +         .idProduct            = 0x2109,
> +         .bInterfaceClass      = USB_CLASS_VIDEO,
> +         .bInterfaceSubClass   = 1,
> +         .bInterfaceProtocol   = 0,
> +         .driver_info          = (kernel_ulong_t)&uvc_quirk_fix_bw_622 },
>         /* Genesys Logic USB 2.0 PC Camera */
>         { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
>                                 | USB_DEVICE_ID_MATCH_INT_INFO,
> diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
> index 41cb1b45fa23..af5233ab667e 100644
> --- a/drivers/media/usb/uvc/uvc_video.c
> +++ b/drivers/media/usb/uvc/uvc_video.c
> @@ -225,9 +225,32 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
>         if ((ctrl->dwMaxPayloadTransferSize & 0xffff0000) == 0xffff0000)
>                 ctrl->dwMaxPayloadTransferSize &= ~0xffff0000;
>
> -       if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) &&
> -           stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
> -           stream->intf->num_altsetting > 1) {
> +       if (!(stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH))
> +               return;
> +
> +       /* Handle UVC_QUIRK_FIX_BANDWIDTH */
> +

Shouldn't this quirk be better implemented in uvc_try_frame_interval() ?

> +       if (format->flags & UVC_FMT_FLAG_COMPRESSED) {
> +               u32 bandwidth;
> +
> +               if (!stream->dev->info->max_bandwidth || !frame->bFrameIntervalType)
> +                       return;
> +
> +               for (i = 0; i < frame->bFrameIntervalType; ++i) {
> +                       bandwidth = frame->wWidth * frame->wHeight;
> +                       bandwidth *= UVC_FIVAL_DENOM / frame->dwFrameInterval[i];

frame->dwFrameInterval[i] comes from the device, it is not sanitized.
We need to make sure it is not zero.

> +
> +                       if (bandwidth <= stream->dev->info->max_bandwidth)
> +                               break;
> +               }
> +
> +               if (ctrl->dwFrameInterval < frame->dwFrameInterval[i])
> +                       ctrl->dwFrameInterval = frame->dwFrameInterval[i];
> +
> +               return;
> +       }
> +
> +       if (stream->intf->num_altsetting > 1) {
>                 u32 interval;
>                 u32 bandwidth;
>
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 966ff82c2ba8..6b702219173f 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -535,6 +535,7 @@ static inline u32 uvc_urb_index(const struct uvc_urb *uvc_urb)
>
>  struct uvc_device_info {
>         u32     quirks;
> +       u32     max_bandwidth; /* In pixels per second */
>         u32     meta_format;
>         u16     uvc_version;
>  };
> --
> 2.47.1
>
>


-- 
Ricardo Ribalda




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux