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…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...