摄像头原始数据读取——V4L2(mmap模式,V4L2_MEMORY_MMAP)
摄像头原始数据读取——V4L2(mmap模式,V4L2_MEMORY_MMAP)
内存映射模式,是将设备在内核态申请的用于存储视频数据的物理内存映射到用户空间,使得用户应用程序可以直接访问和操作设备数据物理内存,避免了数据的拷贝。因此采集速度较快,一般用于连续视频数据的采集。
流程:
- 通过VIDIOC_REQBUFS ioctl请求内核分配视频数据缓冲区。
- 通过VIDIOC_QUERYBUF ioctl获取内核已经分配好的视频数据缓冲区信息。
- 使用mmap函数将获取到的缓冲区映射到用户空间。
- 通过VIDIOC_QBUF ioctl将已经申请好的缓冲区放入数据缓存队列。
- 启动视频流后,使用poll或select函数等待设备缓冲区数据就绪。
- 通过VIDIOC_DQBUF ioctl从队列中取出已填充的数据缓冲区并进行处理。
- 处理完数据后,再次通过VIDIOC_QBUF ioctl将缓冲区放入输入队列,循环使用。
v4l2mmapmode.hpp
#ifndef _V4L2MMAPMODE_H_
#define _V4L2MMAPMODE_H_#include <iostream>
#include <list>
#include <vector>
#include <utility>
#include <functional>
#include <mutex>
#include <thread>
#include <linux/videodev2.h>//图像帧数据结构体
struct VideoBufferStruct
{std::string dev_name; //video设备名unsigned int pixel_format; //当前使用的图像格式int width; //图像宽度int height; //图像高度unsigned long timestamp; //图像从内核读上来后的时间戳size_t data_len; //图像数据长度void *data; //图像数据
};class V4L2CaptureVideoData
{
public:static bool m_keeprunning; //运行标志,用于Ctrl+C结束运行public:explicit V4L2CaptureVideoData();~V4L2CaptureVideoData();void RegisterVideoDataProcessCallback(std::function<void(const VideoBufferStruct&)> func);bool OpenVideoDevice(std::string device_name);bool closeVideoDevice();bool QueryVideoDeviceCapability(const unsigned int capability);void StartMmapData();/* VIDIOC_QUERYCAP 获取设备支持的操作*/bool GetVideoDeviceCapability(struct v4l2_capability &cap);/* VIDIOC_G_PRIORITY 获取设备操作的优先级*/bool GetVideoDevicePriority(unsigned int &priority);/* VIDIOC_S_PRIORITY 设置设备操作的优先级*/bool SetVideoDevicePriority(const unsigned int priority);/* VIDIOC_LOG_STATUS 获取关于视频设备当前状态的日志信息*/bool GetVideoDeviceLogStatus(void);/* VIDIOC_ENUM_FMT 列举设备所支持的视频格式*/bool EnumVideoDeviceFormat(std::list<struct v4l2_fmtdesc> &fmtdesc);/* VIDIOC_G_FMT 获取设备当前使用的视频像素格式*/bool GetVideoDeviceFormat(struct v4l2_format &fmt);/* VIDIOC_S_FMT 设置设备当前使用的视频像素格式*/bool SetVideoDeviceFormat(const struct v4l2_format &fmt);/* VIDIOC_TRY_FMT 尝试设置视频像素格式、用于判断设备是否支持该视频像素格式*/bool TrySetVideoDeviceFormat(const struct v4l2_format &fmt);/* VIDIOC_ENUM_FRAMESIZES 枚举设备支持的视频采集分辨率*/bool EnumVideoDeviceFrameSize(const unsigned int pixel_format, std::list<struct v4l2_frmsizeenum> &frmsize);/* VIDIOC_ENUM_FRAMEINTERVALS 枚举设备支持的视频采集帧率fps*/bool EnumVideoDeviceFrameIntervals(const unsigned int pixel_format, const unsigned int width, const unsigned int height, std::list<struct v4l2_frmivalenum> &frmivals);/*VIDIOC_STREAMON 启动视频采集*/bool StartVideoCapture(void);/*VIDIOC_STREAMOFF 停止视频采集*/bool StopVideoCapture(void);/*VIDIOC_REQBUFS 申请驱动分配视频帧缓冲区*/bool RequestVideoBuffer(const struct v4l2_requestbuffers &requestbuf);/*VIDIOC_QUERYBUF 查询视频缓冲区信息 struct v4l2_buffer*/bool GetVideoBuffer(const unsigned int memory_type, unsigned int index, v4l2_buffer &video_buffer);/*VIDIOC_QBUF 将申请的缓冲帧放入队列*/bool PushVideoBuffer(const struct v4l2_buffer &video_buffer);/*VIDIOC_DQBUF 采集的缓冲帧出队列*/bool PopVideoBuffer(const unsigned int memory_type, struct v4l2_buffer &video_buffer);private:unsigned long getEpochTimeShiftus();private:int m_video_fd;std::function<void(const VideoBufferStruct&)> m_video_data_callback;std::string m_video_device_name;
};#endif // _V4L2MMAPMODE_H_
v4l2mmapmode.cpp
#include "v4l2mmapmode.hpp"#include <iostream>
#include <thread>
#include <chrono>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>bool V4L2CaptureVideoData::m_keeprunning=true;V4L2CaptureVideoData::V4L2CaptureVideoData()
{m_video_fd=-1;m_video_data_callback=nullptr;m_video_device_name.clear();
}V4L2CaptureVideoData::~V4L2CaptureVideoData()
{if(m_video_fd!=-1){closeVideoDevice();}
}void V4L2CaptureVideoData::RegisterVideoDataProcessCallback(std::function<void(const VideoBufferStruct&)> func)
{m_video_data_callback=func;
}bool V4L2CaptureVideoData::OpenVideoDevice(std::string device_name)
{m_video_device_name=device_name;std::string device_head="/dev/video";if(m_video_device_name.compare(0, device_head.size(), device_head)!=0){std::cerr<<m_video_device_name<<" is not camera device"<<std::endl;return false;}m_video_fd = open(m_video_device_name.c_str(), O_RDWR /* required */ | O_NONBLOCK, 0);if (-1 == m_video_fd) {std::cerr<<"cannot open video device:"<<"device name="<<m_video_device_name<<",errno="<<errno<<",strerror="<<strerror(errno)<<std::endl;return false;}return true;
}bool V4L2CaptureVideoData::closeVideoDevice()
{if(m_video_fd<0){return true;}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;
}bool V4L2CaptureVideoData::QueryVideoDeviceCapability(const unsigned int capability)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}v4l2_capability video_cap;if(GetVideoDeviceCapability(video_cap)==false){return false;}if(!(video_cap.capabilities & capability)){std::cerr<<m_video_device_name<<" not support this capability="<<capability<<std::endl;return false;}return true;
}void V4L2CaptureVideoData::StartMmapData()
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return;}if(QueryVideoDeviceCapability(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING)==false){return;}struct v4l2_format video_format;GetVideoDeviceFormat(video_format);struct VideoBufferStruct data_buffer;data_buffer.dev_name=m_video_device_name;data_buffer.pixel_format=video_format.fmt.pix.pixelformat;data_buffer.width=video_format.fmt.pix.width;data_buffer.height=video_format.fmt.pix.height;const unsigned int video_req_buffer_cnts=4;struct v4l2_requestbuffers video_req_buffer;memset(&video_req_buffer,'\0',sizeof(video_req_buffer));video_req_buffer.count = video_req_buffer_cnts;video_req_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;video_req_buffer.memory = V4L2_MEMORY_MMAP;if(RequestVideoBuffer(video_req_buffer)==false){return;}void *mmap_addrs[video_req_buffer_cnts];unsigned int mmap_length[video_req_buffer_cnts];for(int index=0;index<video_req_buffer_cnts;index++){struct v4l2_buffer video_v4l2_buffer;memset(&video_v4l2_buffer,'\0',sizeof(video_v4l2_buffer));if(GetVideoBuffer(V4L2_MEMORY_MMAP,index,video_v4l2_buffer)==false){return;}mmap_addrs[index]=mmap(NULL,video_v4l2_buffer.length,PROT_READ | PROT_WRITE, MAP_SHARED,m_video_fd,video_v4l2_buffer.m.offset);if(mmap_addrs[index]==MAP_FAILED){std::cerr<<"mmap failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return;}mmap_length[index]=video_v4l2_buffer.length;}for(int index=0;index<video_req_buffer_cnts;index++){struct v4l2_buffer tmp_video_buffer;tmp_video_buffer.index=index;tmp_video_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;tmp_video_buffer.memory = V4L2_MEMORY_MMAP;if(PushVideoBuffer(tmp_video_buffer)==false){return;}}if(StartVideoCapture()==false){return;}fd_set fds;struct timeval tv;int ret;while(m_keeprunning==true){FD_ZERO (&fds);FD_SET (m_video_fd, &fds);tv.tv_sec = 3;tv.tv_usec = 0;ret = select (m_video_fd + 1, &fds, NULL, NULL, &tv);if (-1 == ret) {if (EINTR == errno){continue;}else{std::cerr<<"select failed:"<<"errno="<<errno<<",strerror="<<strerror(errno)<<std::endl;break;}}else if (0 == ret) {std::cerr<<"select timeout no data available."<<std::endl;break;}else{struct v4l2_buffer video_buffer_data;if(PopVideoBuffer(V4L2_MEMORY_MMAP,video_buffer_data)==false){break;}data_buffer.data=mmap_addrs[video_buffer_data.index];data_buffer.data_len=video_buffer_data.bytesused;data_buffer.timestamp=video_buffer_data.timestamp.tv_sec*1000000+video_buffer_data.timestamp.tv_usec+getEpochTimeShiftus();m_video_data_callback(data_buffer);if(PushVideoBuffer(video_buffer_data)==false){return;}std::this_thread::sleep_for(std::chrono::milliseconds(10));}}if(StopVideoCapture()==false){return;}for(int index=0;index<video_req_buffer_cnts;index++){if(ret==munmap(mmap_addrs[index], mmap_length[index])){std::cerr<<"munmap failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;}}closeVideoDevice();
}bool V4L2CaptureVideoData::GetVideoDeviceCapability(v4l2_capability &cap)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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;}std::cout<<"camera v4l2_capability {"<<std::endl<<" driver = "<<cap.driver<<std::endl<<" card = "<<cap.card<<std::endl<<" bus_info = "<<cap.bus_info<<std::endl<<" version = "<<cap.version<<std::endl<<" capabilities = "<<cap.capabilities<<std::endl<<" device_caps = "<<cap.device_caps<<std::endl<<"}"<<std::endl;return true;
}bool V4L2CaptureVideoData::GetVideoDevicePriority(unsigned int &priority)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_G_PRIORITY, &priority);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_G_PRIORITY failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}std::cout<<"video device get priority = "<<priority<<std::endl;return true;
}bool V4L2CaptureVideoData::SetVideoDevicePriority(const unsigned int priority)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}unsigned int bk_priority=priority;int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_S_PRIORITY, &bk_priority);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_S_PRIORITY failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}if(bk_priority!=priority){std::cerr<<"actual video device priority set "<<bk_priority<<" not input value "<<priority<<std::endl;return false;}std::cout<<"video device set priority = "<<priority<<std::endl;return true;
}bool V4L2CaptureVideoData::GetVideoDeviceLogStatus()
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_LOG_STATUS, NULL);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_LOG_STATUS failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}bool V4L2CaptureVideoData::EnumVideoDeviceFormat(std::list<struct v4l2_fmtdesc> &fmtdesc)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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);std::cout<<"camera v4l2_fmtdesc {"<<std::endl<<" index = "<<tmp_fmtdesc.index<<std::endl<<" type = "<<tmp_fmtdesc.type<<std::endl<<" flags = "<<tmp_fmtdesc.flags<<std::endl<<" description = "<<tmp_fmtdesc.description<<std::endl<<" pixelformat = "<<std::hex<<tmp_fmtdesc.pixelformat<<std::dec<<std::endl<<"}"<<std::endl;tmp_fmtdesc.index++;} }if(fmtdesc.size()==0){std::cerr<<"get video format cout is 0"<<std::endl;return false;}return true;
}bool V4L2CaptureVideoData::GetVideoDeviceFormat(v4l2_format &fmt)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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;}std::cout<<"camera v4l2_format {"<<std::endl<<" type = "<<fmt.type<<std::endl<<" v4l2_pix_format.width = "<<fmt.fmt.pix.width<<std::endl<<" v4l2_pix_format.height = "<<fmt.fmt.pix.height<<std::endl<<" v4l2_pix_format.pixelformat = "<<std::hex<<fmt.fmt.pix.pixelformat<<std::dec<<std::endl<<" v4l2_pix_format.field = "<<fmt.fmt.pix.field<<std::endl<<" v4l2_pix_format.bytesperline = "<<fmt.fmt.pix.bytesperline<<std::endl<<" v4l2_pix_format.sizeimage = "<<fmt.fmt.pix.sizeimage<<std::endl<<" v4l2_pix_format.colorspace = "<<fmt.fmt.pix.colorspace<<std::endl<<" v4l2_pix_format.priv = "<<fmt.fmt.pix.priv<<std::endl<<" v4l2_pix_format.flags = "<<fmt.fmt.pix.flags<<std::endl<<"}"<<std::endl;return true;
}bool V4L2CaptureVideoData::SetVideoDeviceFormat(const v4l2_format &fmt)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}v4l2_format tmp_fmt;memcpy(&tmp_fmt,&fmt,sizeof(tmp_fmt));int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_S_FMT, &tmp_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;}if((tmp_fmt.fmt.pix.width==fmt.fmt.pix.width) && (tmp_fmt.fmt.pix.height==fmt.fmt.pix.height) && (tmp_fmt.fmt.pix.pixelformat==fmt.fmt.pix.pixelformat)){std::cout<<"camera set v4l2_format {"<<std::endl<<" type = "<<fmt.type<<std::endl<<" v4l2_pix_format.width = "<<fmt.fmt.pix.width<<std::endl<<" v4l2_pix_format.height = "<<fmt.fmt.pix.height<<std::endl<<" v4l2_pix_format.pixelformat = "<<std::hex<<fmt.fmt.pix.pixelformat<<std::dec<<std::endl<<"}"<<std::endl;return true;}else{std::cerr<<"camera actual set v4l2_format {"<<std::endl<<" type = "<<tmp_fmt.type<<std::endl<<" v4l2_pix_format.width = "<<tmp_fmt.fmt.pix.width<<std::endl<<" v4l2_pix_format.height = "<<tmp_fmt.fmt.pix.height<<std::endl<<" v4l2_pix_format.pixelformat = "<<std::hex<<tmp_fmt.fmt.pix.pixelformat<<std::dec<<std::endl<<"}"<<std::endl;return false;}
}bool V4L2CaptureVideoData::TrySetVideoDeviceFormat(const v4l2_format &fmt)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}std::cout<<"camera try set v4l2_format {"<<std::endl<<" type = "<<fmt.type<<std::endl<<" v4l2_pix_format.width = "<<fmt.fmt.pix.width<<std::endl<<" v4l2_pix_format.height = "<<fmt.fmt.pix.height<<std::endl<<" v4l2_pix_format.pixelformat = "<<std::hex<<fmt.fmt.pix.pixelformat<<std::dec<<std::endl<<" v4l2_pix_format.field = "<<fmt.fmt.pix.field<<std::endl<<"}"<<std::endl;int ret=0;do{ret=ioctl(m_video_fd, VIDIOC_TRY_FMT, &fmt);} while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));if(ret!=0){std::cerr<<"ioctl VIDIOC_TRY_FMT failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}bool V4L2CaptureVideoData::EnumVideoDeviceFrameSize(const unsigned int pixel_format,std::list<struct v4l2_frmsizeenum> &frmsize)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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);std::cout<<"camera v4l2_frmsizeenum {"<<std::endl<<" index = "<<tmp_frmsize.index<<std::endl<<" type = "<<tmp_frmsize.type<<std::endl<<" pixel_format = "<<std::hex<<tmp_frmsize.pixel_format<<std::dec<<std::endl<<" v4l2_frmsize_discrete.width = "<<tmp_frmsize.discrete.width<<std::endl<<" v4l2_frmsize_discrete.height = "<<tmp_frmsize.discrete.height<<std::endl<<"}"<<std::endl;tmp_frmsize.index++;} }if(frmsize.size()==0){std::cerr<<"get video frame size cout is 0"<<std::endl;return false;}return true;
}bool V4L2CaptureVideoData::EnumVideoDeviceFrameIntervals(const unsigned int pixel_format,const unsigned int width,const unsigned int height,std::list<struct v4l2_frmivalenum> &frmivals)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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);std::cout<<"Frame interval<"<<tmp_frmival.discrete.denominator / tmp_frmival.discrete.numerator<<"fps>"<<std::endl;std::cout<<"camera v4l2_frmivalenum {"<<std::endl<<" index = "<<tmp_frmival.index<<std::endl<<" type = "<<tmp_frmival.type<<std::endl<<" pixel_format = "<<std::hex<<tmp_frmival.pixel_format<<std::dec<<std::endl<<" width = "<<tmp_frmival.width<<std::endl<<" height = "<<tmp_frmival.height<<std::endl<<" v4l2_fract.numerator = "<<tmp_frmival.discrete.numerator<<std::endl<<" v4l2_fract.denominator = "<<tmp_frmival.discrete.denominator<<std::endl<<" numerator/denominator = "<<tmp_frmival.discrete.denominator / tmp_frmival.discrete.numerator<<" fps"<<std::endl<<"}"<<std::endl;tmp_frmival.index++;}}if(frmivals.size()==0){std::cerr<<"get video frame intervals cout is 0"<<std::endl;return false;}return true;
}bool V4L2CaptureVideoData::StartVideoCapture()
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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;
}bool V4L2CaptureVideoData::StopVideoCapture()
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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;
}bool V4L2CaptureVideoData::RequestVideoBuffer(const v4l2_requestbuffers &requestbuf)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}if(ioctl(m_video_fd, VIDIOC_REQBUFS, &requestbuf)==-1){std::cerr<<"ioctl VIDIOC_REQBUFS failed:("<<"errno="<<errno<<",strerror="<<strerror(errno)<<")"<<std::endl;return false;}return true;
}bool V4L2CaptureVideoData::GetVideoBuffer(const unsigned int memory_type,unsigned int index,struct v4l2_buffer &video_buffer)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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;}std::cout<<"camera v4l2_buffer {"<<std::endl<<" index = "<<video_buffer.index<<std::endl<<" type = "<<video_buffer.type<<std::endl<<" flags = "<<video_buffer.flags<<std::endl<<" memory = "<<video_buffer.memory<<std::endl<<" length = "<<video_buffer.length<<std::endl<<" offset = "<<std::hex<<video_buffer.m.offset<<std::dec<<std::endl<<" fd = "<<std::hex<<video_buffer.m.fd<<std::dec<<std::endl<<" userptr = "<<std::hex<<video_buffer.m.userptr<<std::dec<<std::endl<<"}"<<std::endl;return true;
}bool V4L2CaptureVideoData::PushVideoBuffer(const v4l2_buffer &video_buffer)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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;
}bool V4L2CaptureVideoData::PopVideoBuffer(const unsigned int memory_type,struct v4l2_buffer &video_buffer)
{if(m_video_fd==-1){std::cerr<<"not open video device,must open first"<<std::endl;return false;}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;
}unsigned long V4L2CaptureVideoData::getEpochTimeShiftus()
{struct timeval epochtime;struct timespec vsTime;gettimeofday(&epochtime, NULL);clock_gettime(CLOCK_MONOTONIC, &vsTime);unsigned long uptime_us = vsTime.tv_sec*1000000+(long)round(vsTime.tv_nsec/ 1000.0);unsigned long epoch_us = epochtime.tv_sec*1000000+epochtime.tv_usec;return epoch_us - uptime_us;
}
测试代码test.cpp
#include "v4l2mmapmode.hpp"
#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>//信号绑定,绑定Ctrl+C
static void sig_handler(int sig)
{if (sig == SIGINT) {V4L2CaptureVideoData::m_keeprunning = false;}
}// save picture to file
static int id_index = 0;
//视频帧数据处理函数
void VideoDataFunc(const VideoBufferStruct &video_data)
{std::cout << "device name:" << video_data.dev_name << ",timestamp:" << video_data.timestamp << ",width:" << video_data.width << ",height:" << video_data.height << ",data length:" << video_data.data_len << std::endl;std::string filename = "pictures_yuv/test" + std::to_string(id_index) + ".yuv";int file_fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0777);write(file_fd, video_data.data, video_data.data_len);close(file_fd);id_index++;
}int main(int argc, char *argv[])
{signal(SIGINT, sig_handler); V4L2CaptureVideoData camera_read;//注册回调函数camera_read.RegisterVideoDataProcessCallback(VideoDataFunc);//打开视频设备if(camera_read.OpenVideoDevice("/dev/video0")==false){return -1;}struct v4l2_format video_fmt;memset(&video_fmt, '\0', sizeof(video_fmt));//获取设备当前使用的视频格式if(camera_read.GetVideoDeviceFormat(video_fmt)==false){return -1;}//设置设备的视频格式video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;video_fmt.fmt.pix.width = 1280;video_fmt.fmt.pix.height = 720;video_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;video_fmt.fmt.pix.field = V4L2_FIELD_ANY;if(camera_read.SetVideoDeviceFormat(video_fmt)==false){return -1;}//开始采集数据camera_read.StartMmapData();return 0;
}
测试结果
相关文章:
摄像头原始数据读取——V4L2(mmap模式,V4L2_MEMORY_MMAP)
摄像头原始数据读取——V4L2(mmap模式,V4L2_MEMORY_MMAP) 内存映射模式,是将设备在内核态申请的用于存储视频数据的物理内存映射到用户空间,使得用户应用程序可以直接访问和操作设备数据物理内存,避免了数据的拷贝。因此采集速度较快&#x…...
Ubuntu20.04下安装Matlab2018
Ubuntu20.04下安装Matlab2018 首先需要下载三个文件 挂载第一个镜像文件 先进入到终端,在空白处点击在终端打开 然后输入以下两个命令: mkdir ~/matlab //用户主目录下新建文件夹 matlab sudo mount -o loop Matlab911R2021b_Lin64.iso ~/matlab //将…...
如何做好一份技术文档?
成长路上不孤单😊😊😊😊😊😊 【14后😊///C爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于技术文档写作的相关内容! 关…...
GitHub上如何创建文件夹及上传文件
GitHub上如何创建文件夹_github如何添加文件夹-CSDN博客 然后在对应的文件夹下上传文件即可 可以一个一个添加或一次性拖进去,但一次不能超过100个文件。...
GESP C++等级考试 二级真题(2024年9月)
若需要在线模拟考试,可进入题库中心,在线备考,检验掌握程度: https://www.hixinao.com/tidan/exam-157.html?time1732669362&sid172&index1...
Web 表单开发全解析:从基础到高级掌握 HTML 表单设计
文章目录 前言一、什么是 Web 表单?二、表单元素详解总结前言 在现代 Web 开发中,表单 是用户与后端服务交互的重要桥梁。无论是用户登录、注册、搜索,还是提交反馈,表单都无处不在。在本文中,我们将从基础入手,全面解析表单的核心知识点,并通过示例带你轻松掌握表单开…...
SpringBoot生成顺序规则编号-查询数据库方式实现
先说编号规则: 前缀yyyyMMdd5位序号(00001,00002.......) 首先说说思路: 首先是查询数据库中编号的最大值是多少----->没有数据直接生成一个新的从00001开始----->存在编号就直接截取编号的后5位----->序号1 为了可以…...
【大数据学习 | Spark-Core】RDD的五大特性(包含宽窄依赖)
分析一下rdd的特性和执行流程 A list of partitions 存在一系列的分区列表A function for computing each split 每个rdd上面都存在compute方法进行计算A list of dependencies on other RDDs 每个rdd上面都存在一系列的依赖关系Optionally, a Partitioner for key-value RDDs…...
docker离线安装linux部分问题整理
0:离线安装docker过程命令 echo $PATH tar -zxvf docker-26.1.4.tgz chmod 755 -R docker cp docker/* /usr/bin/ root 权限 vim /etc/systemd/system/docker.service --------- [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.do…...
shell(5)字符串运算符和逻辑运算符
声明! 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&#…...
容器和它的隔离机制
什么是容器和它的隔离机制? 容器 是一种轻量化的虚拟化技术,它允许多个应用程序共享同一个操作系统(OS)内核,同时为每个应用程序提供自己的运行环境。容器通过利用 Linux 的内核功能(如 Namespaces 和 Cgr…...
【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序
DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 1. 窗口的划分 1.1 窗口分为:基于时间的窗口 和 基于数量的窗口 基于时间的窗口:基于起始时间戳 和终止时间戳来决定窗口的大小 基于数量的窗口:根据固定的数量定义窗口 的大小 这…...
DVWA靶场通过——文件上传漏洞
File Upload漏洞 它允许攻击者通过上传恶意文件来执行任意代码、窃取数据、获取服务器权限,甚至完全控制服务器。为了防止文件上传漏洞,开发者需要对文件上传过程进行严格的验证和处理。 1. 文件上传漏洞概述 文件上传漏洞发生在Web应用程序允许用户通过…...
原子类、AtomicLong、AtomicReference、AtomicIntegerFieldUpdater、LongAdder
原子类 JDK提供的原子类,即Atomic*类有很多,大体可做如下分类: 形式类别举例Atomic*基本类型原子类AtomicInteger、AtomicLong、AtomicBooleanAtomic*Array数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArrayAtomic…...
MySQL(8)【聚合函数 | group by分组查询】
阅读导航 引言一、聚合函数1. 简介2. 使用示例(1)COUNT() 函数(2)SUM() 函数(3)AVG() 函数(4)MAX() 函数(5)MIN() 函数 二、group by分组查询1. 基本语法2. 按…...
如何监控Elasticsearch集群状态?
大家好,我是锋哥。今天分享关于【如何监控Elasticsearch集群状态?】面试题。希望对大家有帮助; 如何监控Elasticsearch集群状态? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 监控 Elasticsearch 集群的状态对于确保…...
React第七节 组件三大属性之 refs 的用法注意事项
1、定义 React 中refs 是允许我们操作DOM 访问组件实例的一种方案。开发人员可以直接使用 refs 访问操作DOM,而不用自身的数据状态,这种方案在实际开发过程中是有必要的,但是不建议通篇使用refs操作DOM,如果是这样,那…...
全文单词统计
目标:统计词频 import scala.io.Source //知识点 //1.字符串.split("分隔符"):把字符串用指定的分隔符。拆分成多份,保存在数组中 object test1 {def main(args: Array[String]): Unit { //从文件1.txt中读入内容val contentSourc…...
Angular v19 (二):响应式当红实现signal的详细介绍:它擅长做什么、不能做什么?以及与vue、svelte、react等框架的响应式实现对比
本文紧接着Angular v19 新版本来啦,一起瞧瞧新特性吧!,主要针对它在v18引入了一项全新的响应式技术——Signal,这引起了开发者社区的广泛关注,最新的v19版本推出了更多的signal工具。Signal的加入旨在优化Angular的响应…...
【数据结构】二叉搜索树(二叉排序树)
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:数据结构 目录 前言 一、什么是二叉搜索树 二、二叉搜索树的实现 节点 属性和接口的声明 插入 查找 删除 拷贝构造 析构 中序遍历 三、二叉搜索树的…...
文件的摘要算法(md5、sm3、sha256、crc)
为了校验文件在传输中保证完整性和准确性,因此需要发送方先对源文件产生一个校验码,并将该值传输给接收方,将附件通过ftph或http方式传输后,由接收方使用相同的算法对接收文件再获取一个新的校验码,将该值和发送方传的…...
Python实现人生重开模拟器
目录 人生重开模拟器介绍 代码实现 打印初始界面 设置初始属性 设置角色性别 设置角色出生点 针对每一岁,生成人生经历 完整代码 人生重开模拟器介绍 人生重开模拟器 是之前比较火的一个小游戏,我们这里使用 Python 实现一个简化版的 人生重开模…...
机器学习(二十五):决策树算法以及决策树和神经网络的对比
一、决策树集合 单一决策树会对训练数据的变化很敏感。例子:输入十个数据,判断是否是猫。只替换其中一个数据,信息增益最高的分裂特征就发生了改变,决策树就发生了变化。 使用决策树集合可以使算法更加健壮。例子:使用…...
k8s运行运行pod报错超出文件描述符表限制
1.问题描述 运行pod超过文件描述符表 unable to allocate file descriptor table - out of memory/opt/COMMAND.sh: line 9: 2.查看设备的文件描述符限制 操作前一定要先查询这个值,2097152这个值即为我们可设置的最大值,超过这个值后将无法登录&am…...
非常简单实用的前后端分离项目-仓库管理系统(Springboot+Vue)part 2
七、创建前端项目 你下载了nodejs吗?从cn官网下载:http://nodejs.cn/download/,或者从一个国外org网站下载,选择自己想要的版本https://nodejs.org/download/release/,双击下载好的安装文件,选择安装路径安…...
开源 AI 智能名片 2 + 1 链动模式 S2B2C 商城小程序源码助力品牌共建:价值、策略与实践
摘要:在当今数字化商业环境下,品牌构建已演变为企业与消费者深度共建的过程。本文聚焦于“开源 AI 智能名片 2 1 链动模式 S2B2C 商城小程序源码”,探讨其如何融入品牌建设,通过剖析品牌价值构成,阐述该技术工具在助力…...
微信小程序中的WXSS与CSS的关系及使用技巧
微信小程序中的WXSS与CSS的关系及使用技巧 引言 在微信小程序的开发中,样式的设计与实现是构建用户友好界面的关键。微信小程序使用WXSS(WeiXin Style Sheets)作为其样式表语言,WXSS在语法上与CSS非常相似,但也有一些独特的特性。本文将深入探讨WXSS与CSS的关系,介绍WX…...
STM32的CAN波特率计算
公式: CAN波特率 APB总线频率 / (BRP分频器 1)/ (SWJ BS1 BS2) SWJ一般为1。 例如STM32F407的,CAN1和CAN2都在在APB1下,频率是42000000 如果想配置成1M波特率,则计算公式为:...
【LeetCode面试150】——57插入区间
博客昵称:沈小农学编程 作者简介:一名在读硕士,定期更新相关算法面试题,欢迎关注小弟! PS:哈喽!各位CSDN的uu们,我是你的小弟沈小农,希望我的文章能帮助到你。欢迎大家在…...
活着就好20241128
早晨问候: 亲爱的朋友们,大家早上好!今天是2024年11月28日,第48周的第四天,也是十一月的第二十八天,农历甲辰[龙]年十月廿四。在这个即将步入月末、阳光依旧明媚的清晨,愿第一缕阳光轻轻洒落在…...
【kafka03】消息队列与微服务之Kafka 读写数据
Kafka 读写数据 参考文档 Apache Kafka 常见命令 kafka-topics.sh #消息的管理命令 kafka-console-producer.sh #生产者的模拟命令 kafka-console-consumer.sh #消费者的模拟命令 创建 Topic 创建topic名为 chen,partitions(分区)为3࿰…...
【Agorversev1.1数据转换】Agorverse高清地图转OpenStreetMap及SUMO路网
文章目录 Agorverse高清地图转OpenStreetMap及SUMO路网1. Agorverse osm转换说明2. 转换源码3. 处理效果4. SUMO-Carla联合仿真 Agorverse高清地图转OpenStreetMap及SUMO路网 1. Agorverse osm转换说明 根据作者的描述,其高清地图的osm文件与标准osm的区别在于以下…...
Vue 3 实现高性能拖拽指令的最佳实践
前言 在现代前端开发中,拖拽功能是增强用户体验的重要手段之一。本文将详细介绍如何在 Vue 3 中封装一个拖拽指令(v-draggable),并通过实战例子演示其实现过程。通过这篇教程,您将不仅掌握基础的拖拽功能,…...
AIGC--------AIGC在医疗健康领域的潜力
AIGC在医疗健康领域的潜力 引言 AIGC(Artificial Intelligence Generated Content,人工智能生成内容)是一种通过深度学习和自然语言处理(NLP)等技术生成内容的方式。近年来,AIGC在医疗健康领域展现出了极…...
Apache Calcite - calcite jdbc驱动使用场景
前言 在使用Calcite查询数据时通常会用到这些代码获取schema Connection connection DriverManager.getConnection("jdbc:calcite:", info); CalciteConnection calciteConnection connection.unwrap(CalciteConnection.class); SchemaPlus rootSchema calciteC…...
IEC61850实现方案和测试-4-MMS协议
IEC61850实现方案和测试-4作为介绍实现方案和测试的第四篇文章,后续会继续更新,欢迎关注。前三篇如下 第一篇是:IEC61850实现方案和测试-1-CSDN博客 第二篇是:IEC61850实现方案和测试-2-UCA-CSDN博客 第三篇是:IEC6…...
【ubuntu24.04】GTX4700 配置安装cuda
筛选显卡驱动显卡驱动 NVIDIA-Linux-x86_64-550.135.run 而后重启:最新的是12.6 用于ubuntu24.04 ,但是我的4700的显卡驱动要求12.4 cuda...
时间的礼物:如何珍视每一刻
《时间的礼物:如何珍视每一刻》 夫时间者,宇宙之精髓,生命之经纬,悄无声息而流转不息,如织锦之细线,串联古今,贯穿万物。 人生短暂,犹如白驹过隙,倏忽而逝,…...
componentReceivePropsreact class生命周期
componentReceiveProps并不是有props的变化触发,而是由父组件的更新触发的 父组件导致组件重新渲染,即使props没有更改,也会调用componentReceiveProps这个方法;如果只想处理更改,确保当前值与变更值比较--官方 …...
快速理解微服务中Sentinel怎么实现限流
Sentinel是通过动态管理限流规则,根据定义的规则对请求进行限流控制。 一.实现步骤 1.定义资源:在Sentinel中,资源可以是URL、方法等,用于标识需要进行限流的请求;(在Sentinel中,需要我们去告诉Sentinel哪些…...
25.100ASK_T113-PRO 测试摄像头(型号)
1.摄像头 USB2.0 摄像头,支持 UVC协议, 就是V4L2 USB2.0 大概可这样理解吧.这个是2K分辨率. 2.8mm焦距. 开发板还是 100ASK_T113-PRO V1.2版 2.查看摄像头驱动挂载情况 这样接好. 看看设备有没有挂载上 # ls /dev/video* /dev/video0 /dev/video1 这两个就是USB摄像头.说…...
20241127 给typecho文章编辑附件 添加视频 图片预览
Typecho在写文章时,如果一次性上传太多张图片可能分不清哪张,因为附件没有略缩图,无法实时阅览图片,给文章插入图片时很不方便。 编辑admin/file-upload.php 大约十八行的位置 一个while 循环里面,这是在进行html元素更新操作,在合…...
StarRocks-join优化
1、背景 有两个大表,都是6kw级别上下的,通过SR然后包装了一个接口对外提供查询,当前的问题是,这样大的join查询会导致BE直接宕机。并且这个sql很有代表性,我截图如下: 这个表是个单分区,所以直接…...
如何通过ChatGPT提高自己的编程水平
在编程学习的过程中,开发者往往会遇到各种各样的技术难题和学习瓶颈。传统的学习方法依赖书籍、教程、视频等,但随着技术的不断发展,AI助手的崛起为编程学习带来了全新的机遇。ChatGPT,作为一种强大的自然语言处理工具,…...
实时数据开发 | checkpoints监控和调优
监控Checkpoints 监控 checkpoint 行为最简单的方法是通过 UI 的 checkpoint 部分。 监控这两个指标: 算子收到第一个 checkpoint barrier 的时间。当触发 checkpoint 的耗费时间一直很高时,这意味着 checkpoint barrier 需要很长时间才能从 source 到达 operator…...
面试手撕题积累
1、实现滑动窗口限流,允许每分钟最多有100个请求 阿里一面题。 核心: 时间窗口管理:滑动窗口会根据时间流逝不断更新,需要记录请求的时间戳,并根据当前时间计算窗口内的请求数量。 限流判断:每次请求到来…...
开发中使用UML的流程_05 PIM-1:分析系统流程
目录 1、概述 2、PIM生成的过程 3、用例叙述格式 4、用例关系 5、执行流程: 6、惯用的编号方式 1、概述 在进入到PIM阶段之后,系统分析员将所有系统用例依相关性分成若干组,以组别方式生成该组系统用例涉及的PIM-1---PIM-4产生结果&am…...
【Go】-go中的锁机制
目录 一、锁的基础知识 1. 互斥量/互斥锁 2. CAS(compare and swap) 3. 自旋锁 4. 读写锁 5. 乐观锁 & 悲观锁 6. 死锁 二、go中锁机制 1. Mutex-互斥锁 2. RWMutex-读写锁 2.1 RWMutex流程概览 2.2 写锁饥饿问题 2.3. golang的读写锁源…...
Scala学习记录,全文单词统计
package test32 import java.io.PrintWriter import scala.io.Source //知识点 // 字符串.split("分隔符":把字符串用指定的分隔符,拆分成多个部分,保存在数组中) object test {def main(args: Array[String]): Unit {//从文件1.t…...
重构项目架构
前言 我们上篇文章对整个项目进行一个整体的规划,其中对于APP类规划了类,本篇文章我们就来实现这个规划; class App {//加载页面constructor() {}//获取位置_getPosition() {}//接受位置_loadMap() {}//在地图上点击展现表单_showForm() {}/…...