linux V4L2框架介绍
V4L2框架介绍
V4L2,全称Video for Linux 2,是Linux操作系统下用于视频数据采集设备的驱动框。它提供了一种标准化的方式使用户空间程序能够与视频设备进行通信和交互。通过V4L2接口,用户可以方便地实现视频图像数据的采集、输出、覆盖和编解码等功能,同时,V4L2的架构也为开发者提供了灵活和可扩展的编程接口。
V4L2驱动框架如下
V4L2主要提供以下接口功能:
- 视频采集功能接口(video capture interface):从摄像头等设备上获取视频数据。
- 视频输出功能接口(video output interface):将视频数据编码为模拟信号输出。
- 直接传输视频功能接口(video overlay interface):将视频采集设备采集的信号直接输出到输出设备,而无需经过系统CPU。
- 视频间隔消隐信号功能接口:提供对VBI(Vertical Blanking Interval)数据的控制,可以发送或抓取VBI数据。
- 收音机接收功能接口:用于处理从AM或FM高频头设备接收的音频流。
- 视频数据格式转换、缩放、色域转换等图像处理接口
V4L2设备,在驱动加载成功后在/dev目录下生成videox设备,用户可以该设备进行open或者close,read/write,同时其主要功能是通过ioctl来实现的。其支持的ioctl的命令能力主要有:
ioctrl codes | 说明 |
---|---|
VIDIOC_QUERYCAP | 查询设备功能 |
VIDIOC_G_PRIORITY | 获取设备操作的优先级 |
VIDIOC_S_PRIORITY | 设置设备操作的优先级 |
VIDIOC_LOG_STATUS | 向内核日志打印当前设备的详细状态信息,包括设备的基本信息、输入输出源、视频格式、分辨率、帧率,设备的状态信息以及设备的错误警告信息等 |
VIDIOC_ENUM_FMT | 枚举设备支持的图像格式 |
VIDIOC_G_FMT | 获取设备当前的图像格式 |
VIDIOC_S_FMT | 设置设备的图像格式 |
VIDIOC_TRY_FMT | 测试设备是否支持此格式 |
VIDIOC_ENUM_FRAMESIZES | 枚举设备支持的所有视频分辨率 |
VIDIOC_ENUM_FRAMEINTERVALS | 枚举设备支持的所有视频帧率 |
VIDIOC_G_PARM | 获取设备的流类型相关参数 |
VIDIOC_S_PARM | 设置设备的流类型相关参数 |
VIDIOC_STREAMON | 开始视频流式采集 |
VIDIOC_STREAMOFF | 停止视频流式采集 |
VIDIOC_REQBUFS | 申请缓存 |
VIDIOC_QUERYBUF | 获取缓存信息 |
VIDIOC_QBUF | 将缓存放入队列中 |
VIDIOC_DQBUF | 将缓存从队列中取出 |
VIDIOC_EXPBUF | 导出视频缓冲区 |
VIDIOC_G_FBUF | 查询当前视频帧缓冲区(framebuffer)的配置信息 |
VIDIOC_S_FBUF | 设置当前视频帧缓冲区(framebuffer)的配置信息 |
VIDIOC_OVERLAY | 启动或停止视频覆盖功能 |
VIDIOC_CROPCAP | 获取图像剪裁缩放能力 |
VIDIOC_G_CROP | 获取当前的剪裁矩阵 |
VIDIOC_S_CROP | 设置剪裁矩阵 |
VIDIOC_G_ENC_INDEX | 获取编码器索引 |
VIDIOC_ENCODER_CMD | 设置设备的当前编码器行为 |
VIDIOC_TRY_ENCODER_CMD | 测试设备是否支持此编码器命令 |
VIDIOC_G_INPUT | 获取当前的视频输入设备 |
VIDIOC_S_INPUT | 设置视频输入设备 |
VIDIOC_ENUMINPUT | 枚举视频输入设备 |
VIDIOC_G_OUTPUT | 获取当前的视频输出设备 |
VIDIOC_S_OUTPUT | 设备当前的视频输出设备 |
VIDIOC_ENUMOUTPUT | 枚举视频输出设备 |
VIDIOC_G_STD | 获取当前正在使用的标准 |
VIDIOC_S_STD | 设置视频标准 |
VIDIOC_ENUMSTD | 枚举设备支持的所有标准 |
VIDIOC_QUERYSTD | 自动侦测输入源的视频标准 |
VIDIOC_QUERYCTRL | 查询视频设备支持的控制项control |
VIDIOC_QUERYMENU | 查询与特定控制项相关联的菜单项 |
VIDIOC_G_CTRL | 获取设备指定的control的当前信息 |
VIDIOC_S_CTRL | 设置设备指定的control |
VIDIOC_G_TUNER | 获取设备调谐器信息 |
VIDIOC_S_TUNER | 设置设备调谐器信息 |
VIDIOC_ENUMAUDIO | 枚举音频输入设备 |
VIDIOC_G_AUDIO | 获取音频输入设备 |
VIDIOC_S_AUDIO | 设置音频输入设备 |
VIDIOC_ENUMAUDOUT | 枚举音频输出设备 |
VIDIOC_G_AUDOUT | 获取音频输出设备 |
VIDIOC_S_AUDOUT | 设备音频输出设备 |
VIDIOC_G_EDID | 获取与视频接收器或发射器设备的输入或输出相关联的EDID(Extended Display Identification Data,扩展显示标识数据) |
VIDIOC_S_EDID | 设置与视频接收器或发射器设备的输入或输出相关联的EDID(Extended Display Identification Data,扩展显示标识数据) |
VIDIOC_G_MODULATOR | 获取调制器(Modulator)的状态和配置信息 |
VIDIOC_S_MODULATOR | 设置调制器(Modulator)的状态和配置信息 |
VIDIOC_G_FREQUENCY | 获取当前调谐器或射频调制器(Modulator)的频率值 |
VIDIOC_S_FREQUENCY | 设置当前调谐器或射频调制器(Modulator)的频率值 |
VIDIOC_G_JPEGCOMP | 获取JPEG的压缩信息 |
VIDIOC_S_JPEGCOMP | 设置JPEG的压缩参数 |
VIDIOC_G_SLICED_VBI_CAP | 查询设备支持哪些类型的VBI数据的切片捕获 |
VIDIOC_G_EXT_CTRLS | 获取扩展的控制信息 |
VIDIOC_S_EXT_CTRLS | 设置扩展的控制参数 |
VIDIOC_TRY_EXT_CTRLS | 测试设备是否支持此扩展功能 |
V4L2工具——V4L2-Ctl介绍
V4L2-Ctl是基于V4L2 API的一个命令行工具,主要用于控制和查询Linux系统中的视频设备信息。能够列出系统中的视频设备、查询和设置视频设备参数,以及对视频进行捕获等功能。它提供了丰富的命令选项,使用户能够灵活地操控视频设备。其主要命令选项有:
v4l2-ctl --help / -h
显示帮助信息
v4l2-ctl --help-xxx
显示子选项的帮助信息 如v4l2-ctl --help-streaming 显示视频流式传输控制参数信息
v4l2-ctl -D / --info
显示摄像头基本信息
v4l2-ctl --list-devices
列出系统中的所有video设备
v4l2-ctl --log-status
打印v4l2内核态的详细日志
v4l2-ctl --list-ctrls --device /dev/video0
列出指定设备控制值
v4l2-ctl --list-ctls-menus --device /dev/video0
列出Linux系统中V4L2视频捕获设备支持的控制项(controls)和菜单(menus)
v4l2-ctl --get-priority
获取V4L2的操作优先级
v4l2-ctl --help-vidcap
显示视频捕获设备参数帮助信息
v4l2-ctl --list-formats-ext --device /dev/video0
列出指定设备的支持的图像格式、分辨率以及帧率
v4l2-ctl --list-formats --device /dev/video0
列出指定设备的支持图像格式
v4l2-ctl --device /dev/video0 --list-framesizes YUYV
列出当前设备所指定的图像格式下的分辨率
v4l2-ctl --device /dev/video0 --list-frameintervals width=1280,height=720,pixelformat=YUYV
列出设备在指定的图像格式以及分辨率下所支持的帧率
v4l2-ctl --device /dev/video0 --list-fields
列出指定设备所支持的场顺序
v4l2-ctl --get-fmt-video --device /dev/video0
获取指定设备当前所使用的格式
v4l2-ctl --all --device /dev/video0
获取指定设备的所有信息
v4l2-ctl --set-fmt-video=width=1280,height=720,pixelformat=YUYV --stream-mmap -d /dev/video0
流式输出指定视频设备以及指定格式和分辨率下的数据
v4l2-ctl -d /dev/video0 --stream-mmap
流式输出指定设备的数据
v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=100
流式输出指定设备的指定帧数的数据
v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=1 --stream-to=video0.yuv
将指定设备的图像数据流式输出到文件
v4l2-ctl --device /dev/video0 --stream-mmap --stream-lossless --stream-to-host 127.0.0.1
./qvidcap -p
流式输出指定设备的数据,并通过网络发送除去,可通过v4l2-utils/utils/qvidcap工具进行查看
V4L2 video catpture device api介绍
打开设备
Linux的open函数打开video设备
//方法用例C++函数
bool V4L2CaptureVideoData::OpenVideoDevice(std::string device_name)
{m_video_fd = open(device_name.c_str(), O_RDWR | O_NONBLOCK, 0);if (-1 == m_video_fd) {std::cerr<<"cannot open video device:"<<"device name="<<device_name<<",errno="<<errno<<",strerror="<<strerror(errno)<<std::endl;return false;}return true;
}
关闭设备
linux的close函数关闭video设备
//方法用例C++函数
bool V4L2CaptureVideoData::closeVideoDevice()
{if(close(m_video_fd)==-1){std::cerr<<"close video device failed:"<<"errno="<<errno<<",strerror="<<strerror(errno)<<std::endl;m_video_fd=-1;return false;}m_video_fd=-1;return true;
}
ioctl命令 VIDIOC_QUERYCAP
查询设备功能
//命令字段定义
#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability)
//所使用到的结构体信息
struct v4l2_capability {__u8 driver[16]; // 驱动程序名称__u8 card[32]; // 设备名称__u8 bus_info[32]; // 总线信息__u32 version; // V4L2 版本号__u32 capabilities; // 设备的能力标志__u32 device_caps; // 设备特定能力标志__u32 reserved[3]; // 保留字段
};
//方法用例C++函数
bool V4L2CaptureVideoData::GetVideoDeviceCapability(v4l2_capability &cap)
{int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_QUERYCAP, &cap);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_QUERYCAP failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
ioctl命令 VIDIOC_ENUM_FMT
枚举视频设备支持的图像格式
//命令字段定义
#define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc)
//所使用到的结构体信息
struct v4l2_fmtdesc {__u32 index; // 格式编号,从0开始递增__u32 type; // 帧类型,如V4L2_BUF_TYPE_VIDEO_CAPTURE表示视频捕捉__u32 flags; // 格式标志,如V4L2_FMT_FLAG_COMPRESSED表示压缩格式__u8 description[32]; // 格式描述字符串,如"YUV 4:2:2 (YUYV)"__u32 pixelformat; // 格式的四字符代码(Four-Character Code, FCC),如V4L2_PIX_FMT_UYVY__u32 reserved[4]; // 保留字段,用于未来扩展
};
//方法用例C++函数
bool V4L2CaptureVideoData::EnumVideoDeviceFormat(std::list<struct v4l2_fmtdesc> &fmtdesc)
{fmtdesc.clear();struct v4l2_fmtdesc tmp_fmtdesc;tmp_fmtdesc.index = 0;tmp_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;int ret=0;while(!((ret == -1) && (errno != EINTR) && (errno != EAGAIN))){ret=ioctl(m_video_fd,VIDIOC_ENUM_FMT,&tmp_fmtdesc);if(ret==0){fmtdesc.push_back(tmp_fmtdesc);tmp_fmtdesc.index++;} }return true;
}
ioctl命令 VIDIOC_G_FMT
获取设备当前使用的图像格式
//命令字段定义
#define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format)
//所使用到的结构体信息
struct v4l2_format {enum v4l2_buf_type type; // 帧类型,指示这个格式是用于捕获、输出还是其他类型union {struct v4l2_pix_format pix; // 像素格式信息,用于视频捕获等struct v4l2_window win; // 窗口信息,用于视频输出覆盖struct v4l2_vbi_format vbi; // VBI(Vertical Blanking Interval)格式信息struct v4l2_sliced_vbi_format sliced; // 切片VBI格式信息__u8 raw_data[200]; // 原始数据,用于用户自定义格式} fmt;
};struct v4l2_pix_format {__u32 width; // 视频帧的宽度(像素)__u32 height; // 视频帧的高度(像素)__u32 pixelformat; // 像素格式,使用四字符代码(Four-Character Code, FCC)表示__u32 field; // 字段顺序,如V4L2_FIELD_INTERLACED表示隔行扫描__u32 bytesperline; // 每行的字节数(对于压缩格式,可能表示压缩块的大小)__u32 sizeimage; // 整个图像的大小(字节)__u32 colorspace; // 颜色空间,如V4L2_COLORSPACE_SMPTE170M表示SMPTE 170M标准__u32 priv; // 私有数据,供驱动使用__u32 flags; // 格式标志,如V4L2_PIX_FMT_FLAG_PREMUL_ALPHA表示alpha通道已预乘union {/* enum v4l2_ycbcr_encoding */__u32 ycbcr_enc;/* enum v4l2_hsv_encoding */__u32 hsv_enc;};__u32 quantization; /* enum v4l2_quantization 量化方式*/__u32 xfer_func; /* enum v4l2_xfer_func 传输函数 */
};
//方法用例C++函数
bool V4L2CaptureVideoData::GetVideoDeviceFormat(v4l2_format &fmt)
{fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_G_FMT, &fmt);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_G_FMT failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
ioctl命令 VIDIOC_S_FMT
设置设备当前使用的图像格式
//命令字段定义
#define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format)
//所使用到的结构体信息
struct v4l2_format {enum v4l2_buf_type type; // 帧类型,指示这个格式是用于捕获、输出还是其他类型union {struct v4l2_pix_format pix; // 像素格式信息,用于视频捕获等struct v4l2_window win; // 窗口信息,用于视频输出覆盖struct v4l2_vbi_format vbi; // VBI(Vertical Blanking Interval)格式信息struct v4l2_sliced_vbi_format sliced; // 切片VBI格式信息__u8 raw_data[200]; // 原始数据,用于用户自定义格式} fmt;
};struct v4l2_pix_format {__u32 width; // 视频帧的宽度(像素)__u32 height; // 视频帧的高度(像素)__u32 pixelformat; // 像素格式,使用四字符代码(Four-Character Code, FCC)表示__u32 field; // 字段顺序,如V4L2_FIELD_INTERLACED表示隔行扫描__u32 bytesperline; // 每行的字节数(对于压缩格式,可能表示压缩块的大小)__u32 sizeimage; // 整个图像的大小(字节)__u32 colorspace; // 颜色空间,如V4L2_COLORSPACE_SMPTE170M表示SMPTE 170M标准__u32 priv; // 私有数据,供驱动使用__u32 flags; // 格式标志,如V4L2_PIX_FMT_FLAG_PREMUL_ALPHA表示alpha通道已预乘union {/* enum v4l2_ycbcr_encoding */__u32 ycbcr_enc;/* enum v4l2_hsv_encoding */__u32 hsv_enc;};__u32 quantization; /* enum v4l2_quantization 量化方式*/__u32 xfer_func; /* enum v4l2_xfer_func 传输函数 */
};
//方法用例C++函数
bool V4L2CaptureVideoData::SetVideoDeviceFormat(const v4l2_format &fmt)
{int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_S_FMT, &fmt);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_S_FMT failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
ioctl命令 VIDIOC_ENUM_FRAMESIZES
枚举视频设备指定的图像格式下所支持的所有图像分辨率
//命令字段定义
#define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum)
//所使用到的结构体信息
struct v4l2_frmsizeenum {__u32 index; // 索引,从 0 开始__u32 pixel_format; // 像素格式(例如 V4L2_PIX_FMT_YUYV)__u32 type; // 帧尺寸类型,可以是离散、连续或步进union {struct v4l2_frmsize_discrete {__u32 width; // 宽度__u32 height; // 高度} discrete; // 离散帧大小struct v4l2_frmsize_stepwise {__u32 min_width; // 最小宽度__u32 min_height; // 最小高度__u32 max_width; // 最大宽度__u32 max_height; // 最大高度__u32 step_width; // 步长宽度__u32 step_height; // 步长高度} stepwise; // 逐步帧大小} frm_size; // 帧大小信息__u32 reserved[2]; // 保留字段
};
//方法用例C++函数
bool V4L2CaptureVideoData::EnumVideoDeviceFrameSize(const unsigned int pixel_format,std::list<struct v4l2_frmsizeenum> &frmsize)
{frmsize.clear();struct v4l2_frmsizeenum tmp_frmsize;tmp_frmsize.index=0;tmp_frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;tmp_frmsize.pixel_format = pixel_format;int ret=0;while(!((ret == -1) && (errno != EINTR) && (errno != EAGAIN))){ret=ioctl(m_video_fd,VIDIOC_ENUM_FRAMESIZES,&tmp_frmsize);if(ret==0){frmsize.push_back(tmp_frmsize);tmp_frmsize.index++;} }return true;
}
ioctl命令 VI4DIOC_ENUM_FRAMEINTERVALS
枚举设备在指定的图像格式以及分辨率下所支持的所有视频帧率
//命令字段定义
#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum)
//所使用到的结构体信息
struct v4l2_frmivalenum {__u32 index; // 枚举索引,用于遍历所有支持的帧率和帧间隔__u32 pixel_format; // 像素格式,使用四字符代码(FCC)表示__u32 width; // 帧宽度__u32 height; // 帧高度__u32 type; // 帧间隔类型,可以是离散、连续或步进union {struct v4l2_fract discrete; // 离散帧间隔(或帧率)struct v4l2_frmival_stepwise stepwise; // 步进帧间隔(或帧率)};__u32 reserved[2]; // 保留字段,供未来扩展使用
};struct v4l2_fract {__u32 numerator; // 分子__u32 denominator; // 分母
};struct v4l2_frmival_stepwise {struct v4l2_fract min; // 最小帧间隔(或帧率)struct v4l2_fract max; // 最大帧间隔(或帧率)struct v4l2_fract step; // 步长
};
//方法用例C++函数
bool V4L2CaptureVideoData::EnumVideoDeviceFrameIntervals(const unsigned int pixel_format,const unsigned int width,const unsigned int height,std::list<struct v4l2_frmivalenum> &frmivals)
{frmivals.clear();struct v4l2_frmivalenum tmp_frmival;tmp_frmival.index = 0;tmp_frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;tmp_frmival.pixel_format = pixel_format;tmp_frmival.width = width;tmp_frmival.height = height;int ret=0;while(!((ret == -1) && (errno != EINTR) && (errno != EAGAIN))){ret=ioctl(m_video_fd, VIDIOC_ENUM_FRAMEINTERVALS, &tmp_frmival);if(ret==0){frmivals.push_back(tmp_frmival);tmp_frmival.index++;}}return true;
}
ioctl命令 VIDIOC_STREAMON
开始视频流式采集
//命令字段定义
#define VIDIOC_STREAMON _IOW('V', 18, int)
//方法用例C++函数
bool V4L2CaptureVideoData::StartVideoStreamCapture()
{enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_STREAMON, &type);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_STREAMON failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
ioctl命令 VIDIOC_STREAMOFF
停止视频流式采集
//命令字段定义
#define VIDIOC_STREAMOFF _IOW('V', 19, int)
//方法用例C++函数
bool V4L2CaptureVideoData::StopVideoStreamCapture()
{enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_STREAMOFF, &type);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_STREAMOFF failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
ioctl命令 VIDIOC_REQBUFS
申请设备的视频数据缓存buffer
//命令字段定义
#define VIDIOC_REQBUFS _IOWR('V', 8, struct v4l2_requestbuffers)
//所使用到的结构体信息
struct v4l2_requestbuffers {__u32 count; // 请求的缓冲区数量__u32 type; // 缓冲区类型(例如 V4L2_BUF_TYPE_VIDEO_CAPTURE)__u32 memory; // 内存类型(例如 V4L2_MEMORY_MMAP)__u32 reserved[2]; // 保留字段
};
//方法用例C++函数
bool V4L2CaptureVideoData::RequestVideoBuffer(const unsigned int request_count,const unsigned int memeory_type,v4l2_requestbuffers &requestbuf)
{requestbuf.count=request_count;requestbuf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;requestbuf.memory=memeory_type;int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_REQBUFS, &requestbuf);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_REQBUFS failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
ioctl命令 VIDIOC_QUERYBUF
获取设备已经申请到的缓存buffer信息
//命令字段定义
#define VIDIOC_QUERYBUF _IOWR('V', 9, struct v4l2_buffer)
//所使用到的结构体信息
struct v4l2_buffer {__u32 index; // 缓冲区索引__u32 type; // 缓冲区类型(例如 V4L2_BUF_TYPE_VIDEO_CAPTURE)__u32 bytesused; // 使用的字节数__u32 flags; // 标志位__u32 field; // 场类型(例如 V4L2_FIELD_NONE)struct timeval timestamp; // 缓冲区的时间戳struct v4l2_timecode timecode; // 时间码(如果设备支持)__u32 sequence; // 缓冲区序列号(如果设备支持)/* memory location */__u32 memory; // 缓冲区的内存类型union {__u32 offset; //mmap的偏移量unsigned long userptr; // 用户空间指针struct v4l2_plane *planes; // 平面地址数组,用于多平面格式__s32 fd;} m;__u32 length; // 缓冲区长度(以字节为单位)__u32 reserved2;union {__s32 request_fd;__u32 reserved;};
};
//方法用例C++函数
bool V4L2CaptureVideoData::GetVideoBuffer(const unsigned int memory_type,unsigned int index,struct v4l2_buffer &video_buffer)
{video_buffer.index = index;video_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;video_buffer.memory = memory_type;int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_QUERYBUF, &video_buffer);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_QUERYBUF failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
ioctl命令 VIDIOC_QBUF
将设备已经申请好的缓存buffer放入到数据捕获队列中
//命令字段定义
#define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer)
//所使用到的结构体信息
struct v4l2_buffer {__u32 index; // 缓冲区索引__u32 type; // 缓冲区类型(例如 V4L2_BUF_TYPE_VIDEO_CAPTURE)__u32 bytesused; // 使用的字节数__u32 flags; // 标志位__u32 field; // 场类型(例如 V4L2_FIELD_NONE)struct timeval timestamp; // 缓冲区的时间戳struct v4l2_timecode timecode; // 时间码(如果设备支持)__u32 sequence; // 缓冲区序列号(如果设备支持)/* memory location */__u32 memory; // 缓冲区的内存类型union {__u32 offset; //mmap的偏移量unsigned long userptr; // 用户空间指针struct v4l2_plane *planes; // 平面地址数组,用于多平面格式__s32 fd;} m;__u32 length; // 缓冲区长度(以字节为单位)__u32 reserved2;union {__s32 request_fd;__u32 reserved;};
};
//方法用例C++函数
bool V4L2CaptureVideoData::PushVideoBuffer(const v4l2_buffer &video_buffer)
{int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_QBUF, &video_buffer);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_QBUF failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
ioctl命令 VIDIOC_DQBUF
将设备已经申请好的缓存buffer从视频数据捕获队列中取出
//命令字段定义
#define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer)
//所使用到的结构体信息
struct v4l2_buffer {__u32 index; // 缓冲区索引__u32 type; // 缓冲区类型(例如 V4L2_BUF_TYPE_VIDEO_CAPTURE)__u32 bytesused; // 使用的字节数__u32 flags; // 标志位__u32 field; // 场类型(例如 V4L2_FIELD_NONE)struct timeval timestamp; // 缓冲区的时间戳struct v4l2_timecode timecode; // 时间码(如果设备支持)__u32 sequence; // 缓冲区序列号(如果设备支持)/* memory location */__u32 memory; // 缓冲区的内存类型union {__u32 offset; //mmap的偏移量unsigned long userptr; // 用户空间指针struct v4l2_plane *planes; // 平面地址数组,用于多平面格式__s32 fd;} m;__u32 length; // 缓冲区长度(以字节为单位)__u32 reserved2;union {__s32 request_fd;__u32 reserved;};
};
//方法用例C++函数
bool V4L2CaptureVideoData::PopVideoBuffer(const unsigned int memory_type,struct v4l2_buffer &video_buffer)
{video_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;video_buffer.memory = memory_type;int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_DQBUF, &video_buffer);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_DQBUF failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}
V4L2四种模式下的视频设备数据采集
摄像头原始数据读取——V4L2(read模式,V4L2_CAP_READWRITE)
摄像头原始数据读取——V4L2(mmap模式,V4L2_MEMORY_MMAP)
摄像头原始数据读取——V4L2(userptr模式,V4L2_MEMORY_USERPTR)
摄像头原始数据读取——V4L2(dmabuf模式,V4L2_MEMORY_DMABUF)