Linux V4L2框架介绍
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)
相关文章:
Linux V4L2框架介绍
linux V4L2框架介绍 V4L2框架介绍 V4L2,全称Video for Linux 2,是Linux操作系统下用于视频数据采集设备的驱动框。它提供了一种标准化的方式使用户空间程序能够与视频设备进行通信和交互。通过V4L2接口,用户可以方便地实现视频图像数据的采…...
【前端】JavaScript 中 arguments、类数组与数组的深入解析
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 💯前言💯什么是 arguments 对象2.1 arguments 的定义2.2 arguments 的特性2.3 使用场景 💯深入了解 arguments 的结构3.1 arguments 的内部结构arguments 的关键属性…...
Android 布局菜单或按钮图标或Menu/Item设置可见和不可见
设置可见和不可见 即 设置 显示和隐藏;是双向设置;什么情况显示,什么情况隐藏分判断的条件 它不同于删除和屏蔽,删除和屏蔽,覆盖是单向的,不可逆转的。它间接等于单向的隐藏!!&…...
|| 与 ??的区别
?? : 空值合并运算符, 用于在左侧操作数为 null 或 undefined 时返回右侧操作数 let name null // null 或者 undefinedlet defaultName defaultNamelet displayName name ?? defaultNameconsole.log(displayName) // defaultName || : 逻辑或,…...
wordpress获取文章总数、分类总数、tag总数等
在制作wordpress模板的时候会要调用网站的文章总数分类总数tag总数等这个数值,如果直接用count查询数据库那就太过分了。好在wordpress内置了一些标签可以直接获取到这些数值,本文整理了一些常用的wordpress网站总数标签。 文章总数 <?php $count_…...
pytest 通过实例讲清单元测试、集成测试、测试覆盖率
1. 单元测试 概念 定义: 单元测试是对代码中最小功能单元的测试,通常是函数或类的方法。目标: 验证单个功能是否按照预期工作,而不依赖其他模块或外部资源。特点: 快速、独立,通常是开发者最先编写的测试。 示例:pytest 实现单…...
C#里怎么样自己实现10进制转换为二进制?
C#里怎么样自己实现10进制转换为二进制? 很多情况下,我们都是采用C#里类库来格式化输出二进制数。 如果有人要你自己手写一个10进制数转换为二进制数,并格式化输出, 就可以采用本文里的方法。 这里采用求模和除法来实现的。 下…...
Kafka-Consumer理论知识
一、上下文 之前的博客我们分析了Kafka的设计思想、Kafka的Producer端、Kafka的Server端的分析,为了完整性,我们接下来分析下Kafka的Consumer。《Kafka-代码示例》中有对应的Consumer示例代码,我们以它为入口进行分析 二、KafkaConsumer是什…...
Js-对象-04-Array
重点关注:Array String JSON BOM DOM Array Array对象时用来定义数组的。常用语法格式有如下2种: 方式1: var 变量名 new Array(元素列表); 例如: var arr new Array(1,2,3,4); //1,2,3,4 是存储在数组中的数据࿰…...
React 第八节组件生命周期钩子-类式组件,函数式组件模拟生命周期用法
概述 React组件的生命周期可以分为三个主要阶段: 挂载阶段(Mounting):组件被创建,插入到DOM 树的过程; 更新阶段(Updating):是组件中 props 以及state 发生变化时&#…...
Dubbo源码解析-服务调用(七)
一、服务调用流程 服务在订阅过程中,把notify 过来的urls 都转成了invoker,不知道大家是否还记得前面的rpc 过程,protocol也是在服务端和消费端各连接子一个invoker,如下图: 这张图主要展示rpc 主流程,消费…...
svn 崩溃、 cleanup失败 怎么办
在使用svn的过程中,可能出现整个svn崩溃, 例如cleanup 失败的情况,类似于 这时可以下载本贴资源文件并解压。 或者直接访问网站 SQLite Download Page 进行下载 解压后得到 sqlite3.exe 放到发生问题的svn根目录的.svn路径下 右键呼出pow…...
【Linux系列】NTP时间同步服务器搭建完整指南
在分布式系统和高可用环境中,时间同步是至关重要的。特别是对于银行、金融等关键业务系统,精准的时间同步不仅关系到系统的稳定性,还直接影响交易处理、日志管理、日终结算等功能。本文将介绍NTP(Network Time Protocol࿰…...
go 结构体方法
在 Go 语言中,结构体方法是指附加到结构体类型上的函数。这些方法可以通过结构体的实例来调用。方法的接收者(receiver)指定了该方法属于哪个结构体类型。接收者可以是一个值类型或指针类型。 定义结构体方法 下面是如何为一个结构体定义方…...
DHCP服务(包含配置过程)
目录 一、 DHCP的定义 二、 使用DHCP的好处 三、 DHCP的分配方式 四、 DHCP的租约过程 1. 客户机请求IP 2. 服务器响应 3. 客户机选择IP 4. 服务器确定租约 5. 重新登录 6. 更新租约 五、 DHCP服务配置过程 一、 DHCP的定义 DHCP(Dynamic Host Configur…...
uniapp内嵌的webview H5与应用通信
H5端: 1、找到index.html引入依赖 <script type"text/javascript" src"https://unpkg.com/dcloudio/uni-webview-js0.0.3/index.js"></script> 2、在需要通讯处发送消息 uni.postMessage({data:{code:200,msg:"处理完成&q…...
Android OpenGL ES详解——绘制圆角矩形
1、绘制矩形 代码如下: renderer类: package com.example.roundrectimport android.content.Context import android.opengl.GLES30 import android.opengl.GLSurfaceView.Renderer import com.opengllib.data.VertexArray import com.opengllib.prog…...
网络基础二
文章目录 协议定制,序列化和反序列化应用层网络版计算器协议的定制序列反序列化序列化未复用版 反序列化 TCP是面向字节流的,你怎么保证,你读取上来的数据,是‘’一个“ “完整””的报文呢? 我们没有区分字符串里面有…...
从Full-Text Search全文检索到RAG检索增强
从Full-Text Search全文检索到RAG检索增强 时光飞逝,转眼间六年过去了,六年前铁蛋优化单表千万级数据查询性能的场景依然历历在目,铁蛋也从最开始做CRUD转行去了大数据平台开发,混迹包装开源的业务,机缘巧合下做了实时…...
springMVC 全局异常统一处理
全局异常处理⽅式⼀: 1、配置简单异常处理器 配置 SimpleMappingExceptionResolver 对象: <!-- 配置全局异常统⼀处理的 Bean (简单异常处理器) --> <bean class"org.springframework.web.servlet.handler.SimpleMappingExceptionReso…...
Docker 部署 XiuXianGame 文字修仙游戏:极空间 NAS 上随时挂机刷资源
前言 挂机刷资源,躺平修成仙。 这类文字修仙游戏,说白了就是佛系养成为主,不用时刻盯着,挂着就行。但问题是——大多数要么得在本地电脑跑,要么依赖第三方平台,体验受限。把这套东西跑在自己的 NAS 上&am…...
ClawSuite:模块化网络安全工具集在渗透测试中的实战应用
1. 项目概述:ClawSuite,一个被低估的网络安全工具集如果你在网络安全领域摸爬滚打了一段时间,尤其是在渗透测试或者红队评估的圈子里,你大概率听说过或者用过像 Metasploit、Nmap、Burp Suite 这些耳熟能详的“瑞士军刀”。但今天…...
Sunshine游戏串流服务器:打造你的个人云端游戏平台
Sunshine游戏串流服务器:打造你的个人云端游戏平台 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 想要在任何设备上畅玩PC游戏?Sunshine游戏串流服务器是你…...
浏览器运行Cursor AI编辑器:Docker+KasmVNC部署全攻略
1. 项目概述:在浏览器中运行 Cursor AI 编辑器如果你是一名开发者,大概率听说过或者正在使用 Cursor——这款集成了强大 AI 辅助编程能力的编辑器。它基于 VS Code,但深度整合了类似 ChatGPT 的对话和代码生成功能,能极大提升编码…...
JPlag代码抄袭检测工具:如何高效识别17种编程语言的代码抄袭行为
JPlag代码抄袭检测工具:如何高效识别17种编程语言的代码抄袭行为 【免费下载链接】JPlag State-of-the-Art Source Code Plagiarism & Collusion Detection. Check for plagiarism in a set of programs. 项目地址: https://gitcode.com/gh_mirrors/jp/JPlag …...
一图定胜负|虎贲等考 AI 科研绘图:零代码画出期刊级学术图,让论文颜值与专业度双在线
据 Nature 统计,超 90% 的审稿人先看图表,65% 的初审意见直接来自图表质量,一张规范、清晰、专业的学术图,直接影响论文录用与答辩评分。可现实是:Origin、Visio 难学难精通,PPT 做图粗糙不规范,…...
终极指南:5分钟搭建SillyTavern AI聊天前端,解锁个性化角色对话体验
终极指南:5分钟搭建SillyTavern AI聊天前端,解锁个性化角色对话体验 【免费下载链接】SillyTavern LLM Frontend for Power Users. 项目地址: https://gitcode.com/GitHub_Trending/si/SillyTavern 想要创建专属的AI聊天伙伴,体验深度…...
半导体行业数据分析:从WSTS报告解读市场趋势与从业者应对策略
1. 从一份行业快报说起:如何解读半导体市场的“水温”早上刚冲好咖啡,习惯性地扫了一眼行业新闻,看到EE Times上这篇关于2013年第一季度全球半导体销售额的简报。标题很直接:“Chip sales up 1% through Q1”。1%的增长࿰…...
如何解决QQ音乐下载的歌曲在其他设备上无法播放的问题
如何解决QQ音乐下载的歌曲在其他设备上无法播放的问题 【免费下载链接】qmcflac2mp3 直接将qmcflac文件转换成mp3文件,突破QQ音乐的格式限制 项目地址: https://gitcode.com/gh_mirrors/qm/qmcflac2mp3 你是否曾经在QQ音乐下载了喜欢的歌曲,却发现…...
终极抢票指南:如何用DamaiHelper轻松获取演唱会门票
终极抢票指南:如何用DamaiHelper轻松获取演唱会门票 【免费下载链接】damaihelper 支持大麦网,淘票票、缤玩岛等多个平台,演唱会演出抢票脚本 项目地址: https://gitcode.com/gh_mirrors/dam/damaihelper 你是否曾为抢不到心仪演唱会门…...
