当前位置: 首页 > news >正文

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&#xff0c;全称Video for Linux 2&#xff0c;是Linux操作系统下用于视频数据采集设备的驱动框。它提供了一种标准化的方式使用户空间程序能够与视频设备进行通信和交互。通过V4L2接口&#xff0c;用户可以方便地实现视频图像数据的采…...

【前端】JavaScript 中 arguments、类数组与数组的深入解析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;什么是 arguments 对象2.1 arguments 的定义2.2 arguments 的特性2.3 使用场景 &#x1f4af;深入了解 arguments 的结构3.1 arguments 的内部结构arguments 的关键属性…...

Android 布局菜单或按钮图标或Menu/Item设置可见和不可见

设置可见和不可见 即 设置 显示和隐藏&#xff1b;是双向设置&#xff1b;什么情况显示&#xff0c;什么情况隐藏分判断的条件 它不同于删除和屏蔽&#xff0c;删除和屏蔽&#xff0c;覆盖是单向的&#xff0c;不可逆转的。它间接等于单向的隐藏&#xff01;&#xff01;&…...

|| 与 ??的区别

?? : 空值合并运算符&#xff0c; 用于在左侧操作数为 null 或 undefined 时返回右侧操作数 let name null // null 或者 undefinedlet defaultName defaultNamelet displayName name ?? defaultNameconsole.log(displayName) // defaultName || : 逻辑或&#xff0c;…...

wordpress获取文章总数、分类总数、tag总数等

在制作wordpress模板的时候会要调用网站的文章总数分类总数tag总数等这个数值&#xff0c;如果直接用count查询数据库那就太过分了。好在wordpress内置了一些标签可以直接获取到这些数值&#xff0c;本文整理了一些常用的wordpress网站总数标签。 文章总数 <?php $count_…...

pytest 通过实例讲清单元测试、集成测试、测试覆盖率

1. 单元测试 概念 定义: 单元测试是对代码中最小功能单元的测试&#xff0c;通常是函数或类的方法。目标: 验证单个功能是否按照预期工作&#xff0c;而不依赖其他模块或外部资源。特点: 快速、独立&#xff0c;通常是开发者最先编写的测试。 示例&#xff1a;pytest 实现单…...

C#里怎么样自己实现10进制转换为二进制?

C#里怎么样自己实现10进制转换为二进制&#xff1f; 很多情况下&#xff0c;我们都是采用C#里类库来格式化输出二进制数。 如果有人要你自己手写一个10进制数转换为二进制数&#xff0c;并格式化输出&#xff0c; 就可以采用本文里的方法。 这里采用求模和除法来实现的。 下…...

Kafka-Consumer理论知识

一、上下文 之前的博客我们分析了Kafka的设计思想、Kafka的Producer端、Kafka的Server端的分析&#xff0c;为了完整性&#xff0c;我们接下来分析下Kafka的Consumer。《Kafka-代码示例》中有对应的Consumer示例代码&#xff0c;我们以它为入口进行分析 二、KafkaConsumer是什…...

Js-对象-04-Array

重点关注&#xff1a;Array String JSON BOM DOM Array Array对象时用来定义数组的。常用语法格式有如下2种&#xff1a; 方式1&#xff1a; var 变量名 new Array(元素列表); 例如&#xff1a; var arr new Array(1,2,3,4); //1,2,3,4 是存储在数组中的数据&#xff0…...

React 第八节组件生命周期钩子-类式组件,函数式组件模拟生命周期用法

概述 React组件的生命周期可以分为三个主要阶段&#xff1a; 挂载阶段&#xff08;Mounting&#xff09;&#xff1a;组件被创建&#xff0c;插入到DOM 树的过程&#xff1b; 更新阶段&#xff08;Updating&#xff09;&#xff1a;是组件中 props 以及state 发生变化时&#…...

Dubbo源码解析-服务调用(七)

一、服务调用流程 服务在订阅过程中&#xff0c;把notify 过来的urls 都转成了invoker&#xff0c;不知道大家是否还记得前面的rpc 过程&#xff0c;protocol也是在服务端和消费端各连接子一个invoker&#xff0c;如下图&#xff1a; 这张图主要展示rpc 主流程&#xff0c;消费…...

svn 崩溃、 cleanup失败 怎么办

在使用svn的过程中&#xff0c;可能出现整个svn崩溃&#xff0c; 例如cleanup 失败的情况&#xff0c;类似于 这时可以下载本贴资源文件并解压。 或者直接访问网站 SQLite Download Page 进行下载 解压后得到 sqlite3.exe 放到发生问题的svn根目录的.svn路径下 右键呼出pow…...

【Linux系列】NTP时间同步服务器搭建完整指南

在分布式系统和高可用环境中&#xff0c;时间同步是至关重要的。特别是对于银行、金融等关键业务系统&#xff0c;精准的时间同步不仅关系到系统的稳定性&#xff0c;还直接影响交易处理、日志管理、日终结算等功能。本文将介绍NTP&#xff08;Network Time Protocol&#xff0…...

go 结构体方法

在 Go 语言中&#xff0c;结构体方法是指附加到结构体类型上的函数。这些方法可以通过结构体的实例来调用。方法的接收者&#xff08;receiver&#xff09;指定了该方法属于哪个结构体类型。接收者可以是一个值类型或指针类型。 定义结构体方法 下面是如何为一个结构体定义方…...

DHCP服务(包含配置过程)

目录 一、 DHCP的定义 二、 使用DHCP的好处 三、 DHCP的分配方式 四、 DHCP的租约过程 1. 客户机请求IP 2. 服务器响应 3. 客户机选择IP 4. 服务器确定租约 5. 重新登录 6. 更新租约 五、 DHCP服务配置过程 一、 DHCP的定义 DHCP&#xff08;Dynamic Host Configur…...

uniapp内嵌的webview H5与应用通信

H5端&#xff1a; 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、绘制矩形 代码如下&#xff1a; renderer类&#xff1a; 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…...

网络基础二

文章目录 协议定制&#xff0c;序列化和反序列化应用层网络版计算器协议的定制序列反序列化序列化未复用版 反序列化 TCP是面向字节流的&#xff0c;你怎么保证&#xff0c;你读取上来的数据&#xff0c;是‘’一个“ “完整””的报文呢&#xff1f; 我们没有区分字符串里面有…...

从Full-Text Search全文检索到RAG检索增强

从Full-Text Search全文检索到RAG检索增强 时光飞逝&#xff0c;转眼间六年过去了&#xff0c;六年前铁蛋优化单表千万级数据查询性能的场景依然历历在目&#xff0c;铁蛋也从最开始做CRUD转行去了大数据平台开发&#xff0c;混迹包装开源的业务&#xff0c;机缘巧合下做了实时…...

springMVC 全局异常统一处理

全局异常处理⽅式⼀: 1、配置简单异常处理器 配置 SimpleMappingExceptionResolver 对象: <!-- 配置全局异常统⼀处理的 Bean &#xff08;简单异常处理器&#xff09; --> <bean class"org.springframework.web.servlet.handler.SimpleMappingExceptionReso…...

qt ubuntu i386 系统

sudo ln -s cmake-3.31.0-linux-x86_64/bin/* /usr/local/bin 【Ubuntu20.4安装QT6 - CSDN App】Ubuntu20.4安装QT6_ubuntu安装qt6-CSDN博客 sudo ../configure -release -platform linux-g-64 -static -nomake examples -nomake demos -no-qt3support -no-script -no-scriptt…...

BUUCTF—Reverse—helloword(6)

一道安卓逆向的签到题 下载附件 使用JADX-gui反编译工具打开&#xff08;注意配环境&#xff09;&#xff0c;找到主函数 jadx 本身就是一个开源项目&#xff0c;源代码已经在 Github 上开源了 官方地址&#xff1a;GitHub - skylot/jadx: Dex to Java decompiler 发现flag …...

深入解析下oracle date底层存储方式

之前我们介绍了varchar2和char的数据库底层存储格式&#xff0c;今天我们介绍下date类型的数据存储格式&#xff0c;并通过测试程序快速获取一个日期。 一、环境搭建 1.1&#xff0c;创建表 我们还是创建一个测试表t_code&#xff0c;并插入数据&#xff1a; 1.2&#xff0c;…...

Elasticsearch 开放推理 API 增加了对 IBM watsonx.ai Slate 嵌入模型的支持

作者&#xff1a;来自 Elastic Saikat Sarkar 使用 Elasticsearch 向量数据库构建搜索 AI 体验时如何使用 IBM watsonx™ Slate 文本嵌入。 Elastic 很高兴地宣布&#xff0c;通过集成 IBM watsonx™ Slate 嵌入模型&#xff0c;我们的开放推理 API 功能得以扩展&#xff0c;这…...

如何搭建一个小程序:从零开始的详细指南

在当今数字化时代&#xff0c;小程序以其轻便、无需下载安装即可使用的特点&#xff0c;成为了连接用户与服务的重要桥梁。无论是零售、餐饮、教育还是娱乐行业&#xff0c;小程序都展现了巨大的潜力。如果你正考虑搭建一个小程序&#xff0c;本文将为你提供一个从零开始的详细…...

NFS搭建

NFS搭建 单节点安装配置服务器安装配置启动并使NFS服务开机自启客户端挂载查看是否能发现服务器的共享文件夹创建挂载目录临时挂载自动挂载 双节点安装配置服务器安装配置服务端配置NFS服务端配置Keepalived编辑nfs_check.sh监控脚本安装部署RsyncInofity 客户端 单节点安装配置…...

RNN与LSTM,通过Tensorflow在手写体识别上实战

简介&#xff1a;本文从RNN与LSTM的原理讲起&#xff0c;在手写体识别上进行代码实战。同时列举了优化思路与优化结果&#xff0c;都是基于Tensorflow1.14.0的环境下&#xff0c;希望能给您的神经网络学习带来一定的帮助。如果您觉得我讲的还行&#xff0c;希望可以得到您的点赞…...

Docker部署FastAPI实战

在现代 Web 开发领域&#xff0c;FastAPI 作为一款高性能的 Python 框架&#xff0c;正逐渐崭露头角&#xff0c;它凭借简洁的语法、快速的执行速度以及出色的类型提示功能&#xff0c;深受开发者的喜爱。而 Docker 容器化技术则为 FastAPI 应用的部署提供了便捷、高效且可移植…...

【Python数据分析五十个小案例】电影评分分析:使用Pandas分析电影评分数据,探索评分的分布、热门电影、用户偏好

博客主页&#xff1a;小馒头学python 本文专栏: Python数据分析五十个小案例 专栏简介&#xff1a;分享五十个Python数据分析小案例 在现代电影行业中&#xff0c;数据分析已经成为提升用户体验和电影推荐的关键工具。通过分析电影评分数据&#xff0c;我们可以揭示出用户的…...

Vue2学习记录

前言 这篇笔记&#xff0c;是根据B站尚硅谷的Vue2网课学习整理的&#xff0c;用来学习的 如果有错误&#xff0c;还请大佬指正 Vue核心 Vue简介 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。 它基于标准 HTML、CSS 和 JavaScr…...

网站闭站保护/seo关键词排名网络公司

1. 马哈鱼数据血缘分析工具简介 马哈鱼数据血缘分析工具&#xff08;英文名称为 Gudu SQLFlow &#xff09;是一款用于分析 SQL 语句&#xff0c;并发现其中数据血缘关系的分析软件&#xff0c;经常和元数据管理工具一起使用&#xff0c;是企业数据治理的基础工具。 如果你对 …...

怎么样做游戏网站/搜索图片

💥 项目专栏:【机器学习项目实战案例目录】项目详解 + 完整源码 文章目录 一、支持向量机(SVC)实现乳腺癌肿瘤预测二、数据集介绍三、导包四、加载数据集五、数据处理5.1 数值型特征5.2 离散型特征六、配置流水线七、获取训练数据、测试集八、定义模型九、模型训练十、训练…...

做网站源代码/成都seo论坛

通过kmeans分析出租车数据并进行可视化&#xff08;1&#xff09;数据准备&#xff08;2&#xff09;创建dataframe&#xff08;3&#xff09;kmeans聚类分析&#xff08;4&#xff09;调用百度API进行数据可视化&#xff08;1&#xff09;数据准备 采用数据为出租车载客时的G…...

杭州建德网站建设/万物识别扫一扫

在前几次的Server2008实验里面&#xff0c;我们向服务器FS01、FS02分别添加了一个磁盘分区E盘。但是没有介绍我们是如何通过VMWare Workstation来实现的。今天就让我们来一起利用VMWare Workstation来向虚拟主机添加一块新的硬盘并启用。利用虚拟机做实验&#xff0c;添加硬件&…...

wordpress禁用修订/免费友情链接交换平台

云计算职业转型之一&#xff1a;企业架构师 企业架构师在技术和各平台上是一个颇为具有代表性的角色&#xff0c;但那些准备转移至云的企业寻找的是有那些特定技术的员工。 请看下面的职业图表。有两条非常好的途径可供选择&#xff1a;公共云解决方案架构师和安全架构师。大…...

有什么免费ppt模板网站/sem投放

// 智能指针会自动释放所指向的对象。 // shared_ptr的应用场景是&#xff1a;程序需要在多个对象间共享数据/* 先从应用场景入手吧&#xff0c;说矿工A发现了一个金矿。* 然后矿工A喊来了矿工B&#xff0c;一起开采&#xff0c;不久后矿工A劳累过度死了。* 矿工B继续开采着矿工…...