media: uvcvideo: Support multiple frame descriptors with the same dimensions
The Microsoft HoloLens Sensors device has two separate frame descriptors with the same dimensions, each with a single different frame interval: VideoStreaming Interface Descriptor: bLength 30 bDescriptorType 36 bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) bFrameIndex 1 bmCapabilities 0x00 Still image unsupported wWidth 1280 wHeight 481 dwMinBitRate 147763200 dwMaxBitRate 147763200 dwMaxVideoFrameBufferSize 615680 dwDefaultFrameInterval 333333 bFrameIntervalType 1 dwFrameInterval( 0) 333333 VideoStreaming Interface Descriptor: bLength 30 bDescriptorType 36 bDescriptorSubtype 5 (FRAME_UNCOMPRESSED) bFrameIndex 2 bmCapabilities 0x00 Still image unsupported wWidth 1280 wHeight 481 dwMinBitRate 443289600 dwMaxBitRate 443289600 dwMaxVideoFrameBufferSize 615680 dwDefaultFrameInterval 111111 bFrameIntervalType 1 dwFrameInterval( 0) 111111 Skip duplicate dimensions in enum_framesizes, let enum_frameintervals list the intervals from both frame descriptors. Change set_streamparm to switch to the correct frame index when changing the interval. This enables 90 fps capture on a Lenovo Explorer Windows Mixed Reality headset. [laurent.pinchart@ideasonboard.com: Renamed tmp_ival to ival] Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:

committed by
Mauro Carvalho Chehab

parent
859086ae36
commit
07b7d9fc2a
@@ -373,7 +373,10 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
|
||||
{
|
||||
struct uvc_streaming_control probe;
|
||||
struct v4l2_fract timeperframe;
|
||||
uint32_t interval;
|
||||
struct uvc_format *format;
|
||||
struct uvc_frame *frame;
|
||||
__u32 interval, maxd;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (parm->type != stream->type)
|
||||
@@ -396,9 +399,33 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
format = stream->cur_format;
|
||||
frame = stream->cur_frame;
|
||||
probe = stream->ctrl;
|
||||
probe.dwFrameInterval =
|
||||
uvc_try_frame_interval(stream->cur_frame, interval);
|
||||
probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
|
||||
maxd = abs((__s32)probe.dwFrameInterval - interval);
|
||||
|
||||
/* Try frames with matching size to find the best frame interval. */
|
||||
for (i = 0; i < format->nframes && maxd != 0; i++) {
|
||||
__u32 d, ival;
|
||||
|
||||
if (&format->frame[i] == stream->cur_frame)
|
||||
continue;
|
||||
|
||||
if (format->frame[i].wWidth != stream->cur_frame->wWidth ||
|
||||
format->frame[i].wHeight != stream->cur_frame->wHeight)
|
||||
continue;
|
||||
|
||||
ival = uvc_try_frame_interval(&format->frame[i], interval);
|
||||
d = abs((__s32)ival - interval);
|
||||
if (d >= maxd)
|
||||
continue;
|
||||
|
||||
frame = &format->frame[i];
|
||||
probe.bFrameIndex = frame->bFrameIndex;
|
||||
probe.dwFrameInterval = ival;
|
||||
maxd = d;
|
||||
}
|
||||
|
||||
/* Probe the device with the new settings. */
|
||||
ret = uvc_probe_video(stream, &probe);
|
||||
@@ -408,6 +435,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
|
||||
}
|
||||
|
||||
stream->ctrl = probe;
|
||||
stream->cur_frame = frame;
|
||||
mutex_unlock(&stream->mutex);
|
||||
|
||||
/* Return the actual frame period. */
|
||||
@@ -1146,7 +1174,8 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
|
||||
struct uvc_streaming *stream = handle->stream;
|
||||
struct uvc_format *format = NULL;
|
||||
struct uvc_frame *frame;
|
||||
int i;
|
||||
unsigned int index;
|
||||
unsigned int i;
|
||||
|
||||
/* Look for the given pixel format */
|
||||
for (i = 0; i < stream->nformats; i++) {
|
||||
@@ -1158,10 +1187,20 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
|
||||
if (format == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (fsize->index >= format->nframes)
|
||||
/* Skip duplicate frame sizes */
|
||||
for (i = 0, index = 0; i < format->nframes; i++) {
|
||||
if (i && frame->wWidth == format->frame[i].wWidth &&
|
||||
frame->wHeight == format->frame[i].wHeight)
|
||||
continue;
|
||||
frame = &format->frame[i];
|
||||
if (index == fsize->index)
|
||||
break;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (i == format->nframes)
|
||||
return -EINVAL;
|
||||
|
||||
frame = &format->frame[fsize->index];
|
||||
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
||||
fsize->discrete.width = frame->wWidth;
|
||||
fsize->discrete.height = frame->wHeight;
|
||||
@@ -1175,7 +1214,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
|
||||
struct uvc_streaming *stream = handle->stream;
|
||||
struct uvc_format *format = NULL;
|
||||
struct uvc_frame *frame = NULL;
|
||||
int i;
|
||||
unsigned int nintervals;
|
||||
unsigned int index;
|
||||
unsigned int i;
|
||||
|
||||
/* Look for the given pixel format and frame size */
|
||||
for (i = 0; i < stream->nformats; i++) {
|
||||
@@ -1187,30 +1228,28 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
|
||||
if (format == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
index = fival->index;
|
||||
for (i = 0; i < format->nframes; i++) {
|
||||
if (format->frame[i].wWidth == fival->width &&
|
||||
format->frame[i].wHeight == fival->height) {
|
||||
frame = &format->frame[i];
|
||||
break;
|
||||
nintervals = frame->bFrameIntervalType ?: 1;
|
||||
if (index < nintervals)
|
||||
break;
|
||||
index -= nintervals;
|
||||
}
|
||||
}
|
||||
if (frame == NULL)
|
||||
if (i == format->nframes)
|
||||
return -EINVAL;
|
||||
|
||||
if (frame->bFrameIntervalType) {
|
||||
if (fival->index >= frame->bFrameIntervalType)
|
||||
return -EINVAL;
|
||||
|
||||
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
|
||||
fival->discrete.numerator =
|
||||
frame->dwFrameInterval[fival->index];
|
||||
frame->dwFrameInterval[index];
|
||||
fival->discrete.denominator = 10000000;
|
||||
uvc_simplify_fraction(&fival->discrete.numerator,
|
||||
&fival->discrete.denominator, 8, 333);
|
||||
} else {
|
||||
if (fival->index)
|
||||
return -EINVAL;
|
||||
|
||||
fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
|
||||
fival->stepwise.min.numerator = frame->dwFrameInterval[0];
|
||||
fival->stepwise.min.denominator = 10000000;
|
||||
|
Reference in New Issue
Block a user