4. 设置摄像头采集分辨率
任务目标
本案例实现通过V4L2 API设置摄像头采集分辨率,并验证设置是否生效。核心目标是:打开视频设备后,使用VIDIOC_S_FMT设置指定分辨率(如640x480),再通过VIDIOC_G_FMT读取实际生效格式,确认驱动接受该分辨率。
核心实现
#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(int argc, char *argv[]) {
const char *dev = "/dev/video0";
int width = 640, height = 480;
if (argc >= 2) dev = argv[1];
if (argc >= 4) { width = atoi(argv[2]); height = atoi(argv[3]); }
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 = width;
fmt.fmt.pix.height = height;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
perror("VIDIOC_S_FMT");
close(fd);
return 1;
}
// 读取驱动实际采用的格式
struct v4l2_format cur;
memset(&cur, 0, sizeof(cur));
cur.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_G_FMT, &cur) < 0) {
perror("VIDIOC_G_FMT");
close(fd);
return 1;
}
printf("请求: %dx%d\n", width, height);
printf("实际: %dx%d, 像素格式: %c%c%c%c\n",
cur.fmt.pix.width, cur.fmt.pix.height,
(cur.fmt.pix.pixelformat >> 0) & 0xff,
(cur.fmt.pix.pixelformat >> 8) & 0xff,
(cur.fmt.pix.pixelformat >> 16) & 0xff,
(cur.fmt.pix.pixelformat >> 24) & 0xff);
close(fd);
return 0;
}
编译与运行
# 编译
gcc -o set_resolution set_resolution.c
# 运行(默认 /dev/video0,640x480)
./set_resolution
# 指定设备和分辨率
./set_resolution /dev/video1 1280 720
验证方法
程序执行后观察输出:
- 通过条件:输出中“实际”分辨率与“请求”一致(例如均为640x480),且像素格式为YUYV,说明驱动接受了设置。
- 驱动调整情况:若实际分辨率与请求不同(如请求1280x720但实际为640x480),说明该设备/驱动不支持请求的分辨率,自动回退到最接近的可用值——这属于正常行为,并非程序错误。
- 错误排查:若
VIDIOC_S_FMT返回错误,常见原因是设备不支持YUYV格式或分辨率超出范围,可改用V4L2_PIX_FMT_MJPEG等格式测试。
关键说明
本程序仅完成格式协商,不涉及帧缓冲申请或数据采集。设置分辨率是采集流程的第一步,后续需通过VIDIOC_REQBUFS申请缓冲区并启动流,才能实际获取图像数据。像素格式V4L2_PIX_FMT_YUYV为大多数UVC摄像头默认支持,若设备不支持会返回错误,此时可查询驱动支持的格式列表(通过VIDIOC_ENUM_FMT)后替换。