Re: [PATCH] media: uvcvideo: Add bandwidth_cap module param

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

 



Hi Laurent,

On Sun, 23 Aug 2020 at 23:34, Laurent Pinchart
<laurent.pinchart@xxxxxxxxxxxxxxxx> wrote:
>
> Hi Andrew,
>
> Thank you for the patch.
>
> On Fri, Aug 21, 2020 at 11:00:38PM +0100, Andrew Murray wrote:
> > Many UVC devices report larger values for dwMaxPayloadTransferSize than
> > appear to be required. This results in less bandwidth available for
> > other devices.
> >
> > This problem is commonly observed when attempting to stream from multiple
> > UVC cameras with the host controller returning -ENOSPC and sometimes a
> > warning (XHCI controllers: "Not enough bandwidth for new device state.").
> >
> > For uncompressed video, the UVC_QUIRK_FIX_BANDWIDTH works around this issue
> > by overriding the device provided dwMaxPayloadTransferSize with a
> > calculation of the actual bandwidth requirements from the requested frame
> > size and rate. However for compressed video formats it's not practical to
> > estimate the bandwidth required as the kernel doesn't have enough
> > information.
> >
> > Let's provide a pragmatic solution by allowing the user to impose an upper
> > threshold to the amount of bandwidth each UVC device can reserve. If the
> > parameter isn't used then no threshold is imposed.
>
> Hmmmm... This is a bit annoying as it will apply equally to all formats
> and all cameras. It may solve a real issue, but it's quite a bit of a
> hack.

Yes you're right. There is certainly a real issue here though, if you google
'usb web cam no space left on device' or similar, you'll find plenty
of people having
issues. Many of those which could be resolved with a patch like this.
Part of the
motivation for sharing this patch was so that those people may come across this
patch rather than hack their own or give up - though I'd prefer to
make this less of a
hack.

I could respin this to only apply for UVC_FMT_FLAG_COMPRESSED formats, as
if there is a problem with compressed video then a better solution is to use the
existing UVC_QUIRK_FIX_BANDWIDTH.

I didn't add this as a quirk that is only applied to specific
idVendor/idProducts, as I
felt the list might get large, and in any case my assumption is that
most of the people
that suffer from this issue will likely have a specific camera setup
and a bandwidth cap
wouldn't cause any issues - for example if you have 4 cameras on a
EHCI (perhaps with
one camera with a bandwidth issue) platform - then you could cap all
cameras high at
90Mbps - that would resolve the camera with the bandwidth issue but
not likely affect the
other cameras.  (Many cameras that I've played with seem to request 195 Mbps).

> I'm also concerned that users will be confused regarding how to
> use this parameter properly, as there's no documentation that explains
> its usage, and how to pick a proper value. Is there any way we could do
> better ?

I'm happy to write some, though I couldn't find any (in-tree) for the
existing parameters
(uvc_no_drop_param, uvc_trace_param, etc) so I wasn't sure the best
place for this.
Any suggestions?

Just as per the UVC_QUIRK_FIX_BANDWIDTH quirk, this works by adjusting
dwMaxPayloadTransferSize, which results in the kernel selecting a different USB
alternate configuration from those made available by the device. It selects a
configuration that matches or provides more bandwidth than that
requested. I'm not
sure what happens if you stream at a high resolution but select an
alternate configuration
that has a (too) low bandwidth, perhaps it depends on the camera. It
also requires
knowledge of the camera to determine how much bandwidth it genuinely
needs. Without
such knowledge - the best approach is to come up with a reasonable
estimate of bandwidth
based on compression codec, framesize, rate, etc, look at the
available alternate configs
(e.g. from lsusb), and then set a value of bandwidth_cap larger than
that required. And then
of course test to see if it meets your needs.

Thanks,

Andrew Murray

>
> > Signed-off-by: Andrew Murray <amurray@xxxxxxxxxxxxxxxxxxxx>
> > ---
> >  drivers/media/usb/uvc/uvc_driver.c | 3 +++
> >  drivers/media/usb/uvc/uvc_video.c  | 8 ++++++++
> >  drivers/media/usb/uvc/uvcvideo.h   | 1 +
> >  3 files changed, 12 insertions(+)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> > index 431d86e1c94b..d5ecac7fc264 100644
> > --- a/drivers/media/usb/uvc/uvc_driver.c
> > +++ b/drivers/media/usb/uvc/uvc_driver.c
> > @@ -33,6 +33,7 @@ unsigned int uvc_no_drop_param;
> >  static unsigned int uvc_quirks_param = -1;
> >  unsigned int uvc_trace_param;
> >  unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
> > +unsigned int uvc_bandwidth_cap_param;
> >
> >  /* ------------------------------------------------------------------------
> >   * Video formats
> > @@ -2389,6 +2390,8 @@ module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
> >  MODULE_PARM_DESC(trace, "Trace level bitmask");
> >  module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
> >  MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
> > +module_param_named(bandwidth_cap, uvc_bandwidth_cap_param, uint, S_IRUGO|S_IWUSR);
> > +MODULE_PARM_DESC(bandwidth_cap, "Maximum bandwidth per device");
> >
> >  /* ------------------------------------------------------------------------
> >   * Driver initialization and cleanup
> > diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
> > index a65d5353a441..74a0dc0614cf 100644
> > --- a/drivers/media/usb/uvc/uvc_video.c
> > +++ b/drivers/media/usb/uvc/uvc_video.c
> > @@ -196,6 +196,14 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
> >
> >               ctrl->dwMaxPayloadTransferSize = bandwidth;
> >       }
> > +
> > +     if (uvc_bandwidth_cap_param &&
> > +         ctrl->dwMaxPayloadTransferSize > uvc_bandwidth_cap_param) {
> > +             uvc_trace(UVC_TRACE_VIDEO,
> > +                     "Bandwidth capped from %u to %u B/frame.\n",
> > +                     ctrl->dwMaxPayloadTransferSize, uvc_bandwidth_cap_param);
> > +             ctrl->dwMaxPayloadTransferSize = uvc_bandwidth_cap_param;
> > +     }
> >  }
> >
> >  static size_t uvc_video_ctrl_size(struct uvc_streaming *stream)
> > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > index 6ab972c643e3..c7d9220c9a7a 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -718,6 +718,7 @@ extern unsigned int uvc_no_drop_param;
> >  extern unsigned int uvc_trace_param;
> >  extern unsigned int uvc_timeout_param;
> >  extern unsigned int uvc_hw_timestamps_param;
> > +extern unsigned int uvc_bandwidth_cap_param;
> >
> >  #define uvc_trace(flag, msg...) \
> >       do { \
>
> --
> Regards,
>
> Laurent Pinchart



[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