mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
media: uvcvideo: Refactor frame parsing code into a uvc_parse_frame function
The ftype value does not change in the while loop so we can check it before entering the while loop. Refactoring the frame parsing code into a dedicated uvc_parse_frame function makes this more readable. Signed-off-by: Benoit Sevens <bsevens@google.com> Link: https://lore.kernel.org/r/20241107142204.1182969-3-bsevens@google.com Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
parent
840fb2c339
commit
082dd785e2
|
@ -220,20 +220,127 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev,
|
|||
* Descriptors parsing
|
||||
*/
|
||||
|
||||
static int uvc_parse_frame(struct uvc_device *dev,
|
||||
struct uvc_streaming *streaming,
|
||||
struct uvc_format *format, struct uvc_frame *frame,
|
||||
u32 **intervals, u8 ftype, int width_multiplier,
|
||||
const unsigned char *buffer, int buflen)
|
||||
{
|
||||
struct usb_host_interface *alts = streaming->intf->cur_altsetting;
|
||||
unsigned int maxIntervalIndex;
|
||||
unsigned int interval;
|
||||
unsigned int i, n;
|
||||
|
||||
if (ftype != UVC_VS_FRAME_FRAME_BASED)
|
||||
n = buflen > 25 ? buffer[25] : 0;
|
||||
else
|
||||
n = buflen > 21 ? buffer[21] : 0;
|
||||
|
||||
n = n ? n : 3;
|
||||
|
||||
if (buflen < 26 + 4 * n) {
|
||||
uvc_dbg(dev, DESCR,
|
||||
"device %d videostreaming interface %d FRAME error\n",
|
||||
dev->udev->devnum, alts->desc.bInterfaceNumber);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
frame->bFrameIndex = buffer[3];
|
||||
frame->bmCapabilities = buffer[4];
|
||||
frame->wWidth = get_unaligned_le16(&buffer[5]) * width_multiplier;
|
||||
frame->wHeight = get_unaligned_le16(&buffer[7]);
|
||||
frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
|
||||
frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
|
||||
if (ftype != UVC_VS_FRAME_FRAME_BASED) {
|
||||
frame->dwMaxVideoFrameBufferSize =
|
||||
get_unaligned_le32(&buffer[17]);
|
||||
frame->dwDefaultFrameInterval =
|
||||
get_unaligned_le32(&buffer[21]);
|
||||
frame->bFrameIntervalType = buffer[25];
|
||||
} else {
|
||||
frame->dwMaxVideoFrameBufferSize = 0;
|
||||
frame->dwDefaultFrameInterval =
|
||||
get_unaligned_le32(&buffer[17]);
|
||||
frame->bFrameIntervalType = buffer[21];
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the frame intervals.
|
||||
*
|
||||
* Some bogus devices report dwMinFrameInterval equal to
|
||||
* dwMaxFrameInterval and have dwFrameIntervalStep set to zero. Setting
|
||||
* all null intervals to 1 fixes the problem and some other divisions
|
||||
* by zero that could happen.
|
||||
*/
|
||||
frame->dwFrameInterval = *intervals;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
interval = get_unaligned_le32(&buffer[26 + 4 * i]);
|
||||
(*intervals)[i] = interval ? interval : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply more fixes, quirks and workarounds to handle incorrect or
|
||||
* broken descriptors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Several UVC chipsets screw up dwMaxVideoFrameBufferSize completely.
|
||||
* Observed behaviours range from setting the value to 1.1x the actual
|
||||
* frame size to hardwiring the 16 low bits to 0. This results in a
|
||||
* higher than necessary memory usage as well as a wrong image size
|
||||
* information. For uncompressed formats this can be fixed by computing
|
||||
* the value from the frame size.
|
||||
*/
|
||||
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
|
||||
frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth
|
||||
* frame->wHeight / 8;
|
||||
|
||||
/*
|
||||
* Clamp the default frame interval to the boundaries. A zero
|
||||
* bFrameIntervalType value indicates a continuous frame interval
|
||||
* range, with dwFrameInterval[0] storing the minimum value and
|
||||
* dwFrameInterval[1] storing the maximum value.
|
||||
*/
|
||||
maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1;
|
||||
frame->dwDefaultFrameInterval =
|
||||
clamp(frame->dwDefaultFrameInterval,
|
||||
frame->dwFrameInterval[0],
|
||||
frame->dwFrameInterval[maxIntervalIndex]);
|
||||
|
||||
/*
|
||||
* Some devices report frame intervals that are not functional. If the
|
||||
* corresponding quirk is set, restrict operation to the first interval
|
||||
* only.
|
||||
*/
|
||||
if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
|
||||
frame->bFrameIntervalType = 1;
|
||||
(*intervals)[0] = frame->dwDefaultFrameInterval;
|
||||
}
|
||||
|
||||
uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n",
|
||||
frame->wWidth, frame->wHeight,
|
||||
10000000 / frame->dwDefaultFrameInterval,
|
||||
(100000000 / frame->dwDefaultFrameInterval) % 10);
|
||||
|
||||
*intervals += n;
|
||||
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
static int uvc_parse_format(struct uvc_device *dev,
|
||||
struct uvc_streaming *streaming, struct uvc_format *format,
|
||||
struct uvc_frame *frames, u32 **intervals, const unsigned char *buffer,
|
||||
int buflen)
|
||||
{
|
||||
struct usb_interface *intf = streaming->intf;
|
||||
struct usb_host_interface *alts = intf->cur_altsetting;
|
||||
struct usb_host_interface *alts = streaming->intf->cur_altsetting;
|
||||
const struct uvc_format_desc *fmtdesc;
|
||||
struct uvc_frame *frame;
|
||||
const unsigned char *start = buffer;
|
||||
unsigned int width_multiplier = 1;
|
||||
unsigned int interval;
|
||||
unsigned int i, n;
|
||||
u8 ftype;
|
||||
int ret;
|
||||
|
||||
format->type = buffer[2];
|
||||
format->index = buffer[3];
|
||||
|
@ -371,111 +478,19 @@ static int uvc_parse_format(struct uvc_device *dev,
|
|||
* Parse the frame descriptors. Only uncompressed, MJPEG and frame
|
||||
* based formats have frame descriptors.
|
||||
*/
|
||||
while (ftype && buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
|
||||
buffer[2] == ftype) {
|
||||
unsigned int maxIntervalIndex;
|
||||
|
||||
frame = &frames[format->nframes];
|
||||
if (ftype != UVC_VS_FRAME_FRAME_BASED)
|
||||
n = buflen > 25 ? buffer[25] : 0;
|
||||
else
|
||||
n = buflen > 21 ? buffer[21] : 0;
|
||||
|
||||
n = n ? n : 3;
|
||||
|
||||
if (buflen < 26 + 4*n) {
|
||||
uvc_dbg(dev, DESCR,
|
||||
"device %d videostreaming interface %d FRAME error\n",
|
||||
dev->udev->devnum,
|
||||
alts->desc.bInterfaceNumber);
|
||||
return -EINVAL;
|
||||
if (ftype) {
|
||||
while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
|
||||
buffer[2] == ftype) {
|
||||
frame = &frames[format->nframes];
|
||||
ret = uvc_parse_frame(dev, streaming, format, frame,
|
||||
intervals, ftype, width_multiplier,
|
||||
buffer, buflen);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
format->nframes++;
|
||||
buflen -= ret;
|
||||
buffer += ret;
|
||||
}
|
||||
|
||||
frame->bFrameIndex = buffer[3];
|
||||
frame->bmCapabilities = buffer[4];
|
||||
frame->wWidth = get_unaligned_le16(&buffer[5])
|
||||
* width_multiplier;
|
||||
frame->wHeight = get_unaligned_le16(&buffer[7]);
|
||||
frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
|
||||
frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
|
||||
if (ftype != UVC_VS_FRAME_FRAME_BASED) {
|
||||
frame->dwMaxVideoFrameBufferSize =
|
||||
get_unaligned_le32(&buffer[17]);
|
||||
frame->dwDefaultFrameInterval =
|
||||
get_unaligned_le32(&buffer[21]);
|
||||
frame->bFrameIntervalType = buffer[25];
|
||||
} else {
|
||||
frame->dwMaxVideoFrameBufferSize = 0;
|
||||
frame->dwDefaultFrameInterval =
|
||||
get_unaligned_le32(&buffer[17]);
|
||||
frame->bFrameIntervalType = buffer[21];
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the frame intervals.
|
||||
*
|
||||
* Some bogus devices report dwMinFrameInterval equal to
|
||||
* dwMaxFrameInterval and have dwFrameIntervalStep set to
|
||||
* zero. Setting all null intervals to 1 fixes the problem and
|
||||
* some other divisions by zero that could happen.
|
||||
*/
|
||||
frame->dwFrameInterval = *intervals;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
interval = get_unaligned_le32(&buffer[26+4*i]);
|
||||
(*intervals)[i] = interval ? interval : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply more fixes, quirks and workarounds to handle incorrect
|
||||
* or broken descriptors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
|
||||
* completely. Observed behaviours range from setting the
|
||||
* value to 1.1x the actual frame size to hardwiring the
|
||||
* 16 low bits to 0. This results in a higher than necessary
|
||||
* memory usage as well as a wrong image size information. For
|
||||
* uncompressed formats this can be fixed by computing the
|
||||
* value from the frame size.
|
||||
*/
|
||||
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
|
||||
frame->dwMaxVideoFrameBufferSize = format->bpp
|
||||
* frame->wWidth * frame->wHeight / 8;
|
||||
|
||||
/*
|
||||
* Clamp the default frame interval to the boundaries. A zero
|
||||
* bFrameIntervalType value indicates a continuous frame
|
||||
* interval range, with dwFrameInterval[0] storing the minimum
|
||||
* value and dwFrameInterval[1] storing the maximum value.
|
||||
*/
|
||||
maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1;
|
||||
frame->dwDefaultFrameInterval =
|
||||
clamp(frame->dwDefaultFrameInterval,
|
||||
frame->dwFrameInterval[0],
|
||||
frame->dwFrameInterval[maxIntervalIndex]);
|
||||
|
||||
/*
|
||||
* Some devices report frame intervals that are not functional.
|
||||
* If the corresponding quirk is set, restrict operation to the
|
||||
* first interval only.
|
||||
*/
|
||||
if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
|
||||
frame->bFrameIntervalType = 1;
|
||||
(*intervals)[0] = frame->dwDefaultFrameInterval;
|
||||
}
|
||||
|
||||
uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n",
|
||||
frame->wWidth, frame->wHeight,
|
||||
10000000 / frame->dwDefaultFrameInterval,
|
||||
(100000000 / frame->dwDefaultFrameInterval) % 10);
|
||||
|
||||
format->nframes++;
|
||||
*intervals += n;
|
||||
|
||||
buflen -= buffer[0];
|
||||
buffer += buffer[0];
|
||||
}
|
||||
|
||||
if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
|
||||
|
|
Loading…
Reference in New Issue
Block a user