這兩天在琢磨用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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/154123.html
標籤:硬件使用
上一篇:TTL轉接串口
