Linux驱动,之camera的驱动v4L2(video for linux two)框架,应用篇(一)

一、前言
在前一篇,我会总结,记录工作过程中,调试过的各种接口(rgb,hdmi,cdi,mipi,usb)的摄像头,各种接口的时序图,接口总线。

本篇将下应用层v4L2(video for linux two),采集图像的框架,很早就像写了,以前多次研究过,很久不用,老是忘记。
其实v4L2和海思的音频芯片35xx,sdk音视频采集非常像,海思对他进行了封装,流程差不多。

应用层v4L2(video for linux two)其实非常简单,不像底层的v4L2驱动框架,那么复杂,应用层,就是api,设置摄像头设备
的参数(码率,分辨率,有的会设置编码格式,有的摄像头是不支持的,输出的是raw数据,帧率等等。),然后mmap映射
dma分配一块内存地址映射(这块和Lcd,codex,网络有点像,通过dma来搬运数据,而不是cpu),然后采集数据,送到lcd显示
或者送到编码模块,发送网络。

Video4Linux2(v4l2)是用于Linux系统的视频设备驱动框架,它允许用户空间应用程序直接与视频设备(如摄像头、视频采集卡等)进行交互。

linux系统下一切皆文件,对视频设备的操作就像对文件的操作一样,使用类似读取、写入文件的方式来进行,v4l2也都是通过open()ioctl()read()close(),字符设备那一套规则,来实现对视频设备的操作。

感谢原文博主热心分享,他写的非常好了。
原文链接:https://blog.csdn.net/weixin_43147845/article/details/136899272

一、v4L2采集摄像头流程

梳理大概得流程和设置

摄像头框架编程步骤
(1)打开摄像头设备(/dev/video0 、/dev/video1 )。
(2)设置图像格式:VIDIOC_S_FMT(视频捕获格式、图像颜色数据格式、图像宽和高)。
(3)申请缓冲区:VIDIOC_REQBUFS(缓冲区数量、缓冲映射方式、视频捕获格式)。
(4)将缓冲区映射到进程空间:VIDIOC_QUERYBUF(要映射的缓冲区下标、缓冲映射方式、视频捕获格式)。
(5)将缓冲区添加到队列中:VIDIOC_QBUF(映射的缓冲区下标、缓冲映射方式、视频捕获格式)。
(6)开启摄像头采集:VIDIOC_STREAMON (视频捕获格式)。
(7)从采集队列中取出图像数据VIDIOC_DQBUF,进行图像渲染。

在这里插入图片描述

1、打开设备:

首先,应用程序需要打开要使用的视频设备。通常,这可以通过调用open()系统调用来完成,传递设备文件的路径作为参数。例如,摄像头通常会以/dev/videoX的形式出现,其中X是数字。

O_NONBLOCK以非阻塞方式打开
fd = open("/dev/video0", O_RDWR | O_NONBLOCK, 0);

2、查询设备能力、设置视频格式:

一旦设备打开,应用程序通常会查询设备的能力,例如支持的视频格式、分辨率、帧率等信息。这可以通过调用ioctl()系统调用来执行VIDIOC_QUERYCAP操作来完成。根据设备的能力和应用程序的需求,可以设置所需的视频格式。这包括像素格式、分辨率、帧率等。通常,可以使用VIDIOC_S_FMT操作来设置视频格式。

int ioctl(int fd, unsigned long request, ...);

v4l2请求命令和请求参数在/usr/include/linux/videodev2.h里面定义
在这里插入图片描述
在这里插入图片描述

2.1、查询设备信息:

linux定义了如下一个结构体
/*
 * struct v4l2_capability {
 *    __u8    driver[16];     // 驱动模块的名称(例如 "bttv")
 *    __u8    card[32];       // 设备的名称(例如 "Hauppauge WinTV")
 *    __u8    bus_info[32];   // 总线的名称(例如 "PCI:" + pci_name(pci_dev))
 *    __u32   version;        // KERNEL_VERSION
 *    __u32   capabilities;   // 整个物理设备的功能
 *    __u32   device_caps;    // 通过此特定设备(节点)访问的功能
 *    __u32   reserved[3];    // 保留字段,用于未来扩展
 * };
 */
 
struct v4l2_capability cap;

if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
   
     //调用ioctl函数,VIDIOC_QUERYCAP查询信息,返回到cap的结构体里
  
    perror("VIDIOC_QUERYCAP");
    return -1;
}

2.2、 查询摄像头支持的格式:

/*
 * struct v4l2_fmtdesc {
 *         __u32               index;        // 格式编号,摄像头可能支持多种格式,查看的时候需要指定格式编号,循环遍历获取所有支持的格式 
 *         __u32               type;         // 枚举 v4l2_buf_type 
 *         __u32               flags;
 *         __u8                description[32];   // 描述字符串 
 *         __u32               pixelformat;       // 格式 FourCC,通常由四个ASCII字符组成,用于唯一地标识特定的数据格式或编码方式
 *         __u32               reserved[4];
 * };
 */
 
struct v4l2_fmtdesc fmtdesc;

fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1) {
   
   
   
    printf("\t%d.%s\n", fmtdesc.index + 1, fmtdesc.description);
    fmtdesc.index++;
}

2.3、 设置采集的视频格式:

struct v4l2_pix_format

struct v4l2_pix_format {
   
   
	__u32 width;				//图像宽度
	__u32 height;				//图像高度
	__u32 pixelformat;			//图像数据格式
	__u32 field; 				/*enum v4l2_field */
	__u32 bytesperline; 		/*for padding, zero if unused */
	__u32 sizeimage;
	__u32 colorspace; 			/*enum v4l2_colorspace*/
	__u32 priv; 				/*private data, depends on pixelformat */
};

struct v4l2_format

struct v4l2_format {
   
   
	__u32 type;									/* 类型V4L2_BUF_TYPE_VIDEO_CAPTURE*/
								
	union {
   
   
		struct v4l2_pix_format pix; 			/* V4L2_BUF_TYPE_VIDEO_CAPTURE视频捕获格式*/
		struct v4l2_pix_format_mplane pix_mp; 	/* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE /
		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;
};

struct v4l2_format中的, type是枚举类型,enum v4l2_buf_type用于表示数据流格式,
定义如下:fmt是枚举体,根据类型,选择设置对应的结构体。

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_VBI_CAPTURE          = 4,  // 垂直空白间隔(VBI)捕获类型,用于捕获VBI数据
        V4L2_BUF_TYPE_VBI_OUTPUT           = 5,  // VBI输出类型,用于输出VBI数据
        V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,  // 切片VBI捕获类型,用于捕获切片VBI数据
        V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,  // 切片VBI输出类型,用于输出切片VBI数据
        V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,  // 视频输出叠加类型,用于输出叠加图像或视频
        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,  // 多平面视频捕获类型,用于从多平面视频设备捕获图像数据(视频编解码)
        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10, // 多平面视频输出类型,用于将图像数据输出到多平面视频设备(视频编解码)
        V4L2_BUF_TYPE_SDR_CAPTURE          = 11, // SDR捕获类型,用于从SDR设备捕获数据
        V4L2_BUF_TYPE_SDR_OUTPUT           = 12, // SDR输出类型,用于将数据输出到SDR设备
        V4L2_BUF_TYPE_META_CAPTURE         = 13, // 元数据捕获类型,用于从设备捕获元数据
        /* 已废弃,请勿使用 */
        V4L2_BUF_TYPE_PRIVATE              = 0x80, // 私有类型,用于自定义和扩展目的
};

看下这个像素格式结构体

struct v4l2_pix_format {
   
   
        __u32                   width;          // 图像宽度
        __u32                   height;         // 图像高度
        __u32                   pixelformat;    // 像素格式,使用 FOURCC 表示
        __u32                   field;          // 视频场类型,枚举 v4l2_field
        __u32                   bytesperline;   // 每行字节数,用于填充,如果未使用则为零
        __u32                   sizeimage;      // 图像数据大小
        __u32                   colorspace;     // 颜色空间,枚举 v4l2_colorspace
        __u32                   priv;           // 私有数据,依赖于像素格式
        __u32                   flags;          // 格式标志(V4L2_PIX_FMT_FLAG_*)
        union {
   
   
                // YCbCr 编码
                __u32                   ycbcr_enc;
                // HSV 编码
                __u32                   hsv_enc;
        };
        __u32                   quantization;   // 量化方式,枚举 v4l2_quantization
        __u32                   xfer_func;      // 传输函数,枚举 v4l2_xfer_func
};

例如、填充结构体,设置采集参数

struct v4l2_format fmt;

CLEAN(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;

if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
   
   
    printf("VIDIOC_S_FMT IS ERROR! LINE:%d\n", __LINE__);
    //return -1;
}

如果设置类型type,选择的是,V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,。则使用struct v4l2_pix_format_mplane,一般用于v4l2视频编解码中,定义如下:

struct v4l2_pix_format_mplane {
   
   
        __u32                           width;          // 图像宽度
        __u32                           height;         // 图像高度
        __u32                           pixelformat;    // 图像像素格式 小端四字符代码(FourCC)
        __u32                           field;          // 图像字段顺序 enum v4l2_field; 字段顺序(用于隔行扫描视频)
        __u32                           colorspace;     // 图像色彩空间 enum v4l2_colorspace; 与 pixelformat 相关的补充信息
 
        struct v4l2_plane_pix_format    plane_fmt[VIDEO_MAX_PLANES
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值