1. 程式人生 > >imx6平臺V4L2程式設計學習記錄之初始化(二)

imx6平臺V4L2程式設計學習記錄之初始化(二)

本文記錄的是我自己摸索學習、實現功能的過程,其中可能有些地方理解不正確,還望指出。

根據手冊說明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;
        }
    }
}