v4l2视频采集笔记

int video_fd = v4l2_open(“/dev/video0”, O_RDWR | O_NONBLOCK, 0);

开启视频设备文件;

v4l2_capability cap;

int ret = vc_ioctl(video_fd, VIDIOC_QUERYCAP, &cap);

获取设备能力,功能,是否有视频输入,采集输入输出方式(直接读写,流形式(内存映射(不需要new),用户内存指针等));

int vc_ioctl(int fd, unsigned long int request, void *arg)

{

​ int ret = 0;

​ do { ret = v4l2_ioctl( fd, request, arg ); }

​ while (ret == -1 && ((errno == EINTR) || (errno == EAGAIN)));

​ return ret;

​}各种io控制,具体数据结构可以自己f2进去慢慢看。

if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))

{

//not a video capture device

}

if(cap.capabilities & V4L2_CAP_READWRITE)

{

//is read and write!

}

if(cap.capabilities & V4L2_CAP_STREAMING)

{

//it can use mmap!

}

设置帧格式:
v4l2_format fmt , afmt;

afmt.pixelformat = V4L2_PIX_FMT_YUV420;

​memset(&fmt, 0x00, sizeof(fmt));

​fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

​fmt.fmt.pix = afmt;

​vc_ioctl(video_fd, VIDIOC_S_FMT, &fmt);

获取视频帧格式,定义an image format:

v4l2_format fmt;

memset(&fmt, 0x00, sizeof(fmt));

​fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//类型都是这个宏 。。

​vc_ioctl(video_fd, VIDIOC_G_FMT, &fmt);

​获取帧率:

​v4l2_streamparm param;

​memset(&param, 0x00, sizeof(param));

​param.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

​vc_ioctl(video_fd, VIDIOC_G_PARM, &param);//获取。。

​if (param.parm.capture.timeperframe.numerator != 0) 

int fps = param.parm.capture.timeperframe.denominator / param.parm.capture.timeperframe.numerator; //我也不知道为什么这么算???

​设置帧率:

​v4l2_streamparm param;

​memset(&param, 0x00, sizeof(param));

​param.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

​param.parm.capture.timeperframe.denominator = fps; //分母param.parm.capture.timeperframe.numerator = 1; //分子

​vc_ioctl(video_fd, VIDIOC_S_PARM, &param);//设置。。


​这里采用内存映射获取输入流:1.设置为内存映射; 2.指定大小的内存映射缓冲区(不小于3,不大于5)

​v4l2_requestbuffers req;req.count = 4;//缓冲区大小

​req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

​req.memory = V4L2_MEMORY_MMAP;//内存映射

​int ret = vc_ioctl(video_fd, VIDIOC_REQBUFS, &req);

​class Ca_Buf

​{

​public: 

unsigned long video_len; 

char * video_buf; 

Ca_Buf()

​ : video_len(0)

​ , video_buf(0)

​ {}

​};

​std::vector< Ca_Buf > buffers;

​buffers.resize(4);

​for (unsigned int i = 0; i < 4; i ++) 

v4l2_buffer buf; 

memset(&buf, 0x00, sizeof(buf));

​ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 

buf.memory = V4L2_MEMORY_MMAP; 

buf.index = i;

​ ret = vc_ioctl(video_fd, VIDIOC_QUERYBUF, &buf);

 buffers[i].video_len = buf.length;

​ buffers[i].video_buf = (char*)v4l2_mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, video_fd, buf.m.offset);//内存映射 。。

​ if (buffers[i].video_buf == MAP_FAILED) 

printf("capture mmap buf failure!\n"); 

return -1; 

}

 ret = vc_ioctl(video_fd, VIDIOC_QBUF, &buf);

}

​开始采集码流:

​v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

​ret = vc_ioctl(video_fd, VIDIOC_STREAMON, &type);

​获取缓冲区中视频帧流,取出最先入队的帧缓冲区指针:

​v4l2_buffer dq_buf;

​memset(&dq_buf,0,sizeof(dq_buf));

​dq_buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

​dq_buf.memory=V4L2_MEMORY_MMAP;

​dq_buf.index=0;

​int ret = vc_ioctl(video_fd, VIDIOC_DQBUF, &dq_buf);

​这出队后是码流处理,渲染或是存储,反正就是拷贝后(随你怎么用)才能将指针入队。将缓冲区指针再次入队,等待收取新的帧流:

​int ret = vc_ioctl(video_fd, VIDIOC_QBUF, &dq_buf);

​停止采集数据:

​v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

​int ret = vc_ioctl(video_fd, VIDIOC_STREAMOFF, &type);

​释放内存映射:

​for(size_t i = 0; i < buffers.size(); i++)

​{ 

ret = v4l2_munmap(buffers[i].video_buf, buffers[i].video_len);

​ if (ret == -1) 

{ printf("capture munmap buf failure!\n"); return -1; }

​}

​关闭设备文件:v4l2_close(video_fd);

检查当前视频设备支持的标准

在亚洲,一般使用PAL(720X576)制式的摄像头,而欧洲一般使用NTSC(720X480),使用VIDIOC_QUERYSTD来检测

v4l2_std_id std;

ret = vc_ioctl(video_fd, VIDIOC_QUERYSTD, &std);

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值