V4L2开发应用流程的各类超实用VIDIOC命令及其结构体集锦_Mark_minGE的博客-CSDN博客
V4L2常用命令详解_Linuxxulin的博客-CSDN博客
一、摄像头设备的打开和关闭
1.打开设备
open()函数
函数原型: int fd=open(const char *pathname, int flags);
or int fd=open(const char *pathname, int flags, mode_t mode);
ps: 基本上用第一个函数原型
函数参数:
1. pathname:打开文件的路径名 ,如 “/dev/video0” ,也可以是预定义字符串的宏,或char*类型的字符串指针。
2. flags:用来控制打开文件的模式。
3. mode:用来设置创建文件的权限(rwx). 当flags使用 O_CREAT时才有效。
返回值:
1.调用失败: 返回-1,并修改errno
2. 调用成功: 返回一个int类型的文件描述符fd
应用于V4L2的实例,打开设备节点: /dev/video0,则int fd = open("/dev/video0", O_RDWR);。
2.关闭设备
头文件:#include <unistd.h>
原型: int close(int fd);
实例: close(fd);
二. 查询、设置、获取设备属性(QUERY,ENUM, SET, GET)
2.1 查询VIDIOC_QUERYCAP 硬件信息
函数原型:int ioctl(int fd, int request, struct v4l2_capability *argp);
ps: 此处request 即 VIDIOC_QUERYCAP,即控制命令
/*相关结构体:*/
struct v4l2_capability
{
__u8 driver[16]; // 驱动名字
__u8 card[32]; // 设备名字
__u8 bus_info[32]; // 设备在系统中的位置
__u32 version; // 驱动版本号
__u32 capabilities; // 设备支持的操作
__u32 reserved[4]; // 保留字段
};
其中capabilities在摄像头中设置值为 V4L2_CAP_VIDEO_CAPTURE
//例程:
int querycap_camera(int fd)
{
//获取驱动信息,VIDIOC_QUERCAP
struct v4l2_capability cap;
int ret = 0;
memset(&cap,0, sizeof(cap));
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if(ret < 0)
{
printf("VIDIOC_QUERYCAP failed(%d)\n", ret);
return -1;
}
else
{
/*输出 caoability 信息*/
printf("Capability Informations:\n");
printf(" driver: %s\n", cap.driver);
printf(" card: %s\n", cap.card);
printf(" bus_info: %s\n", cap.bus_info);
printf(" version: %08X\n", cap.version);
printf(" capabilities: %08X\n", cap.capabilities);
}
printf("--------------------\n"); //可作为分割线。
return ret;
}
2.2 查询支持的格式等信息 VIDIOC_ENUM_FMT (显示所有支持的格式)
//相关的结构体:
struct v4l2_fmtdesc
{
__u32 index; // 要查询的格式序号,应用程序设置
enum v4l2_buf_type type; // 帧类型,应用程序设置
__u32 flags; // 是否为压缩格式
__u8 description[32]; // 格式名称
__u32 pixelformat; // 格式
__u32 reserved[4]; // 保留,不使用设置为0
};
参数分析:
1. index :是用来确定格式的一个简单整型数。与其他V4L2所使用的索引一样,这个也是从0开始递增,至最大允许值为止。应用可以通过一直递增索引值知道返回-EINVAL的方式枚举所有支持的格式。
2. type:是描述数据流类型的字段。对于视频捕获设备(摄像头或调谐器)来说,就是V4L2_BUF_TYPE_VIDEO_CAPTURE。
3. flags: 只定义了一个值,即V4L2_FMT_FLAG_COMPRESSED,表示这是一个压缩的视频格式。
4. description: 是对这个格式的一种简短的字符串描述。
5. pixelformat: 应是描述视频表现方式的四字符码
ps: 其中第3、4、5项为就index所支持的某个图像格式,V4L2驱动会自动填写的结构体成员信息。
//fun: display all supported formats
void enum_camera_format(int fd)
{
struct v4l2_fmtdesc fmtdesc;
memset(&fmtdesc, 0, sizeof(fmtdesc));
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("Supported format:\n");
while(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1)
{
printf("\t%d.%s\n",fmtdesc.index+1, fmtdesc.description);
fmtdesc.index++;
}
}
2.3 设置视频捕获格式 VIDIOC_S_FMT
Fun:设置视频捕获格式
函数原型: int ioctl(int fd, int request, struct v4l2_format* argp);
//相关的结构体
struct v4l2_format
{
enum v4l2_buf_type type;
union
{
struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
__u8 raw_data[200]; /* user-defined */
} fmt;
};
PS: 此处type 用于视频捕获设备来说也就是V4L2_BUF_TYPE_VIDEO_CAPTURE,对应fmt共用体中的pix,即pix是重点。
//其中:
enum v4l2_buf_type
{
V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
...
V4L2_BUF_TYPE_PRIVATE = 0x80,
};struct v4l2_pix_format
{
__u32 width; // 宽,必须是16的倍数
__u32 height; // 高,必须是16的倍数
__u32 pixelformat; // 视频数据存储类型,例如是//YUV4:2:2
enum v4l2_field field;
__u32 bytesperline; // 一行图像占用的字节数
__u32 sizeimage;
enum v4l2_colorspace colorspace;
__u32 priv; /* private data, depends on pixelformat */
};
描述:
可用v4l2_format 结构体用来设置摄像头的视频制式、帧格式等,在设置这个参数时应先填好
v4l2_format 的各个域,如 type(传输流类型),fmt.pix.width(宽)fmt.pix.heigth(高),
fmt.pix.field(采样区域,如隔行采样),fmt.pix.pixelformat(采样类型,如 YUV4:2:2),
然后通过 VIDIO_S_FMT 操作命令设置视频捕捉格式。
//例程:
int set_camera_fmt_c(int fd, struct v4l2_format *fmt)
{
//设置视频格式,格式先在fmt结构体里设置好,再调用VIDIOC_S_FMT,
int ret = 0;
memset(fmt, 0, sizeof(*fmt));
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt->fmt.pix.width = 1920;
fmt->fmt.pix.height =1080; //获取1080P的视频帧
fmt->fmt.pix.pixelformat =V4L2_PIX_FMT_YUYV; //格式设置为YUV格式
fmt->fmt.pix.field = V4L2_FIELD_ALTERNATE;
ret = ioctl(fd, VIDIOC_S_FMT, fmt);
if(ret < 0)
{
printf("VIDIOC_S_FMT failed(%d)\n", ret);
return -1;
}
else
{
printf("VIDIOC_S_FMT succeed(%d)\n", ret);
}
return 0;
}