1. 程式人生 > >Linux下使用v4l2程式設計操作攝像頭裝置獲取圖片

Linux下使用v4l2程式設計操作攝像頭裝置獲取圖片

進行操作前請參考我的另一篇部落格:

看懂之後再研究下面的程式:

/*****************************************************
 * 檔名:GetYuyv.c
 * 檔案描述:linux下使用v4l2程式設計操作攝像頭裝置獲取圖片 
 * 編寫人:王廷雲
 * 編寫日期:2017-12-1
 * 修改日期:2018-1-1
*****************************************************/
#include <stdio.h>
#include <unistd.h>

#include <sys/types.h>
// 下面四個標頭檔案是linux系統程式設計特有的 #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <fcntl.h> #include <linux/videodev2.h> // 操作攝像頭裝置 #define WIDTH 640 // 圖片的寬度 #define HEIGHT 480
// 圖片的高度 #define FMT V4L2_PIX_FMT_YUYV // 圖片格式 #define COUNT 5 // 緩衝區個數 int main(int argc, char **argv) { unsigned char *datas[COUNT]; // 緩衝區資料地址 int ret, i; int fd; /* 第一步:開啟攝像頭裝置檔案 */ fd = open("/dev/video0", O_RDWR); // 注意檢視攝像頭裝置名 if (-1 == fd)
{ perror("open /dev/video0"); return -1; } /* 第二步:設定捕捉圖片幀格式 */ struct v4l2_format format; format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 操作型別為獲取圖片 format.fmt.pix.width = WIDTH; // 圖片的寬度 format.fmt.pix.height = HEIGHT; // 圖片的高度 format.fmt.pix.pixelformat = FMT; // 圖片格式 ret = ioctl(fd, VIDIOC_S_FMT, &format); // 進行設定(Set) if (-1 == ret) { perror("ioctl VIDIOC_S_FMT"); close(fd); return -2; } /* 第三步:檢查是否設定成功 */ ret = ioctl(fd, VIDIOC_G_FMT, &format); // Get if (-1 == ret) { perror("ioctl VIDIOC_G_FMT"); close(fd); return -3; } if (format.fmt.pix.pixelformat == FMT) { printf("ioctl VIDIOC_S_FMT sucessful\n"); } else { printf("ioctl VIDIOC_S_FMT failed\n"); } /* 第四步:讓攝像頭驅動申請存放影象資料的緩衝區 */ struct v4l2_requestbuffers reqbuf; reqbuf.count = COUNT; // 緩衝區個數 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 緩衝區型別 reqbuf.memory = V4L2_MEMORY_MMAP; // 緩衝區的用途:用於記憶體對映 ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf); if (-1 == ret) { perror("ioctl VIDIOC_REQBUFS"); close(fd); return -4; } /* 第五步:查詢每個緩衝區的資訊,同時進行記憶體對映 */ struct v4l2_buffer buff; buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buff.memory = V4L2_MEMORY_MMAP; for (i = 0; i < COUNT; i++) { buff.index = i; ret = ioctl(fd, VIDIOC_QUERYBUF, &buff); if (-1 == ret) // 操作失敗 { break; } /* 列印緩衝區的長度和偏移量 */ printf("buf[%d]: len = %d offset: %d\n", i, buff.length, buff.m.offset); /* 把每塊緩衝區對映到當前程序來 */ datas[i] = mmap(NULL, buff.length, PROT_READ, MAP_SHARED, fd, buff.m.offset); if (MAP_FAILED == datas[i]) // 對映失敗 { perror("mmap failed"); return -5; } /* 把對映成功的緩衝區加入到攝像頭驅動的影象資料採集佇列裡 */ ret = ioctl(fd, VIDIOC_QBUF, &buff); // Queue if (-1 == ret) { perror("VIDIOC_QBUF"); return -6; } } /* 第六步:啟動採集 */ int on = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 設定啟動標誌位 ret = ioctl(fd, VIDIOC_STREAMON, &on); // 開啟攝像頭流 if (-1 == ret) { perror("ioctl VIDIOC_STREAMON"); return -7; } /* 第七步:讓已經採集好的資料緩衝退出佇列 */ ret = ioctl(fd, VIDIOC_DQBUF, &buff); // Dequeue if (-1 == ret) { perror("ioctl VIDIOC_DQUF"); return -8; } /* 第八步:從退出佇列的緩衝區中獲取資料並儲存到檔案中 */ FILE *fl; fl = fopen("./my.yuyv", "w"); if (NULL == fl) { fprintf(stderr, "open write file failed."); } fwrite(datas[buff.index], buff.bytesused, 1, fl); fclose(fl); // 記得關閉已開啟的檔案 close(fd); // 記得關閉已開啟的裝置 return 0; }