Signed-off-by: Alexey Fisher <bug-tr...@fisher-privat.net> --- drivers/media/video/uvc/uvc_video.c | 59 ++++++++++++++++++++++++++++++----- 1 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 64bd1d6..5380189 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -92,10 +92,9 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, { struct uvc_format *format; struct uvc_frame *frame = NULL; + struct usb_host_endpoint *ep; unsigned int i; - pr_debug("%s", __func__); - if (ctrl->bFormatIndex <= 0 || ctrl->bFormatIndex > stream->nformats) return; @@ -112,6 +111,9 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, if (frame == NULL) return; + pr_debug("%s: %s %ux%u", __func__, + format->name, frame->wWidth, frame->wHeight); + if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) || (ctrl->dwMaxVideoFrameSize == 0 && stream->dev->uvc_version < 0x0110) || @@ -123,11 +125,13 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, frame->dwMaxVideoFrameBufferSize; } - if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) && + if ((!(format->flags & UVC_FMT_FLAG_COMPRESSED) || + format->fcc == V4L2_PIX_FMT_MJPEG ) && stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH && stream->intf->num_altsetting > 1) { u32 interval; u32 bandwidth; + unsigned int best_psize = 3 * 1024; interval = (ctrl->dwFrameInterval > 100000) ? ctrl->dwFrameInterval @@ -139,13 +143,17 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, * high-speed devices) per second and add the UVC header size * (assumed to be 12 bytes long). */ - bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp; + bandwidth = frame->dwMaxVideoFrameBufferSize; + //bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp; bandwidth *= 10000000 / interval + 1; bandwidth /= 1000; if (stream->dev->udev->speed == USB_SPEED_HIGH) bandwidth /= 8; bandwidth += 12; + /* add 20% more, in some cases it is still not enough */ + bandwidth *= 1.2; + /* The bandwidth estimate is too low for many cameras. Don't use * maximum packet sizes lower than 1024 bytes to try and work * around the problem. According to measurements done on two @@ -153,12 +161,39 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, * resolutions working while not preventing two simultaneous * VGA streams at 15 fps. */ + pr_debug("%s: calculated bandwidth: %u for %u(fps); (before 1024 workaround).", + __func__, bandwidth, 10000000/interval); bandwidth = max_t(u32, bandwidth, 1024); + i = 0; + for (i = 0; i < stream->intf->num_altsetting; ++i) { + struct usb_host_interface *alts; + struct usb_host_endpoint *ep; + unsigned int psize; + + alts = &stream->intf->altsetting[i]; + ep = uvc_find_endpoint(alts, + stream->header.bEndpointAddress); + if (ep == NULL) + continue; + + psize = le16_to_cpu(ep->desc.wMaxPacketSize); + psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); + if ((psize >= bandwidth && psize <= best_psize) || + (i == stream->intf->num_altsetting - 1)) { + if (bandwidth > psize) + pr_debug("%s: trying psize=%u even if " + "bandwidth=%u", __func__, + psize, bandwidth); + best_psize = psize; + break; + } + } + pr_debug("%s: rewrite dwMaxPayloadTransferSize=%u to %u.", - __func__, ctrl->dwMaxPayloadTransferSize, bandwidth); + __func__, ctrl->dwMaxPayloadTransferSize, best_psize); - ctrl->dwMaxPayloadTransferSize = bandwidth; + ctrl->dwMaxPayloadTransferSize = best_psize; } } @@ -1099,11 +1134,19 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) /* Check if the bandwidth is high enough. */ psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - if (psize >= bandwidth && psize <= best_psize) { + pr_debug("%s: bandwidth: %u; psize: %u; best_psize: %u", + __func__, bandwidth, psize, best_psize); + if ((psize >= bandwidth && psize <= best_psize) || + (i == intf->num_altsetting - 1)) { + if (bandwidth > psize) + pr_debug("%s: trying psize=%u even if " + "bandwidth=%u", __func__, + psize, bandwidth); altsetting = i; best_psize = psize; best_ep = ep; - } + break; + } } if (best_ep == NULL) { -- 1.7.1 _______________________________________________ Linux-uvc-devel mailing list Linux-uvc-devel@lists.berlios.de https://lists.berlios.de/mailman/listinfo/linux-uvc-devel