摄像头原始数据读取——V4L2(mmap模式,V4L2_MEMORY_MMAP)

摄像头原始数据读取——V4L2(mmap模式,V4L2_MEMORY_MMAP)

内存映射模式,是将设备在内核态申请的用于存储视频数据的物理内存映射到用户空间,使得用户应用程序可以直接访问和操作设备数据物理内存,避免了数据的拷贝。因此采集速度较快,一般用于连续视频数据的采集。
流程:

  1. 通过VIDIOC_REQBUFS ioctl请求内核分配视频数据缓冲区。
  2. 通过VIDIOC_QUERYBUF ioctl获取内核已经分配好的视频数据缓冲区信息。
  3. 使用mmap函数将获取到的缓冲区映射到用户空间。
  4. 通过VIDIOC_QBUF ioctl将已经申请好的缓冲区放入数据缓存队列。
  5. 启动视频流后,使用poll或select函数等待设备缓冲区数据就绪。
  6. 通过VIDIOC_DQBUF ioctl从队列中取出已填充的数据缓冲区并进行处理。
  7. 处理完数据后,再次通过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;
}

测试结果
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/479096.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零地址挂页

零地址 如果我们有比较好的C编程基础&#xff0c;我们就会知道&#xff0c;我们在代码中定义了一个零地址或者空指针&#xff0c;那么它实际上会指向虚拟内存的零地址&#xff0c;多数操作系统&#xff0c;包括Win&#xff0c;在进程创建的时候&#xff0c;都会空出前64k的空间…

QT6学习第四天 感受QT的文件编译

QT6学习第四天 感受QT的文件编译 使用纯代码编写程序新建工程 使用其他编辑器纯代码编写程序并在命令行运行使用 .ui 表单文件生成界面使用自定义 C 窗口类使用现成的QT Designer界面类 使用纯代码编写程序 我们知道QT Creator中可以用拖拽的方式在 .ui 文件上布局&#xff0c…

windows安全中心,永久卸载工具分享

使用方法 2024Goby红队版工具分享&#xff0c;附2024年漏洞POC下载 下载链接&#xff1a; https://pan.quark.cn/s/4fc2712a2afc一路回车&#xff0c;选项Y即可 耐心等待几秒种&#xff0c;自动重启 此时打开windows安全中心&#xff0c;已经完全不能使用了&#xff0c;响应…

jvm核心组件介绍

1. 类加载器&#xff08;ClassLoader&#xff09;&#xff1a; • 想象它是一个快递员&#xff0c;负责把Java类&#xff08;.class文件&#xff09;这个“包裹”从磁盘这个“发货地”送到JVM内部这个“目的地”。类加载器确保每个类只被加载一次&#xff0c;并维护一个类的层级…

目标检测,图像分割,超分辨率重建

目标检测和图像分割 目标检测和图像分割是计算机视觉中的两个不同任务&#xff0c;它们的输出形式也有所不同。下面我将分别介绍这两个任务的输出。图像分割又可以分为&#xff1a;语义分割、实例分割、全景分割。 语义分割&#xff08;Semantic Segmentation&#xff09;&…

Python编程技巧:多变量赋值的优雅艺术

在Python编程的世界里&#xff0c;有许多令人惊叹的语法特性&#xff0c;而多变量赋值就像是一颗闪耀的明珠&#xff0c;它不仅让代码更优雅&#xff0c;还能提升程序的执行效率。今天我们就深入探讨这个看似简单却蕴含深意的编程技巧。 基础认识 传统的变量赋值方式&#xff…

CentOS 7 安装部署 KVM

1.关闭虚拟机 打开相关选项 打开虚拟机centos7 连接xshell 测试网络&#xff0c;现在就是没问题的&#xff0c;因为我们要使用网络源 安装 GNOME 桌面环境 安装KVM 模块 安装KVM 调试工具 构建虚拟机的命令行工具 qemu 组件,创建磁盘、启动虚拟机等 输入这条命令&#xff0c;…

微信小程序学习指南从入门到精通

&#x1f5fd;微信小程序学习指南从入门到精通&#x1f5fd; &#x1f51d;微信小程序学习指南从入门到精通&#x1f51d;✍前言✍&#x1f4bb;微信小程序学习指南前言&#x1f4bb;一、&#x1f680;文章列表&#x1f680;二、&#x1f52f;教程文章的好处&#x1f52f;1. ✅…

【C++】读取数量不定的输入数据

读取数量不定的输入数据 似乎是一个很实用的东西&#xff1f; 问题&#xff1a; 我们如何对用户输入的一组数&#xff08;事先不知道具体有多少个数&#xff09;求和&#xff1f; 这需要不断读取数据直至没有新的输入为止。&#xff08;所以我们的代码就是这样设计的&#x…

基于vite创建的react18项目的单元测试

题外话 最近一个小伙伴进了字节外包&#xff0c;第一个活就是让他写一个单元测试。 嗯&#xff0c;说实话&#xff0c;在今天之前我只知道一些理论&#xff0c;但是并没有实操过&#xff0c;于是我就试验了一下。 通过查询资料&#xff0c;大拿们基本都说基于vite的项目&…

如何用通义灵码助力项目开发 | OceanBase obdiag 项目共建实践

本文来自 obdiag 项目共建的用户分享 一、背景 我的数据库探索之旅始于OceanBase。作为一位满怀好奇心的DBA&#xff0c;我内心始终怀揣着对数据库内部运作机制的无尽向往。开源如同一把钥匙&#xff0c;为我们这些求知欲旺盛的“好奇猫”解锁了通往新知的神秘大门。在众多分布…

idea_卸载与安装

卸载与安装 卸载1、设置 -> 应用2、查找到应用&#xff0c;点击卸载3、把删除记录和设置都勾选上4、删除其它几个位置的残留 安装1、下载安装包2、欢迎安装 -> Next3、选择安装目录 -> Next4、创建快捷图标和添加到环境变量5、确认文件夹的名称 -> Install6、完成安…

day01

Hm-Footer.vue <template><div class"hm-footer">我是hm-footer</div></template><script>export default {}</script><style>.hm-footer{height:100px;line-height:100px;text-align:center;font-size:30px;background-…

NLP 1、人工智能与NLP简介

人人都不看好你&#xff0c;可偏偏你最争气 —— 24.11.26 一、AI和NLP的基本介绍 1.人工智能发展流程 弱人工智能 ——> 强人工智能 ——> 超人工智能 ① 弱人工智能 人工智能算法只能在限定领域解决特定的问题 eg&#xff1a;特定场景下的文本分类、垂直领域下的对…

基于混合ABC和A*算法复现

基于混合ABC和A*算法复现 一、背景介绍二、算法原理&#xff08;一&#xff09;A*算法原理&#xff08;二&#xff09;人工蜂群算法原理&#xff08;三&#xff09;混合ABC和A*算法策略 三、代码实现&#xff08;一&#xff09;数据准备&#xff08;二&#xff09;关键函数实现…

解决SpringBoot连接Websocket报:请求路径 404 No static resource websocket.

问题发现 最近在工作中用到了WebSocket进行前后端的消息通信&#xff0c;后端代码编写完后&#xff0c;测试一下是否连接成功&#xff0c;发现报No static resource websocket.&#xff0c;看这个错貌似将接口变成了静态资源来访问了&#xff0c;第一时间觉得是端点没有注册成…

VITE+VUE3+TS环境搭建

前言&#xff08;与搭建项目无关&#xff09;&#xff1a; 可以安装一个node管理工具&#xff0c;比如nvm&#xff0c;这样可以顺畅的切换vue2和vue3项目&#xff0c;以免出现项目跑不起来的窘境。我使用的nvm&#xff0c;当前node 22.11.0 目录 搭建项目 添加状态管理库&…

红外小目标检测

目录 背景概述算法原理演示效果核心逻辑 使用方式基础镜像配置环境直接运行 参考文献 文章声明&#xff0c;非广告&#xff0c;仅个人体验。 背景 红外图像在许多领域中都有所应用。例如军事领域中&#xff0c;经常需要通过红外成像设备对远距离的目标进行侦察和监视&#xff…

【滑动窗口】找到字符串中所有字母异位词

文章目录 找到字符串中所有字母异位词 class Solution { public:vector<int> findAnagrams(string s, string p) {vector<int> ret;int sLen s.size(), pLen p.size(), validChar;// 母串长度比子串长度还小 直接返回空vectorif (sLen < pLen)return ret;// …

nodepad配置c/c++ cmd快速打开创建项目文件

前提:下载MinGw,并且配置环境变量 点击阅读次篇文章配置MinGw 无论是哪个编译器&#xff0c;执行c文件都是经历以下步骤: 编译文件生成exe文件执行该exe文件 我们先手动完成这两部 手动编译文件使用指令 gcc {你的c文件} -o {生成文件名}生成exe文件 第二步运行exe直接点击该文…