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

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

用户指针方式允许用户空间的应用程序分配内存,并将内存地址传递给内核中的驱动程序。驱动程序直接将数据填充到用户空间的内存中,从而避免了数据的拷贝过程。
流程:

  1. 通过VIDIOC_REQBUFS ioctl请求内核分配视频数据缓冲区,在v4l2_requestbuffers里将memory字段设置成V4L2_MEMORY_USERPTR
  2. 通过VIDIOC_QUERYBUF ioctl获取内核已经分配好的视频数据缓冲区信息。
  3. 应用程序分配内存,并将内存地址填充到已经分配好的视频缓冲区中。
  4. 通过VIDIOC_QBUF ioctl将已经申请好的缓冲区放入数据缓存队列,将memory字段设置成V4L2_MEMORY_USERPTR
  5. 启动视频流后,使用poll或select函数等待设备缓冲区数据就绪。
  6. 通过VIDIOC_DQBUF ioctl从队列中取出已填充的数据缓冲区并进行处理。
  7. 处理完数据后,再次通过VIDIOC_QBUF ioctl将缓冲区放入输入队列,循环使用。

v4l2userptrmode.hpp

#ifndef _V4L2USERPTRMODE_H_
#define _V4L2USERPTRMODE_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;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 RegisterVideoUserptr(std::vector<std::pair<unsigned long, unsigned int>> &video_userptr);void StartUserptrData();/* 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;std::vector<std::pair<unsigned long, unsigned int>> m_video_userptr;
};#endif // _V4L2USERPTRMODE_H_

v4l2userptrmode.cpp

#include "v4l2userptrmode.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();m_video_userptr.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::RegisterVideoUserptr(std::vector<std::pair<unsigned long, unsigned int>> &video_userptr)
{m_video_userptr=video_userptr;
}void V4L2CaptureVideoData::StartUserptrData()
{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;}if(m_video_userptr.size()==0){std::cerr<<"not input already allocated memory block for v4l2 using in userptr mode"<<std::endl;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;unsigned int video_req_buffer_cnt=m_video_userptr.size();struct v4l2_requestbuffers video_req_buffer;memset(&video_req_buffer,'\0',sizeof(video_req_buffer));video_req_buffer.count = video_req_buffer_cnt;video_req_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;video_req_buffer.memory = V4L2_MEMORY_USERPTR;if(RequestVideoBuffer(video_req_buffer)==false){return;}for(int index=0;index<video_req_buffer_cnt;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_USERPTR;tmp_video_buffer.m.userptr = m_video_userptr[index].first;tmp_video_buffer.length =m_video_userptr[index].second;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_USERPTR,video_buffer_data)==false){break;}data_buffer.data=(void*)m_video_userptr[video_buffer_data.index].first;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;}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 "v4l2userptrmode.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, char **)
{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;}//申请用户空间内存std::vector<std::pair<unsigned long, unsigned int>> video_userptr_block;void *userptr_databuffer[4];for (int index = 0; index < 4; index++){userptr_databuffer[index] = malloc(video_fmt.fmt.pix.sizeimage);video_userptr_block.push_back(std::make_pair((unsigned long)userptr_databuffer[index], video_fmt.fmt.pix.sizeimage));}//注册用户空间内存,用以接收图像数据camera_read.RegisterVideoUserptr(video_userptr_block);//开始采集数据camera_read.StartUserptrData();//释放用户空间申请的内存for (int index = 0; index < 4; index++){free(userptr_databuffer[index]);userptr_databuffer[index]=NULL;}return 0;
}

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

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

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

相关文章

亚马逊开发视频人工智能模型,The Information 报道

根据《The Information》周三的报道&#xff0c;电子商务巨头亚马逊&#xff08;AMZN&#xff09;已开发出一种新的生成式人工智能&#xff08;AI&#xff09;&#xff0c;不仅能处理文本&#xff0c;还能处理图片和视频&#xff0c;从而减少对人工智能初创公司Anthropic的依赖…

一次完整的CNAS软件测试实验室内部审核流程

内部审核是软件测试实验室管理体系重的重要部分&#xff0c;通过内部审核可以为有效的管理评审和纠正、预防措施提供信息&#xff0c;以验证组织的管理体系是否持续的满足规定的要求并且正在运行。 内部审核需要依据文件化的程序&#xff0c;每年至少实施一次&#xff0c;软件…

Matlab数字信号处理——音频信号处理与分析GUI

1.实现内容 实现功能有回响、变声、倒放、变速、音量调整、加噪、设计 FIR和 IR 滤波器实现去噪功能(高通低通带通带阻)&#xff0c;并且在时域波形图和频域波形展示变化。滤波器包括各种参数的选择、滤波器结构和类型的选择等。同时GUI上还包含打开、播放、保存、退出功能。 …

pcb线宽与电流

三十年一路高歌猛进的中国经济&#xff0c; 中国经历了几个三十年&#xff1f; 第一个三十年&#xff1a;以计划为导向。 第二个三十年&#xff1a;以经济为导向。 现在&#xff0c;第三个三十年呢&#xff1f; 应该是以可持续发展为导向。 传统企业摇摇欲坠&#xff0c; 新兴企…

redis命令 及 redis 常见的数据结构

文章目录 一. 核心命令1. set2. get 二. 全局命令1. keys2. exists3. del4. expire5. ttl6. type 三. redis 常见的数据结构 一. 核心命令 1. set set key value key 和 value 都是string类型的 对于key value, 不需要加上引号, 就是表示字符串类型, 加上也可以 redis中, 不…

跨平台应用开发框架(4)----Qt(系统篇)

目录 1.Qt事件 1.事件来源 2.事件处理 3.按键事件 1.组合按键 4.鼠标事件 1.鼠标单击事件 2.鼠标释放事件 3.鼠标双击事件 4.鼠标移动事件 5.滚轮事件 5.定时器 1.QTimerEvent类 2.QTimer 类 3.获取系统日期及时间 6.事件分发器 7.事件过滤器 2.Qt文件 1.输入…

uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?

在uniapp(App端)中实现自定义弹框&#xff0c;可以通过创建一个透明页面来实现。点击进入当前页面时&#xff0c;页面背景会变透明&#xff0c;用户可以根据自己的需求进行自定义&#xff0c;最终效果类似于弹框。 遇到问题&#xff1a;当打开弹窗(进入弹窗页面)就会触发当前页…

DM达梦管理工具拖出空白区块,无法关闭

1. 出现问题&#xff1a;DM达梦管理工具拖出空白区块&#xff0c;无法关闭。 2. 解决方法 新建查询页&#xff0c;把查询页拖到空白区块里&#xff0c;完全覆盖空白区块。之后空白区块会变成查询页&#xff0c;右上角会出现叉号&#xff0c;点击叉号关闭就行。 3. 后记 达梦…

DevExpress的web Dashboard应用

本文旨在从零开始创建一个包含dashboard的应用 一、前期准备 1、语言&#xff1a;C# 2、软件&#xff1a;Visual Studio 2019 3、框架&#xff1a;DevExpress19.2(付费)、ASP.NET(Web) 4、组件&#xff1a;dashboard 二、创建ASP.NET Web窗体仪表板应用程序 1、创建一个空的w…

【vue-router】Vue-router如何实现路由懒加载

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

go语言切片

切片 切片是一种数据结构&#xff0c;这种数据结构便于使用和管理数据集合。切片是围绕动态数组的概念构建的&#xff0c;可以按需自动增长和缩小。切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的…

2024年一级建造师考试成绩,即将公布!

一级建造师考试成绩一般在考试结束后3个月左右的时间公布&#xff01; 根据官方通知&#xff0c;重庆、江苏、青海、江西、云南、湖南、福建、北京、山西、黑龙江等地在今年一建报名通知里提到&#xff1a;2024年一级建造师考试成绩预计于2024年12月上旬公布。考生可在这个时间…

基于Matlab的图像去噪算法仿真

中值滤波的仿真 本节选用中值滤波法对含有高斯噪声和椒盐噪声的图像进行去噪&#xff0c;并用Matlab软件仿真。 &#xff08;1&#xff09;给图像加入均值为0&#xff0c;方差为0.02的高斯噪声&#xff0c;分别选择33模板、55模板和77模板进行去噪 Matlab部分代码&#xff1…

交通流量预测:基于交通流量数据建立模型

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

嵌入式QT学习第4天:Qt 信号与槽

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 本章思维导图如下&#xff1a; 不使用 Qt Designer 的方式进行开发&#xff0c;用代码绘界面&#xff0c;可以锻炼我们的布局能力&#xff0c;和代码逻辑能力&#x…

多线程+线程池

普通线程的创建 三种创建方式实例&#xff1a; 多线程本质上是毫无关系的&#xff0c;执行顺序是不可预知的&#xff0c;但是由于callable方式创建的对象有返回值所以主函数在执行的时候&#xff0c;需要等待返回值回来才能继续执行其他线程&#xff0c;所以在这种状态下是…

mac访达打开终端

选择文件夹打开 选中文件夹&#xff0c;然后右键即可&#xff1a; 在当前文件夹打开 在访达的当前文件夹长按option键 左下角出现当前文件夹路径 右键即可打开终端

【模型剪枝】YOLOv8 模型剪枝实战 | 稀疏化-剪枝-微调

文章目录 0. 前言1. 模型剪枝概念2. 模型剪枝实操2.1 稀疏化训练2.2 模型剪枝2.3 模型微调总结0. 前言 无奈之下,我还是写了【模型剪枝】教程🤦‍♂️。回想当年,在写《YOLOv5/v7进阶实战专栏》 时,我经历了许多挫折,才最终完成了【模型剪枝】和【模型蒸馏】的内容。当时…

Django 路由层

1. 路由基础概念 URLconf (URL 配置)&#xff1a;Django 的路由系统是基于 urls.py 文件定义的。路径匹配&#xff1a;通过模式匹配 URL&#xff0c;并将请求传递给对应的视图处理函数。命名路由&#xff1a;每个路由可以定义一个名称&#xff0c;用于反向解析。 2. 基本路由配…

单点登录原理

允许跨域–>单点登录。 例如https://www.jd.com/ 同一个浏览器下&#xff1a;通过登录页面产生的cookie里的一个随机字符串的标识&#xff0c;在其他子域名下访问共享cookie获取标识进行单点登录&#xff0c;如果没有该标识则返回登录页进行登录。 在hosts文件下面做的域名…