/*
* V4L2 三级枚举示例:像素格式 -> 分辨率 -> 帧率 (FPS)
*
* 演示三个 ioctl 的嵌套枚举:
* VIDIOC_ENUM_FMT 枚举像素格式
* VIDIOC_ENUM_FRAMESIZES 枚举每种格式的分辨率
* VIDIOC_ENUM_FRAMEINTERVALS 枚举每个分辨率的帧间隔(帧率)
*
* 帧率 = denominator / numerator(例如 1/30 就是 30fps)
*/
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char *dev = "/dev/video0";
/*
* enum_frameintervals - 枚举指定格式+分辨率下的帧间隔(帧率)
* @fd: 设备描述符
* @fourcc: 像素格式 FourCC
* @w: 宽度
* @h: 高度
*
* 使用 VIDIOC_ENUM_FRAMEINTERVALS ioctl。
* v4l2_frmivalenum.type 也有三种类型,用法与帧尺寸枚举类似:
*
* V4L2_FRMIVAL_TYPE_DISCRETE
* 离散帧率列表,需递增 index 多次调用。每次返回一个分数 (numerator/denominator),
* 帧率 = denominator / numerator (单位 fps)。
* 例如 numerator=1, denominator=30 表示 30fps。
*
* V4L2_FRMIVAL_TYPE_STEPWISE
* 步进范围,一次调用获得 min~max/step 的帧率范围。
*
* V4L2_FRMIVAL_TYPE_CONTINUOUS
* 连续范围,一次调用获得 min~max 的帧率范围,区间内任意帧率都支持。
*/
static void enum_frameintervals(int fd, unsigned int fourcc, int w, int h)
{
struct v4l2_frmivalenum frmi;
for (int index = 0; ; index++) {
memset(&frmi, 0, sizeof(frmi));
frmi.index = index;
frmi.pixel_format = fourcc;
frmi.width = w;
frmi.height = h;
if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmi) < 0)
break;
switch (frmi.type) {
case V4L2_FRMIVAL_TYPE_DISCRETE:
/* 离散帧率:转换分数为浮点 fps */
printf(" [%d] %.2f fps\n", index,
(float)frmi.discrete.denominator / frmi.discrete.numerator);
break;
case V4L2_FRMIVAL_TYPE_STEPWISE:
/* 步进帧率:min ~ max fps,步进 step fps */
printf(" [%d] %.2f ~ %.2f fps step %.3f\n", index,
(float)frmi.stepwise.min.denominator / frmi.stepwise.min.numerator,
(float)frmi.stepwise.max.denominator / frmi.stepwise.max.numerator,
(float)frmi.stepwise.step.denominator / frmi.stepwise.step.numerator);
return;
case V4L2_FRMIVAL_TYPE_CONTINUOUS:
/* 连续帧率:min ~ max fps */
printf(" [%d] %.2f ~ %.2f fps (continuous)\n", index,
(float)frmi.stepwise.min.denominator / frmi.stepwise.min.numerator,
(float)frmi.stepwise.max.denominator / frmi.stepwise.max.numerator);
return;
}
}
}
/*
* enum_framesizes - 枚举像素格式下的分辨率及对应帧率
* @fd: 设备描述符
* @fourcc: 像素格式 FourCC
*/
static void enum_framesizes(int fd, unsigned int fourcc)
{
struct v4l2_frmsizeenum frmsize;
/* 先获知帧尺寸类型(DISCRETE/STEPWISE/CONTINUOUS) */
memset(&frmsize, 0, sizeof(frmsize));
frmsize.pixel_format = fourcc;
frmsize.index = 0;
if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) < 0)
return;
switch (frmsize.type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
/* 离散分辨率:递增 index 枚举每一项 */
for (int index = 0; ; index++) {
memset(&frmsize, 0, sizeof(frmsize));
frmsize.pixel_format = fourcc;
frmsize.index = index;
if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) < 0)
break;
printf(" [%d] %dx%d\n", index,
frmsize.discrete.width, frmsize.discrete.height);
/* 进一步枚举该分辨率的帧率 */
enum_frameintervals(fd, fourcc,
frmsize.discrete.width,
frmsize.discrete.height);
}
break;
case V4L2_FRMSIZE_TYPE_STEPWISE:
printf(" stepwise: %dx%d ~ %dx%d step %dx%d\n",
frmsize.stepwise.min_width, frmsize.stepwise.min_height,
frmsize.stepwise.max_width, frmsize.stepwise.max_height,
frmsize.stepwise.step_width, frmsize.stepwise.step_height);
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
printf(" continuous: %dx%d ~ %dx%d\n",
frmsize.stepwise.min_width, frmsize.stepwise.min_height,
frmsize.stepwise.max_width, frmsize.stepwise.max_height);
break;
}
}
/*
* enum_all - 三级枚举:格式 -> 分辨率 -> 帧率
*/
static void enum_all(int fd)
{
struct v4l2_fmtdesc fmt;
printf("====== 枚举像素格式/分辨率/帧率 ======\n");
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
for (fmt.index = 0; ; fmt.index++) {
if (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) < 0)
break;
printf(" [%d] 0x%08x %s\n",
fmt.index, fmt.pixelformat, fmt.description);
enum_framesizes(fd, fmt.pixelformat);
}
printf("\n");
}
int main(void)
{
int fd = open(dev, O_RDWR);
if (fd < 0) {
perror("open");
return -1;
}
enum_all(fd);
close(fd);
return 0;
}
root@wyl:~/c-std/for-linux/099_other/v4l2# ./002_v4l2_fmt_fps
====== 枚举像素格式/分辨率/帧率 ======
[0] 0x56595559 YUYV 4:2:2
[0] 96x200
[0] 25.00 fps
[1] 200x96
[0] 25.00 fps
[2] 8x8448
[0] 25.00 fps
[3] 8448x8
[0] 25.00 fps
[4] 4x2321
[0] 25.00 fps
[5] 96x100
[0] 25.00 fps
[6] 4x2637
[0] 25.00 fps
[7] 4x14733
[0] 25.00 fps
[8] 4x5188
[0] 25.00 fps
[9] 5188x4
[0] 25.00 fps
[10] 8x8642
[0] 25.00 fps
[11] 8642x8
[0] 25.00 fps
[12] 96x96
[0] 25.00 fps
[13] 240x240
[0] 25.00 fps