imx6平臺V4L2程式設計學習記錄之初始化(二)
阿新 • • 發佈:2018-12-12
本文記錄的是我自己摸索學習、實現功能的過程,其中可能有些地方理解不正確,還望指出。
根據手冊說明V4L2程式設計支援兩種資料採集方式:記憶體對映和直接讀取。而我目前只實現過通過記憶體對映的方式採集資料,如果有嘗試直接讀取的方式後再記錄。
初始化的流程: 1、開啟USB攝像頭裝置,Linux下外設以“裝置檔案”的形式存在。 2、設定視訊資料的格式,其中包括影象的寬高、視訊的格式,使用的攝像頭不同設定可能有所不同。 3、申請n塊幀緩衝區 4、對映到應用記憶體。
使用: 1、獲取單張影象資料。 2、獲取視訊流儲存為視訊格式,暫時沒幹過這事。
步驟(函式上方的巨集及全域性變數為引數說明)
1、開啟裝置
#define CAMERA_DEVICE "/dev/video0" /* 攝像機裝置路徑 */
static int video_fd; /* 攝像頭裝置檔案描述符 */
/*******************************************************************
** 函式描述: 開啟攝像頭裝置
********************************************************************/
static void open_device ()
{
video_fd = open(CAMERA_DEVICE, O_RDWR, 0);
if (video_fd < 0) {
printf("Open %s failed\n", CAMERA_DEVICE);
}
}
2、獲取及設定視訊格式
static int video_fd; /* 攝像頭裝置檔案描述符 */
static struct v4l2_fmtdesc fmtdesc; /* V4L2的視訊格式描述 */
static struct v4l2_format fmt; /* V4L2的視訊資料格式 */
/*******************************************************************
** 函式描述: 獲取視訊資料格式
********************************************************************/
static void get_data_format()
{
int ret;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(video_fd, VIDIOC_G_FMT, &fmt);
if (ret < 0) {
printf("VIDIOC_G_FMT failed (%d)\n", ret);
return;
}
}
/*******************************************************************
** 函式描述: 設定視訊資料格式
********************************************************************/
static void set_data_format()
{
int ret;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = VIDEO_WIDTH;
fmt.fmt.pix.height = VIDEO_HEIGHT;
fmt.fmt.pix.pixelformat = fmtdesc.pixelformat;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(video_fd, VIDIOC_S_FMT, &fmt);
if (ret < 0) {
printf("VIDIOC_S_FMT failed (%d)\n", ret);
return;
}
}
3、申請幀緩衝區
#define BUFFER_COUNT 3 /* 快取區數量 */
static struct v4l2_requestbuffers reqbuf; /* 初始化記憶體對映的請求快取 */
/*******************************************************************
** 函式描述: 申請V4L2視訊驅動記憶體
********************************************************************/
static void request_buf()
{
int ret;
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.count = BUFFER_COUNT;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(video_fd, VIDIOC_REQBUFS, &reqbuf);
if(ret < 0) {
printf("VIDIOC_REQBUFS failed (%d)\n", ret);
return;
}
}
4、記憶體對映
#define BUFFER_COUNT 3 /* 快取區數量 */
static int video_fd; /* 攝像頭裝置檔案描述符 */
static app_buffer_t app_buffer[BUFFER_COUNT]; /* 應用層緩衝區對映 */
static struct v4l2_buffer buf; /* 緩衝區 */
/*******************************************************************
** 函式描述: 對映記憶體並放置緩衝區
********************************************************************/
static void mmap_map_qbuf()
{
int i, ret;
for (i = 0; i < BUFFER_COUNT; i++)
{
memset(&buf, 0, sizeof(buf));
buf.index = i;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(video_fd, VIDIOC_QUERYBUF, &buf);
if(ret < 0) {
printf("VIDIOC_QUERYBUF (%d) failed (%d)\n", i, ret);
return;
}
app_buffer[i].length = buf.length;
app_buffer[i].start = (char *) mmap(0, buf.length, PROT_READ|PROT_WRITE,
MAP_SHARED, video_fd, buf.m.offset);
if (app_buffer[i].start == MAP_FAILED) {
printf("mmap (%d) failed: %s\n", i, strerror(errno));
return;
}
}
}