Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+55 −16
Original line number Diff line number Diff line
@@ -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];
			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;