跳到主要内容V4L2 数据结构详解 | 极客日志CAI算法
V4L2 数据结构详解
详细解析了 V4L2(Video for Linux 2)框架中的核心数据结构、枚举类型及 ioctl 命令。涵盖了 struct v4l2_capability、v4l2_format、v4l2_buffer 等关键结构体的字段含义与应用场景,特别是针对 IPC 摄像头的开发注意事项。同时介绍了内存管理方式、像素格式枚举以及 VIDIOC_* 系列命令的方向说明,为视频采集设备的驱动开发与调试提供了基础参考。
微码行者5 浏览 一、前言
V4L2(Video for Linux 2)通过一组精心设计的 ioctl 命令 和 配套的数据结构/枚举类型,实现了对视频采集设备的统一抽象。
二、核心数据结构体
1. struct v4l2_capability
作用:查询设备基本信息和能力(只读)
{
__u8 driver[];
__u8 card[];
__u8 bus_info[];
__u32 version;
__u32 capabilities;
__u32 device_caps;
__u32 reserved[];
};
struct
v4l2_capability
16
32
32
3
capabilities:常用标志位包括:
V4L2_CAP_VIDEO_CAPTURE:支持视频采集(IPC 必需)
V4L2_CAP_STREAMING:支持流式 I/O(mmap/userptr)
V4L2_CAP_READWRITE:支持 read/write 接口(性能差,不推荐)
struct v4l2_capability cap;
ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf(stderr, "Not a capture device!\n");
}
2. struct v4l2_format
struct v4l2_format {
enum v4l2_buf_type type;
union {
struct v4l2_pix_format pix;
struct v4l2_pix_format_mplane pix_mp;
struct v4l2_window win;
struct v4l2_vbi_format vbi;
struct v4l2_sliced_vbi_format sliced;
__u8 raw_data[200];
};
};
子结构:struct v4l2_pix_format
struct v4l2_pix_format {
__u32 width;
__u32 height;
__u32 pixelformat;
__u32 field;
__u32 bytesperline;
__u32 sizeimage;
__u32 colorspace;
__u32 priv;
__u32 flags;
};
IPC 开发注意:
设置后务必检查返回值!驱动可能调整 width/height/sizeimage。bytesperline 若设为 0,驱动会自动对齐(通常按 16 字节对齐)。
3. struct v4l2_requestbuffers
struct v4l2_requestbuffers {
__u32 count;
enum v4l2_buf_type type;
enum v4l2_memory memory;
__u32 reserved[2];
};
count:通常设为 3~8。太少易丢帧,太多增加延迟。
memory:IPC 最常用 V4L2_MEMORY_MMAP(零拷贝)。
4. struct v4l2_buffer
struct v4l2_buffer {
__u32 index;
enum v4l2_buf_type type;
__u32 bytesused;
__u32 flags;
enum v4l2_field field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
enum v4l2_memory memory;
union {
__u32 offset;
unsigned long userptr;
struct v4l2_plane *planes;
__s32 fd;
} m;
__u32 length;
__u32 reserved2;
__u32 reserved;
};
index:标识是哪个缓冲区(对应 mmap 映射数组)
bytesused:实际帧大小(对 MJPEG/H.264 至关重要)
timestamp:用于计算帧率、同步
sequence:检测丢帧(应连续递增)
5. struct v4l2_control / struct v4l2_ext_controls
struct v4l2_control {
__u32 id;
__s32 value;
};
struct v4l2_ext_controls {
__u32 ctrl_class;
__u32 count;
__u32 error_idx;
__u32 reserved[2];
struct v4l2_ext_control *controls;
};
struct v4l2_ext_control {
__u32 id;
__u32 size;
__u32 reserved2[1];
union {
__s32 value;
__s64 value64;
char *string;
__u8 *p_u8;
__u16 *p_u16;
__u32 *p_u32;
void *ptr;
};
};
V4L2_CID_EXPOSURE_AUTO:自动曝光开关
V4L2_CID_EXPOSURE:手动曝光值
V4L2_CID_GAIN:模拟增益
V4L2_CID_WHITE_BALANCE_TEMPERATURE:色温(K)
6. struct v4l2_fmtdesc
struct v4l2_fmtdesc {
__u32 index;
enum v4l2_buf_type type;
__u32 flags;
__u8 description[32];
__u32 pixelformat;
__u32 reserved[4];
};
struct v4l2_fmtdesc fmtdesc = {0};
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
for (fmtdesc.index = 0; ; fmtdesc.index++) {
if (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) break;
printf("Format %d: %.4s (%s)\n", fmtdesc.index, (char*)&fmtdesc.pixelformat, fmtdesc.description);
}
7. struct v4l2_frmsizeenum / struct v4l2_frmivalenum
struct v4l2_frmsizeenum fsize = {0};
fsize.pixel_format = V4L2_PIX_FMT_YUYV;
for (fsize.index = 0; ; fsize.index++) {
if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsize) < 0) break;
if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
printf("Resolution: %dx%d\n", fsize.discrete.width, fsize.discrete.height);
}
}
struct v4l2_frmivalenum fival = {0};
fival.pixel_format = V4L2_PIX_FMT_YUYV;
fival.width = 640;
fival.height = 480;
for (fival.index = 0; ; fival.index++) {
if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) < 0) break;
if (fival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
printf("FPS: %d/%d = %.2f\n", fival.discrete.denominator, fival.discrete.numerator, (double)fival.discrete.denominator / fival.discrete.numerator);
}
}
8. struct v4l2_queryctrl
作用:查询 control 能力的 ioctl 命令
struct v4l2_queryctrl {
__u32 id;
__u32 type;
__u8 name[32];
__s32 minimum;
__s32 maximum;
__s32 step;
__s32 default_value;
__u32 flags;
__u32 reserved[2];
};
三、核心枚举类型
1. enum v4l2_buf_type
| 枚举值 | 说明 |
|---|
V4L2_BUF_TYPE_VIDEO_CAPTURE | 视频采集(IPC 主要用此) |
V4L2_BUF_TYPE_VIDEO_OUTPUT | 视频输出(如 HDMI 输出) |
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE | 多平面采集(如 NV12 分 Y/UV 平面) |
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE | 多平面输出 |
2. enum v4l2_memory
| 枚举值 | 说明 | IPC 适用性 |
|---|
V4L2_MEMORY_MMAP | 内核分配,用户 mmap 映射 | 最常用,零拷贝 |
V4L2_MEMORY_USERPTR | 用户分配内存,传指针给驱动 | 需物理连续内存(ARM 通常不可用) |
V4L2_MEMORY_DMABUF | 使用 dma-buf 共享缓冲区 | 适用于多进程/硬件加速(如 GPU/NPU) |
3. enum v4l2_field
| 枚举值 | 说明 |
|---|
V4L2_FIELD_NONE | 逐行扫描(IPC 绝大多数用此) |
V4L2_FIELD_INTERLACED | 隔行扫描(先顶场后底场) |
V4L2_FIELD_TOP / V4L2_FIELD_BOTTOM | 单一场 |
建议:IPC 摄像头基本都是逐行,设为 V4L2_FIELD_NONE。
4. enum v4l2_colorspace
| 枚举值 | 说明 |
|---|
V4L2_COLORSPACE_SRGB | sRGB(普通摄像头) |
V4L2_COLORSPACE_REC709 | HDTV(Rec.709) |
V4L2_COLORSPACE_JPEG | Full-range YUV(0-255) |
V4L2_COLORSPACE_SMPTE170M | SDTV(NTSC/PAL) |
注意:错误的色彩空间会导致颜色失真!通常摄像头默认为 V4L2_COLORSPACE_SRGB 或 V4L2_COLORSPACE_JPEG。
5. 像素格式枚举(__u32 pixelformat)
虽然不是 C 枚举,但以宏形式定义,本质是四字符编码(FourCC):
| 宏 | FourCC | 说明 |
|---|
V4L2_PIX_FMT_YUYV | 'YUYV' | YUV 4:2:2 packed(最通用) |
V4L2_PIX_FMT_UYVY | 'UYVY' | 同上,UV 顺序不同 |
V4L2_PIX_FMT_MJPEG | 'MJPG' | Motion JPEG(压缩流) |
V4L2_PIX_FMT_H264 | 'H264' | H.264 码流(需硬件编码器) |
V4L2_PIX_FMT_RGB24 | 'RGB3' | 24-bit RGB(低效,慎用) |
V4L2_PIX_FMT_GREY | 'GREY' | 8-bit 灰度图 |
V4L2_PIX_FMT_SRGGB8 | 'RGGB' | Bayer RAW 格式(R-G-G-B 排列) |
V4L2_PIX_FMT_NV12 | 'NV12' | YUV 4:2:0 planar(Y 平面 + UV interleaved) |
- UVC 摄像头常用
YUYV 或 MJPEG
- SoC ISP 输出常用
NV12(节省带宽)
- AI 推理常需
RGB 或 GRAY,需软件转换
6. 控制 ID 枚举(V4L2_CID_*)
| 控制 ID | 类型 | 说明 |
|---|
V4L2_CID_BRIGHTNESS | integer | 亮度 |
V4L2_CID_CONTRAST | integer | 对比度 |
V4L2_CID_SATURATION | integer | 饱和度 |
V4L2_CID_HUE | integer | 色调 |
V4L2_CID_AUTO_WHITE_BALANCE | boolean | 自动白平衡开关 |
V4L2_CID_WHITE_BALANCE_TEMPERATURE | integer | 色温(单位:K) |
V4L2_CID_EXPOSURE_AUTO | menu | 自动曝光模式 |
V4L2_CID_EXPOSURE | integer | 手动曝光时间(单位依赖驱动) |
V4L2_CID_GAIN | integer | 模拟增益 |
V4L2_CID_ZOOM_ABSOLUTE | integer | 数字变焦 |
struct v4l2_queryctrl qctrl = {.id = V4L2_CID_EXPOSURE};
ioctl(fd, VIDIOC_QUERYCTRL, &qctrl);
printf("Exposure: min=%d, max=%d, step=%d\n", qctrl.minimum, qctrl.maximum, qctrl.step);
四、核心 VIDIOC_* 命令详解
V4L2(Video for Linux 2)框架中用于 ioctl 系统调用的命令标识符(ioctl command codes)。
每个 VIDIOC_XXX 对应一个唯一的整数,用于告诉内核:'我要执行 XXX 操作'。
- 命名规则:
VIDIOC = Video I/O Control
- 用途:用户空间程序通过
ioctl(fd, VIDIOC_XXX, &arg) 与 V4L2 驱动通信。
- 本质:是一组预定义的宏(
#define),由内核提供。
- 位置:所有
VIDIOC_* 宏均定义在 Linux 内核头文件中:#include <linux/videodev2.h>
| 宏名称 | 全称 / 含义 | ioctl 方向 | 参数类型 | 主要作用 | 使用阶段 |
|---|
VIDIOC_QUERYCAP | QUERY CAPability | _IOR(只读) | struct v4l2_capability* | 查询设备基本信息和能力(是否支持 capture/streaming 等) | 初始化 |
VIDIOC_S_FMT | Set FMT (format) | _IOWR(读写) | struct v4l2_format* | 设置视频格式(分辨率、像素格式、场序等) | 初始化 |
VIDIOC_G_FMT | Get FMT | _IOR | struct v4l2_format* | 获取当前视频格式 | 调试/初始化 |
VIDIOC_TRY_FMT | TRY FMT | _IOWR | struct v4l2_format* | 测试格式是否支持(不实际设置) | 初始化前验证 |
VIDIOC_REQBUFS | REQuest BUFferS | _IOWR | struct v4l2_requestbuffers* | 请求内核分配缓冲区队列(mmap/userptr) | 缓冲区准备 |
VIDIOC_QUERYBUF | QUERY BUFfer | _IOWR | struct v4l2_buffer* | 查询缓冲区元数据(如 offset、length),用于 mmap | 缓冲区映射 |
VIDIOC_QBUF | Queue BUFfer | _IOW | struct v4l2_buffer* | 将空缓冲区入队,交给驱动填充 | 流启动后循环使用 |
VIDIOC_DQBUF | DeQueue BUFfer | _IOWR | struct v4l2_buffer* | 出队已填充的帧缓冲区 | 主采集循环 |
VIDIOC_STREAMON | STREAM ON | _IOW | enum v4l2_buf_type* | 启动视频流(开始 DMA 传输) | 流控制 |
VIDIOC_STREAMOFF | STREAM OFF | _IOW | enum v4l2_buf_type* | 停止视频流(停止 DMA) | 流控制 / 退出 |
VIDIOC_QUERYCTRL | QUERY CTRL (control) | _IOWR | struct v4l2_queryctrl* | 查询某个 control(如曝光、增益)的能力信息(范围、类型、是否禁用) | 控制参数配置 |
VIDIOC_G_CTRL | Get CTRL | _IOWR | struct v4l2_control* | 获取单个 control 的当前值 | 控制读取 |
VIDIOC_S_CTRL | Set CTRL | _IOWR | struct v4l2_control* | 设置单个 control 的值 | 控制写入 |
VIDIOC_G_EXT_CTRLS | Get EXTended CTRLS | _IOWR | struct v4l2_ext_controls* | 批量获取 controls 值(推荐) | 高级控制 |
VIDIOC_S_EXT_CTRLS | Set EXTended CTRLS | _IOWR | struct v4l2_ext_controls* | 批量设置 controls 值(推荐) | 高级控制 |
VIDIOC_ENUM_FMT | ENUMerate FMT | _IOWR | struct v4l2_fmtdesc* | 枚举设备支持的所有像素格式 | 调试 / 自适应 |
VIDIOC_ENUM_FRAMESIZES | ENUMerate FRAME SIZES | _IOWR | struct v4l2_frmsizeenum* | 枚举某格式支持的分辨率 | 调试 |
VIDIOC_ENUM_FRAMEINTERVALS | ENUMerate FRAME INTERVALS | _IOWR | struct v4l2_frmivalenum* | 枚举某分辨率下的帧率 | 调试 |
五、ioctl 方向说明
_IO(type, nr):无数据传递
_IOR(type, nr, data_type):从内核读取数据到用户空间(Read)
_IOW(type, nr, data_type):向内核写入数据(Write)
_IOWR(type, nr, data_type):先写入再读出(Write-Read),最常见
#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability)
#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format)
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online