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…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...

springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...