v4l2 打开摄像头,ioctl 发送VIDIOC_DQBUF命令返回-1,错误码62:Timer expired

RwinR 2019-03-15 12:19:40
这两天在琢磨用v4l2框架开启摄像头,遇到了解决不了的问题,在百度上也搜不到相关解决办法,求各位前辈指教。

我写的代码执行到发送命令VIDIOC_DQBUF获取帧数据的时候,返回-1,提示错误信息Timer expired,

我申请的的缓冲区个数是三个,取第一个缓冲区数据失败,第二个第三个会成功,但是取到的数据写到jpg文件在电脑上无法显示。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>

struct buf_inf
{
void *start;
int length;
};


int main()
{
int i,ret,camfd;
char jpgpath[10];

camfd = open("/dev/video7",O_RDWR);
if(camfd == -1)
{
perror("打开摄像头驱动失败\n");
return -1;
}

//获取摄像头功能参数
struct v4l2_capability cam_cap;
bzero(&cam_cap,sizeof(cam_cap));
ret = ioctl(camfd,VIDIOC_QUERYCAP,&cam_cap);
if(ret == -1)
{
perror("获取摄像头功能参数失败\n");
return -1;
}

printf("version:%d\n",cam_cap.version);

//设置摄像头通道
int channel=0;
ret = ioctl(camfd,VIDIOC_S_INPUT,&channel);
if(ret == -1)
{
perror("设置摄像头通道失败\n");
return -1;
}

//获取摄像头的采集格式
struct v4l2_format cam_fmt;
bzero(&cam_fmt,sizeof(cam_fmt));
cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(camfd,VIDIOC_G_FMT,&cam_fmt);
if(ret == -1)
{
perror("获取摄像头采集格式失败\n");
return -1;
}
printf("摄像头当前的宽为:%d 高为:%d\n",cam_fmt.fmt.pix.width,cam_fmt.fmt.pix.height);

//设置摄像头采集格式
bzero(&cam_fmt,sizeof(cam_fmt));
cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cam_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
cam_fmt.fmt.pix.width = 640;
cam_fmt.fmt.pix.height = 480;
ret = ioctl(camfd,VIDIOC_S_FMT,&cam_fmt);
if(ret == -1)
{
perror("设置摄像头采集格式失败\n");
return -1;
}
printf("摄像头当前的宽为:%d 高为:%d\n",cam_fmt.fmt.pix.width,cam_fmt.fmt.pix.height);


//申请缓冲块
struct v4l2_requestbuffers cam_bufs;
bzero(&cam_bufs,sizeof(cam_bufs));
cam_bufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cam_bufs.memory = V4L2_MEMORY_MMAP;
cam_bufs.count = 3;

ret = ioctl(camfd,VIDIOC_REQBUFS,&cam_bufs);
if(ret == -1)
{
perror("申请缓冲块失败\n");
return -1;
}

//分配缓冲块
struct buf_inf *cam_inf = calloc(cam_bufs.count,sizeof(struct buf_inf));
for(i=0; i<cam_bufs.count; i++)
{
struct v4l2_buffer cam_buf;
bzero(&cam_buf,sizeof(cam_buf));
cam_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cam_buf.memory = V4L2_MEMORY_MMAP;
cam_buf.index = i;

ret = ioctl(camfd,VIDIOC_QUERYBUF,&cam_buf);
if(ret == -1)
{
perror("分配缓冲块失败\n");
return -1;
}

//把分配到的内存映射到自定义的空间(保存首地址,方便使用)
cam_inf[i].start = mmap(NULL, cam_buf.length, PROT_WRITE|PROT_READ, MAP_SHARED,camfd, cam_buf.m.offset);
if(cam_inf[i].start == NULL)
{
perror("映射内存失败\n");
}

cam_inf[i].length = cam_buf.length;
}

//将帧数据放到缓存(入队)
for(i=0; i<cam_bufs.count; i++)
{
struct v4l2_buffer cam_buf;
bzero(&cam_buf,sizeof(cam_buf));
cam_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cam_buf.memory = V4L2_MEMORY_MMAP;
cam_buf.index = i;

ret = ioctl(camfd,VIDIOC_QBUF,&cam_buf);
if(ret == -1)
{
perror("入队失败\n");
return -1;
}
}

//开启摄像头,采集数据
enum v4l2_buf_type cam_type1 = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(camfd,VIDIOC_STREAMON,&cam_type1);
if(ret == -1)
{
perror("开启摄像头失败\n");
return -1;
}

//将缓冲块中的帧数据拿出来保存到空白的JPG文件中
for(i=0; i<cam_bufs.count; i++)
{
struct v4l2_buffer cam_buf1;
bzero(&cam_buf1,sizeof(cam_buf1));
cam_buf1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cam_buf1.memory = V4L2_MEMORY_MMAP;
cam_buf1.index = i;

printf("出队%d\n",i);
ret = ioctl(camfd,VIDIOC_DQBUF,&cam_buf1);
if(ret == -1)
{
perror("出队失败\n");
printf("errno:%d\n",errno);
continue;
}

sprintf(jpgpath,"%d.jpg",i);
int fd = open(jpgpath,O_CREAT|O_TRUNC|O_RDWR);
if(fd == -1)
{
perror("创建jpg文件失败\n");
return -1;
}

write(fd,cam_inf[i].start,cam_inf[i].length);

close(fd);
}

//关闭摄像头,停止采集数据
ret = ioctl(camfd,VIDIOC_STREAMOFF,&cam_type1);
if(ret == -1)
{
perror("关闭摄像头失败\n");
return -1;
}

return 0;
}


运行结果如下
version:197671
摄像头当前的宽为:640 高为:480
摄像头当前的宽为:640 高为:480
出队0
出队失败
: Timer expired
errno:62
出队1
出队2
...全文
1154 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

5,313

社区成员

发帖
与我相关
我的任务
社区描述
硬件使用专区,欢迎大家讨论硬件相关内容 宝藏!数字IC精品文章收录(CSDN近500篇) http://t.csdn.cn/QbivO
社区管理员
  • 硬件使用社区
  • 张江打工人
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧