Commit 07b7d9fc authored by Philipp Zabel's avatar Philipp Zabel Committed by Mauro Carvalho Chehab

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: default avatarPhilipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 859086ae
...@@ -373,7 +373,10 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, ...@@ -373,7 +373,10 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
{ {
struct uvc_streaming_control probe; struct uvc_streaming_control probe;
struct v4l2_fract timeperframe; struct v4l2_fract timeperframe;
uint32_t interval; struct uvc_format *format;
struct uvc_frame *frame;
__u32 interval, maxd;
unsigned int i;
int ret; int ret;
if (parm->type != stream->type) if (parm->type != stream->type)
...@@ -396,9 +399,33 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, ...@@ -396,9 +399,33 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
return -EBUSY; return -EBUSY;
} }
format = stream->cur_format;
frame = stream->cur_frame;
probe = stream->ctrl; probe = stream->ctrl;
probe.dwFrameInterval = probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
uvc_try_frame_interval(stream->cur_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. */ /* Probe the device with the new settings. */
ret = uvc_probe_video(stream, &probe); ret = uvc_probe_video(stream, &probe);
...@@ -408,6 +435,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, ...@@ -408,6 +435,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
} }
stream->ctrl = probe; stream->ctrl = probe;
stream->cur_frame = frame;
mutex_unlock(&stream->mutex); mutex_unlock(&stream->mutex);
/* Return the actual frame period. */ /* Return the actual frame period. */
...@@ -1146,7 +1174,8 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, ...@@ -1146,7 +1174,8 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
struct uvc_streaming *stream = handle->stream; struct uvc_streaming *stream = handle->stream;
struct uvc_format *format = NULL; struct uvc_format *format = NULL;
struct uvc_frame *frame; struct uvc_frame *frame;
int i; unsigned int index;
unsigned int i;
/* Look for the given pixel format */ /* Look for the given pixel format */
for (i = 0; i < stream->nformats; i++) { for (i = 0; i < stream->nformats; i++) {
...@@ -1158,10 +1187,20 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, ...@@ -1158,10 +1187,20 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
if (format == NULL) if (format == NULL)
return -EINVAL; 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; return -EINVAL;
frame = &format->frame[fsize->index];
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = frame->wWidth; fsize->discrete.width = frame->wWidth;
fsize->discrete.height = frame->wHeight; fsize->discrete.height = frame->wHeight;
...@@ -1175,7 +1214,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, ...@@ -1175,7 +1214,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
struct uvc_streaming *stream = handle->stream; struct uvc_streaming *stream = handle->stream;
struct uvc_format *format = NULL; struct uvc_format *format = NULL;
struct uvc_frame *frame = 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 */ /* Look for the given pixel format and frame size */
for (i = 0; i < stream->nformats; i++) { for (i = 0; i < stream->nformats; i++) {
...@@ -1187,30 +1228,28 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, ...@@ -1187,30 +1228,28 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
if (format == NULL) if (format == NULL)
return -EINVAL; return -EINVAL;
index = fival->index;
for (i = 0; i < format->nframes; i++) { for (i = 0; i < format->nframes; i++) {
if (format->frame[i].wWidth == fival->width && if (format->frame[i].wWidth == fival->width &&
format->frame[i].wHeight == fival->height) { format->frame[i].wHeight == fival->height) {
frame = &format->frame[i]; frame = &format->frame[i];
break; nintervals = frame->bFrameIntervalType ?: 1;
if (index < nintervals)
break;
index -= nintervals;
} }
} }
if (frame == NULL) if (i == format->nframes)
return -EINVAL; return -EINVAL;
if (frame->bFrameIntervalType) { if (frame->bFrameIntervalType) {
if (fival->index >= frame->bFrameIntervalType)
return -EINVAL;
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fival->discrete.numerator = fival->discrete.numerator =
frame->dwFrameInterval[fival->index]; frame->dwFrameInterval[index];
fival->discrete.denominator = 10000000; fival->discrete.denominator = 10000000;
uvc_simplify_fraction(&fival->discrete.numerator, uvc_simplify_fraction(&fival->discrete.numerator,
&fival->discrete.denominator, 8, 333); &fival->discrete.denominator, 8, 333);
} else { } else {
if (fival->index)
return -EINVAL;
fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
fival->stepwise.min.numerator = frame->dwFrameInterval[0]; fival->stepwise.min.numerator = frame->dwFrameInterval[0];
fival->stepwise.min.denominator = 10000000; fival->stepwise.min.denominator = 10000000;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment