LINUX&UVC驱动枚举视频帧大小和帧率
2024-04-01
69
0
UVC视频分为视频格式、帧大小及帧率。不过一般帧率和帧大小(分辨率)合并在一起的。
视频格式通过VIDIOC_ENUM_FMT获取到,但该视频格式下可能支持多种帧率和帧大小(分辨率)。故在应用层通过VIDIOC_ENUM_FRAMESIZES控制码来枚举该视频格式下的帧分辨率及帧率。
帧分辨率在UVCC&LINUX驱动中为:
const struct v4l2_ioctl_ops uvc_ioctl_ops = {
.vidioc_enum_frameintervals = uvc_ioctl_enum_frameintervals,
.vidioc_enum_frameintervals = uvc_ioctl_enum_frameintervals,
}
通过淅代码可知,其首先通过指定的视频格式找到其对应的struct uvc_format,然后再在该视频格式枚举其下的帧分辨率。
static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
unsigned int index;
unsigned int i;
/* Look for the given pixel format */
for (i = 0; i < stream->nformats; i++) {
if (stream->format[i].fcc == fsize->pixel_format) {
format = &stream->format[i];
break;
}
}
if (format == NULL)
return -EINVAL;
/* Skip duplicate frame sizes */
for (i = 0, index = 0; i < format->nframes; i++) {
if (frame
&& 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;
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = frame->wWidth;
fsize->discrete.height = frame->wHeight;
return 0;
}
而帧率的相关函数为:
static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *fival)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
struct uvc_format *format = NULL;
struct uvc_frame *frame = NULL;
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++) {
if (stream->format[i].fcc == fival->pixel_format) {
format = &stream->format[i];
break;
}
}
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 (i == format->nframes)
return -EINVAL;
if (frame->bFrameIntervalType) {
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fival->discrete.numerator = frame->dwFrameInterval[index];
fival->discrete.denominator = 10000000;
uvc_simplify_fraction(&fival->discrete.numerator,&fival->discrete.denominator, 8, 333);
} else {
fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
fival->stepwise.min.numerator = frame->dwFrameInterval[0];
fival->stepwise.min.denominator = 10000000;
fival->stepwise.max.numerator = frame->dwFrameInterval[1];
fival->stepwise.max.denominator = 10000000;
fival->stepwise.step.numerator = frame->dwFrameInterval[2];
fival->stepwise.step.denominator = 10000000;
uvc_simplify_fraction(&fival->stepwise.min.numerator,&fival->stepwise.min.denominator, 8, 333);
uvc_simplify_fraction(&fival->stepwise.max.numerator,&fival->stepwise.max.denominator, 8, 333);
uvc_simplify_fraction(&fival->stepwise.step.numerator,&fival->stepwise.step.denominator, 8, 333);
}
return 0;
}