4. 枚举视频格式
任务目标
实现一个V4L2视频设备驱动中的格式枚举功能,当用户空间程序调用VIDIOC_ENUM_FMT ioctl时,驱动能够返回所支持的像素格式列表(YUYV、RGB24等),并正确填充索引(index)、描述符(description)和像素格式标识(pixelformat)。
核心实现
在V4L2驱动中,格式枚举通过vidioc_enum_fmt回调实现。该回调接收用户传入的struct v4l2_fmtdesc指针,其中index字段由用户设置,用于指定要查询的格式序号。驱动需要根据该索引返回对应的格式信息,若索引超出范围则返回-EINVAL。
#include <linux/videodev2.h>
#include <media/v4l2-ioctl.h>
/* 驱动支持的像素格式表 */
static const struct v4l2_format_info {
u32 pixelformat;
const char *description;
} supported_formats[] = {
{ V4L2_PIX_FMT_YUYV, "YUYV 4:2:2" },
{ V4L2_PIX_FMT_RGB24, "24-bit RGB 8-8-8" },
{ V4L2_PIX_FMT_MJPEG, "Motion-JPEG" },
};
#define NUM_FORMATS ARRAY_SIZE(supported_formats)
static int vidioc_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
if (f->index >= NUM_FORMATS)
return -EINVAL;
/* 清除保留位,确保返回结构干净 */
memset(f->reserved, 0, sizeof(f->reserved));
/* 设置格式类型(视频捕获) */
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* 填充像素格式和描述 */
f->pixelformat = supported_formats[f->index].pixelformat;
strscpy(f->description, supported_formats[f->index].description,
sizeof(f->description));
return 0;
}
/* 在v4l2_ioctl_ops中注册 */
static const struct v4l2_ioctl_ops my_ioctl_ops = {
.vidioc_enum_fmt = vidioc_enum_fmt,
/* ... 其他回调 ... */
};
关键说明
- 索引语义:V4L2规范要求驱动按
index从0开始连续返回格式,直到返回-EINVAL为止。用户程序通常循环调用此ioctl来枚举所有格式。 - 描述符长度:
description字段最大32字节(含结尾NUL),使用strscpy确保不越界。 - 类型匹配:若驱动同时支持视频捕获和输出,需检查
f->type是否与当前设备节点匹配,不匹配时返回-EINVAL。本例为简化仅支持捕获。
用户空间验证
编译并运行以下测试程序,观察输出是否符合预期:
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
int main(void)
{
int fd = open("/dev/video0", O_RDWR);
if (fd < 0) { perror("open"); return 1; }
struct v4l2_fmtdesc fmt;
int index = 0;
while (1) {
memset(&fmt, 0, sizeof(fmt));
fmt.index = index;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) < 0)
break; /* EINVAL 表示枚举结束 */
printf("index=%d pixelformat=0x%08x desc=%s\n",
index, fmt.pixelformat, fmt.description);
index++;
}
close(fd);
return 0;
}
预期输出(与驱动中格式表严格一致):
index=0 pixelformat=0x56595559 desc=YUYV 4:2:2
index=1 pixelformat=0x47524742 desc=24-bit RGB 8-8-8
index=2 pixelformat=0x47504a4d desc=Motion-JPEG
通过判定标准
- 测试程序能依次打印出驱动中定义的全部3种格式,且
pixelformat值与V4L2定义一致(YUYV=0x56595559,RGB24=0x47524742,MJPEG=0x47504a4d)。 - 当
index超过2时,ioctl返回-1且errno为EINVAL,循环正常终止。 - 使用
v4l2-ctl --list-formats工具验证时,输出格式列表与上述一致。