4. 设置视频格式
任务目标
本案例演示通过V4L2 ioctl调用VIDIOC_S_FMT,将摄像头采集格式设置为YUYV、分辨率640x480,并验证设置是否生效。核心是理解struct v4l2_format的填充方式与驱动返回值的校验逻辑。
环境与依赖
- Linux系统(含
/dev/video0设备节点) - 内核已启用V4L2驱动,设备支持YUYV格式
- 编译依赖:
linux/videodev2.h(内核头文件)、libc
关键完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
int main(void) {
const char *dev = "/dev/video0";
int fd = open(dev, O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
perror("VIDIOC_S_FMT");
close(fd);
return 1;
}
// 验证驱动实际采用的参数
if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) {
fprintf(stderr, "格式不支持: 驱动返回 0x%08x\n", fmt.fmt.pix.pixelformat);
close(fd);
return 1;
}
if (fmt.fmt.pix.width != 640 || fmt.fmt.pix.height != 480) {
fprintf(stderr, "分辨率被调整: %ux%u\n", fmt.fmt.pix.width, fmt.fmt.pix.height);
close(fd);
return 1;
}
printf("设置成功: YUYV 640x480, sizeimage=%u\n", fmt.fmt.pix.sizeimage);
close(fd);
return 0;
}
编译与运行
gcc -o set_fmt set_fmt.c
./set_fmt
验证方法与判定标准
- 成功标志:程序输出
设置成功: YUYV 640x480, sizeimage=614400(614400 = 640×480×2字节),退出码为0。 - 失败排查:若ioctl返回错误,检查设备节点权限(
sudo运行)或确认摄像头驱动是否支持YUYV格式(可用v4l2-ctl --list-formats查看)。 - 驱动调整验证:部分驱动会静默修改分辨率或格式,代码中已加入二次校验,若驱动返回不同值会打印错误并退出非0。
常见问题
- field字段:设置为
V4L2_FIELD_NONE表示逐行扫描,若设备要求隔行需改用V4L2_FIELD_INTERLACED。 - sizeimage含义:驱动填充的单帧图像字节数,YUYV为每像素2字节,可用于后续mmap缓冲区分配。