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]

 



Hi,

On 6-Jan-25 3:48 PM, Ricardo Ribalda wrote:
> 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() ?

This is the place where the other bandwidth checks / UVC_QUIRK_FIX_BANDWIDTH
handling is done, so I guess it makes sense to keep this here.

>> +       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.

That is a good point, in the non-compressed UVC_QUIRK_FIX_BANDWIDTH handling
this is handled by doing:

			bandwidth *= UVC_FIVAL_DENOM / (frame->dwFrameInterval[i] + 1);

I guess we should do the same here then ?

Regards,

Hans



> 
>> +
>> +                       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
>>
>>
> 
> 





[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