性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

Camera | 4.MIPI攝像頭應(yīng)用程序編寫

前面3篇我們講解了camera的基礎(chǔ)概念,MIPI協(xié)議,CSI2,常用命令等,本文帶領(lǐng)大家入門,如何用c語言編寫應(yīng)用程序來操作攝像頭。

Linux下攝像頭驅(qū)動(dòng)都是基于v4l2架構(gòu),要基于該架構(gòu)編寫攝像頭的應(yīng)用程序,必須先要搞清楚什么是v4l2。

1. 什么是v4l2

v4l2是video for Linux 2的縮寫,是一套Linux內(nèi)核視頻設(shè)備的驅(qū)動(dòng)框架,該驅(qū)動(dòng)框架為應(yīng)用層提供一套統(tǒng)一的操作接口(一系列的ioctl)

https://linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/

官網(wǎng)有一個(gè)簡(jiǎn)單的用于抓圖的程序capture.c。

本文后面基于該實(shí)例編寫一個(gè)最簡(jiǎn)單的抓圖程序。

v4l2接口

V4L2 :video for linux 2 ,是 linux ??套標(biāo)準(zhǔn)的視頻驅(qū)動(dòng),讓應(yīng)?層可以像訪問普通?件?樣對(duì)**/dev/videoX** 節(jié)點(diǎn)進(jìn)? open 、 read 、 ioctl 等操作。

V4L2在設(shè)計(jì)時(shí),是要支持很多廣泛的設(shè)備的,它們之中只有一部分在本質(zhì)上是真正的視頻設(shè)備,可以支持多種設(shè)備,它可以有以下幾種接口:

1. video capture interface(捕獲): 視頻采集接口,這種接口應(yīng)用于攝像頭,v4l2在最初設(shè)計(jì)的時(shí)候就是應(yīng)用于這種功能

2. video output interface(輸出): 視頻輸出接口,將靜止圖像或圖像序列編碼為模擬視頻信號(hào),通過此接口,應(yīng)用程序可以控制編碼過程并將圖像從用戶空間移動(dòng)到驅(qū)動(dòng)程序

3. video overlay interface(預(yù)覽): 視頻直接傳輸接口,可以將采集到的視頻數(shù)據(jù)直接傳輸?shù)斤@示設(shè)備,不需要cpu參與,這種方式的顯示圖像的效率比其他方式高得多

本文主要講解如何使用capture功能。

2. 截取圖象的3種方法

1)用mmap(內(nèi)存映射)方式截取視頻

mmap( )系統(tǒng)調(diào)用使得進(jìn)程之間通過映射同一個(gè)普通文件實(shí)現(xiàn)共享內(nèi)存。普通文件被映射到進(jìn)程地址空間后,進(jìn)程可以向訪問普通內(nèi)存一樣對(duì)文件進(jìn)行訪問,不必再調(diào)用read(),write()等操作。

兩個(gè)不同進(jìn)程A、B共享內(nèi)存的意思是,同一塊物理內(nèi)存被映射到進(jìn)程A、B各自的進(jìn)程地址空間。進(jìn)程A可以即時(shí)看到進(jìn)程B對(duì)共享內(nèi)存中數(shù)據(jù)的更新,反之亦然

采用共享內(nèi)存通信的一個(gè)顯而易見的好處是效率高,因?yàn)檫M(jìn)程可以直接讀寫內(nèi)存,而不需要任何數(shù)據(jù)的拷貝

*(1)設(shè)置picture的屬性

*(2) 初始化video_mbuf,以得到所映射的buffer的信息

ioctl(vd->fd, VIDIOCGMBUF, &(vd->mbuf))

*(3)可以修改video_mmap和幀狀態(tài)的當(dāng)前設(shè)置

 Eg. vd->mmap.format = VIDEO_PALETTE_RGB24 vd->framestat[0] = vd->framestat[1] = 0; vd->frame = 0;

*(4)將mmap與video_mbuf綁定

void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset )len //映射到調(diào)用進(jìn)程地址空間的字節(jié)數(shù),它從被映射文件開頭offset個(gè)字節(jié)開始算起Prot //指定共享內(nèi)存的訪問權(quán)限 PROT_READ(可讀), PROT_WRITE (可寫), PROT_EXEC (可執(zhí)行)flags // MAP_SHARED MAP_PRIVATE中必選一個(gè) // MAP_ FIXED不推薦使用addr //共內(nèi)存享的起始地址,一般設(shè)0,表示由系統(tǒng)分配Mmap( ) 返回值是系統(tǒng)實(shí)際分配的起始地址if((vd->map = (unsigned char*)mmap(0, vd->mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, vd->fd, 0)) < 0){ perror("v4l_mmap mmap:"); return -1;}

*(5)Mmap方式下真正做視頻截取的 VIDIOCMCAPTURE

ioctl(vd->fd, VIDIOCMCAPTURE, &(vd->mmap)) ;若調(diào)用成功,開始一幀的截取,是非阻塞的,是否截取完畢留給VIDIOCSYNC來判斷

*(6)調(diào)用VIDIOCSYNC等待一幀截取結(jié)束

if(ioctl(vd->fd, VIDIOCSYNC, &frame) < 0){ perror("v4l_sync:VIDIOCSYNC"); return -1;}

若成功,表明一幀截取已完成。可以開始做下一次 VIDIOCMCAPTURE

frame是當(dāng)前截取的幀的序號(hào)。

關(guān)于雙緩沖:

video_bmuf bmuf.frames = 2;一幀被處理時(shí)可以采集另一幀int frame; //當(dāng)前采集的是哪一幀int framestat[2]; //幀的狀態(tài) 沒開始采集|等待采集結(jié)束幀的地址由vd->map + vd->mbuf.offsets[vd->frame]得到采集工作結(jié)束后調(diào)用munmap取消綁定munmap(vd->map, vd->mbuf.size)

2)視頻截取的第二種方法:直接讀設(shè)備

關(guān)于緩沖大小,圖象等的屬性須由使用者事先設(shè)置

int read (要訪問的文件描述符;指向要讀寫的信息的指針;應(yīng)該讀寫的字符數(shù)); 返回值為實(shí)際讀寫的字符數(shù)

實(shí)例:

int len ;unsigned char *vd->map= (unsigned char *) malloc(vd->capability.maxwidth*vd->capability.maxheight );len = read(vd->fd,vd->map, vd->capability.maxwidth*vd->capability.maxheight*3 );

3)用戶指針

3. v4l2 設(shè)備操作說明

對(duì)設(shè)備的大多數(shù)操作都是應(yīng)用層通過調(diào)用ioctl實(shí)現(xiàn)的, 不同的命令需要操作不同的文件設(shè)備節(jié)點(diǎn), 具體的需要根據(jù)拓?fù)浣Y(jié)構(gòu)來決定操作那個(gè)字符設(shè)備。

以下是瑞芯微rk3568平臺(tái)的攝像頭拓?fù)鋱D,移植了ov13850攝像頭。

在這里插入圖片描述

  1. 其中攝像頭對(duì)應(yīng)的此設(shè)備為: /dev/v4l-subdev3
  2. 應(yīng)用層要配置通用配置、或者獲取圖像,需要操作設(shè)備 /dev/video0
  3. 有一些攝像頭專用的命令,我們可以操作 /dev/v4l-subdev3

ov13850攝像頭驅(qū)動(dòng)中注冊(cè)了一些命令對(duì)應(yīng)的回調(diào)函數(shù):

這些回調(diào)函數(shù)都注冊(cè)到了V4L2架構(gòu)中,我們可以通過字符設(shè)備 /dev/videox,、/dev/v4l-subdevx 直接或者間接訪問到這些回調(diào)函數(shù)。

V4L2定義了一些通用的命令,操作字符設(shè)備 /dev/videox即可調(diào)用,命令具體定義如下:

kernel\drivers\media\v4l2-core\v4l2-ioctl.c

可以通過數(shù)組名+命令對(duì)應(yīng)的數(shù)值方式訪問對(duì)應(yīng)的回調(diào)函數(shù)。 該數(shù)組定義如下:

struct v4l2_ioctl_info { unsigned int ioctl; u32 flags; const char * const name; int (*func)(const struct v4l2_ioctl_ops *ops, struct file *file,      void *fh, void *p); void (*debug)(const void *arg, bool write_only);};

字符設(shè)備**/dev/v4l-subdevx**支持的命令如下:

@kernel\drivers\media\v4l2-core\v4l2-subdev.cstatic long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg){  …… switch (cmd) { case VIDIOC_QUERYCTRL:  …… case VIDIOC_QUERY_EXT_CTRL:  …… case VIDIOC_QUERYMENU:  …… case VIDIOC_G_CTRL:  …… case VIDIOC_S_CTRL:  …… case VIDIOC_G_EXT_CTRLS:  …… case VIDIOC_S_EXT_CTRLS:  …… case VIDIOC_TRY_EXT_CTRLS:  …… case VIDIOC_DQEVENT:  …… case VIDIOC_SUBSCRIBE_EVENT:  return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); case VIDIOC_UNSUBSCRIBE_EVENT:  return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);#ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER:  …… case VIDIOC_DBG_S_REGISTER:  …… case VIDIOC_DBG_G_CHIP_INFO:  ……#endif case VIDIOC_LOG_STATUS: {  ……#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) case VIDIOC_SUBDEV_G_FMT: {  …… case VIDIOC_SUBDEV_S_FMT: {  …… case VIDIOC_SUBDEV_G_CROP: {  …… } case VIDIOC_SUBDEV_S_CROP: {  …… } case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {  …… } case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {  …… } case VIDIOC_SUBDEV_G_FRAME_INTERVAL: {  …… } case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {  …… } case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {  …… } case VIDIOC_SUBDEV_G_SELECTION: {  …… } case VIDIOC_SUBDEV_S_SELECTION: {  …… } case VIDIOC_G_EDID: {  …… } case VIDIOC_S_EDID: {  …… } case VIDIOC_SUBDEV_DV_TIMINGS_CAP: {  …… } case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: {  …… } case VIDIOC_SUBDEV_QUERY_DV_TIMINGS:  return v4l2_subdev_call(sd, video, query_dv_timings, arg); case VIDIOC_SUBDEV_G_DV_TIMINGS:  return v4l2_subdev_call(sd, video, g_dv_timings, arg); case VIDIOC_SUBDEV_S_DV_TIMINGS:  return v4l2_subdev_call(sd, video, s_dv_timings, arg); case VIDIOC_G_INPUT:  return v4l2_subdev_call(sd, video, g_input_status, arg); case VIDIOC_SUBDEV_G_STD:  return v4l2_subdev_call(sd, video, g_std, arg); case VIDIOC_SUBDEV_S_STD: {  v4l2_std_id *std = arg;  return v4l2_subdev_call(sd, video, s_std, *std); } case VIDIOC_SUBDEV_ENUMSTD: {  …… } case VIDIOC_SUBDEV_QUERYSTD:  …… } return 0;}

這其中有一些命令是和字符設(shè)備 /dev/videox 的命令重復(fù)的,

比如:VIDIOC_S_CTRL,

VIDIOC_SUBDEV_ 開頭的則是subdev私有的。

關(guān)于這些命令和回調(diào)函數(shù),后續(xù)會(huì)再深入講解,對(duì)于應(yīng)用程序開發(fā),

我們首先搞清楚設(shè)備的拓?fù)浣Y(jié)構(gòu),然后需要知道我們要執(zhí)行的命令功能以及對(duì)應(yīng)的是哪一個(gè)設(shè)備節(jié)點(diǎn)即可。

4. ioctl命令說明

參見結(jié)構(gòu)體見

 /usr/include/linux/videodev2.h

1)Querying Capabilities

查詢?cè)O(shè)備的功能

由于V4L2涵蓋了各種各樣的設(shè)備,因此并非API的所有方面都適用于所有類型的設(shè)備,在使用v4l2設(shè)備時(shí),必須調(diào)用此API,獲得設(shè)備支持的功能(capture、output、overlay…)

ID 描述 VIDIOC_QUERYCAP 查詢?cè)O(shè)備功能

struct v4l2_capability{ u8 driver[16]; // 驅(qū)動(dòng)名字 u8 card[32]; // 設(shè)備名字 u8 bus_info[32]; // 設(shè)備在系統(tǒng)中的位置 u32 version; // 驅(qū)動(dòng)版本號(hào) u32 capabilities; // 設(shè)備支持的操作 u32 reserved[4]; // 保留字段};

capabilities 常用值:

V4L2_CAP_VIDEO_CAPTURE // 是否支持圖像獲取

2)Application Priority

應(yīng)用優(yōu)先級(jí)

當(dāng)多個(gè)應(yīng)用程序共享設(shè)備時(shí),可能需要為它們分配不同的優(yōu)先級(jí)。視頻錄制應(yīng)用程序可以例如阻止其他應(yīng)用程序改變視頻控制或切換當(dāng)前的電視頻道。

另一個(gè)目標(biāo)是允許在后臺(tái)工作的低優(yōu)先級(jí)應(yīng)用程序,這些應(yīng)用程序可以被用戶控制的應(yīng)用程序搶占,并在以后自動(dòng)重新獲得對(duì)設(shè)備的控制

ID 描述 VIDIOC_G_PRIORITY 獲取優(yōu)先級(jí) VIDIOC_S_PRIORITY 設(shè)置優(yōu)先級(jí)

3)Device Inputs and Outputs

輸入和輸出設(shè)備

ID 描述 VIDIOC_ENUMINPUT 枚舉視頻輸入設(shè)備 VIDIOC_G_INPUT 獲取當(dāng)前的視頻輸入設(shè)備 VIDIOC_S_INPUT 設(shè)置視頻輸入設(shè)備 VIDIOC_ENUMOUTPUT 枚舉視頻輸出設(shè)備 VIDIOC_G_OUTPUT 獲取當(dāng)前視頻輸出設(shè)備 VIDIOC_S_OUTPUT 設(shè)置視頻輸出設(shè)備 VIDIOC_ENUMAUDIO 枚舉音頻輸入設(shè)備 VIDIOC_G_AUDIO 獲取當(dāng)前音頻輸入設(shè)備 VIDIOC_S_AUDIO 設(shè)置音頻輸入設(shè)備 VIDIOC_ENUMAUDOUT 枚舉音頻輸出設(shè)備 VIDIOC_G_OUTPUT 獲取音頻輸出設(shè)備 VIDIOC_S_AUDOUT 設(shè)置音頻輸出設(shè)備

VIDIOC_G_INPUT 和 VIDIOC_S_INPUT 用來查詢和選則當(dāng)前的 input,一個(gè) video 設(shè)備 節(jié)點(diǎn)可能對(duì)應(yīng)多個(gè)視頻源,比如 saf7113 可以最多支持四路 cvbs 輸入,如果上層想在四 個(gè)cvbs視頻輸入間切換,那么就要調(diào)用 ioctl(fd, VIDIOC_S_INPUT, &input) 來切換。

VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回當(dāng)前的 video input和output的index.

struct v4l2_input { __u32 index; /* Which input */ __u8 name[32]; /* Label */ __u32 type; /* Type of input */ __u32 audioset; /* Associated audios (bitfield) */ __u32 tuner; /* Associated tuner */ v4l2_std_id std; __u32 status; __u32 reserved[4];};

我們可以通過VIDIOC_ENUMINPUT and VIDIOC_ENUMOUTPUT 分別列舉一個(gè)input或者 output的信息,我們使用一個(gè)v4l2_input結(jié)構(gòu)體來存放查詢結(jié)果,這個(gè)結(jié)構(gòu)體中有一個(gè) index域用來指定你索要查詢的是第幾個(gè)input/ouput,如果你所查詢的這個(gè)input是當(dāng)前正 在使用的,那么在v4l2_input還會(huì)包含一些當(dāng)前的狀態(tài)信息,如果所 查詢的input/output 不存在,那么回返回EINVAL錯(cuò)誤,所以,我們通過循環(huán)查找,直到返回錯(cuò)誤來遍歷所有的 input/output. VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回當(dāng)前的video input和output 的index.

4) Video Standards

視頻標(biāo)準(zhǔn)

ID 描述 VIDIOC_ENUMSTD 枚舉設(shè)備支持的所有標(biāo)準(zhǔn) VIDIOC_G_STD 獲取當(dāng)前正在使用的標(biāo)準(zhǔn) VIDIOC_S_STD 設(shè)置視頻標(biāo)準(zhǔn) VIDIOC_QUERYSTD 有的設(shè)備支持自動(dòng)偵測(cè)輸入源的視頻標(biāo)準(zhǔn),此ioctl獲取檢測(cè)到的標(biāo)準(zhǔn)。

typedef u64 v4l2_std_id; struct v4l2_standard { u32 index; v4l2_std_id id; u8 name[24]; struct v4l2_fract frameperiod; /* Frames, not fields */ u32 framelines; u32 reserved[4];};

當(dāng)然世界上現(xiàn)在有多個(gè)視頻標(biāo)準(zhǔn),如NTSC和PAL,他們又細(xì)分為好多種,那么我們的設(shè) 備輸入/輸出究竟支持什么樣的標(biāo)準(zhǔn)呢?我們的當(dāng)前在使用的輸入和輸出正在使用的是哪 個(gè)標(biāo)準(zhǔn)呢?我們?cè)趺丛O(shè)置我們的某個(gè)輸入輸出使用的標(biāo)準(zhǔn)呢?這都是有方法的。

查詢我們的輸入支持什么標(biāo)準(zhǔn),首先就得找到當(dāng)前的這個(gè)輸入的index,然后查出它的 屬性,在其屬性里面可以得到該輸入所支持的標(biāo)準(zhǔn),將它所支持的各個(gè)標(biāo)準(zhǔn)與所有的標(biāo)準(zhǔn) 的信息進(jìn)行比較,就可以獲知所支持的各個(gè)標(biāo)準(zhǔn)的屬性。一個(gè)輸入所支持的標(biāo)準(zhǔn)應(yīng)該是一 個(gè)集合,而這個(gè)集合是用bit與的方式用一個(gè)64位數(shù)字表示。因此我們所查到的是一個(gè)數(shù)字。

5) Camera Control Reference

控制屬性

ID 描述 VIDIOC_QUERYCTRL 查詢指定的control詳細(xì)信息 VIDIOC_QUERYMENU 查詢menu VIDIOC_G_CTRL 獲取設(shè)備指定control的當(dāng)前信息 VIDIOC_S_CTRL 設(shè)置設(shè)備指定的control

6) Image Format

圖像格式

圖像由多種格式Y(jié)UV和RGB還有壓縮格式等等,其中每種格式又分有多種格式,比如RGB:RGB565、RGB888…

所以在使用設(shè)備時(shí),需要對(duì)格式進(jìn)行設(shè)置

ID 描述 VIDIOC_ENUM_FMT 枚舉設(shè)備支持的圖像格式 VIDIOC_G_FMT 獲取當(dāng)前設(shè)備的圖像格式 VIDIOC_S_FMT 設(shè)置圖像格式 VIDIOC_TRY_FMT 測(cè)試設(shè)備是否支持此格式

查詢并顯示所有支持的格式:VIDIOC_ENUM_FMT

struct v4l2_fmtdesc{ u32 index; // 要查詢的格式序號(hào),應(yīng)用程序設(shè)置 enum v4l2_buf_type type; // 幀類型,應(yīng)用程序設(shè)置 u32 flags; // 是否為壓縮格式 u8 description[32]; // 格式名稱 u32 pixelformat; // 格式 u32 reserved[4]; // 保留};

查看或設(shè)置當(dāng)前格式: VIDIOC_G_FMT, VIDIOC_S_FMT

struct v4l2_format{ enum v4l2_buf_type type; // 幀類型,應(yīng)用程序設(shè)置 union fmt {  struct v4l2_pix_format pix; // 視頻設(shè)備使用   struct v4l2_window win;   struct v4l2_vbi_format vbi;   struct v4l2_sliced_vbi_format sliced;   u8 raw_data[200];  };};struct v4l2_pix_format{ u32 width; // 幀寬,單位像素  u32 height; // 幀高,單位像素  u32 pixelformat; // 幀格式  enum v4l2_field field;  u32 bytesperline;  u32 sizeimage;  enum v4l2_colorspace colorspace;  u32 priv;};

7) Cropping, composing and scaling

圖像裁剪、插入與縮放

ID 描述 VIDIOC_CROPCAP 獲取圖像裁剪縮放能力 VIDIOC_G_CROP 獲取當(dāng)前的裁剪矩陣 VIDIOC_S_CROP 設(shè)置裁剪矩陣

Cropping 和 scaling 主要指的是圖像的取景范圍及圖片的比例縮放的支持。Crop 就 是把得到的數(shù)據(jù)作一定的裁剪和伸縮,裁剪可以只取樣我們可以得到的圖像大小的一部分, 剪裁的主要參數(shù)是位置、長度、寬度。而 scale 的設(shè)置是通過 VIDIOC_G_FMT 和 VIDIOC_S_FMT 來獲得和設(shè)置當(dāng)前的 image 的長度,寬度來實(shí)現(xiàn)的。 看下圖:

我們可以假設(shè) bounds 是 sensor 最大能捕捉到的圖像范圍,而 defrect 是設(shè)備默認(rèn) 的最大取樣范圍,這個(gè)可以通過 VIDIOC_CROPCAP 的 ioctl 來獲得設(shè)備的 crap 相關(guān)的屬 性 v4l2_cropcap,其中的 bounds 就是這個(gè) bounds,其實(shí)就是上限。每個(gè)設(shè)備都有個(gè)默 認(rèn)的取樣范圍,就是 defrect,就是 default rect 的意思,它比 bounds 要小一些。這 個(gè)范圍也是通過 VIDIOC_CROPCAP 的 ioctl 來獲得的 v4l2_cropcap 結(jié)構(gòu)中的 defrect 來表示的,我們可以通過 VIDIOC_G_CROP 和 VIDIOC_S_CROP 來獲取和設(shè)置設(shè)備當(dāng)前的 crop 設(shè)置。

設(shè)置設(shè)備捕捉能力的參數(shù)

struct v4l2_cropcap{ enum v4l2_buf_type type; // 數(shù)據(jù)流的類型,應(yīng)用程序設(shè)置 struct v4l2_rect bounds; // 這是 camera 的鏡頭能捕捉到的窗口大小的局限 struct v4l2_rect defrect; // 定義默認(rèn)窗口大小,包括起點(diǎn)位置及長,寬的大小,大小以像素為單位 struct v4l2_fract pixelaspect; // 定義了圖片的寬高比};

設(shè)置窗口取景參數(shù) VIDIOC_G_CROP 和 VIDIOC_S_CROP

struct v4l2_crop{ enum v4l2_buf_type type;// 應(yīng)用程序設(shè)置 struct v4l2_rect c;}

8) buf Input/Output

數(shù)據(jù)的輸入和輸出

內(nèi)核中使用緩存隊(duì)列對(duì)圖像數(shù)據(jù)進(jìn)行管理,用戶空間獲取圖像數(shù)據(jù)有兩種方式,一種是通過read、write方式讀取內(nèi)核空間的緩存,一種是將內(nèi)核空間的緩存映射到用戶空間,即streaming。在操作v4l2設(shè)備時(shí),通過VIDIOC_QUERYCAP獲取設(shè)備支持哪種方式。 streaming就是在內(nèi)核空間中維護(hù)一個(gè)緩存隊(duì)列,然后將內(nèi)存映射到用戶空間,應(yīng)用讀取圖像數(shù)據(jù)就是一個(gè)不斷地出隊(duì)列和入隊(duì)列的過程,如下圖所示

ID 描述 VIDIOC_REQBUFS 申請(qǐng)緩存 VIDIOC_QUERYBUF 獲取緩存信息 VIDIOC_QBUF 將緩存放入隊(duì)列中 VIDIOC_DQBUF 將緩存從隊(duì)列中取出

1. 向設(shè)備申請(qǐng)緩沖區(qū) VIDIOC_REQBUFS

struct v4l2_requestbuffers{ u32 count; // 緩沖區(qū)內(nèi)緩沖幀的數(shù)目 enum v4l2_buf_type type; // 緩沖幀數(shù)據(jù)格式 enum v4l2_memory memory; // 區(qū)別是內(nèi)存映射還是用戶指針方式 u32 reserved[2];};enum v4l2_memoy{ V4L2_MEMORY_MMAP, V4L2_MEMORY_USERPTR};

獲取緩沖幀的地址,長度:VIDIOC_QUERYBUF

struct v4l2_buffer{ u32 index; //buffer 序號(hào) enum v4l2_buf_type type; //buffer 類型 u32 byteused; //buffer 中已使用的字節(jié)數(shù) u32 flags; // 區(qū)分是MMAP 還是USERPTR  enum v4l2_field field;  struct timeval timestamp; // 獲取第一個(gè)字節(jié)時(shí)的系統(tǒng)時(shí)間  struct v4l2_timecode timecode;  u32 sequence; // 隊(duì)列中的序號(hào)  enum v4l2_memory memory; //IO 方式,被應(yīng)用程序設(shè)置  union m  {   u32 offset; // 緩沖幀地址,只對(duì)MMAP 有效   unsigned long userptr;  };  u32 length; // 緩沖幀長度  u32 input;  u32 reserved;};

2. 內(nèi)存映射MMAP 及定義一個(gè)結(jié)構(gòu)體來映射每個(gè)緩沖幀。 相關(guān)結(jié)構(gòu)體:

struct buffer{ void* start; unsigned int length;}*buffers;

相關(guān)函數(shù):

#include <sys/mman.h>void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)參數(shù):addr 映射起始地址,一般為NULL ,讓內(nèi)核自動(dòng)選擇length 被映射內(nèi)存塊的長度prot 標(biāo)志映射后能否被讀寫,其值為PROT_EXEC,PROT_READ,PROT_WRITE, PROT_NONEflags 確定此內(nèi)存映射能否被其他進(jìn)程共享,MAP_SHARED,MAP_PRIVATEfd,offset, 確定被映射的內(nèi)存地址 返回成功映射后的地址,不成功返回MAP_FAILED ((void*)-1)

3.將所有的緩存放入隊(duì)列

struct v4l2_buffer v4l2_buffer;for(i = 0; i < nr_bufs; i++){ memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer)); v4l2_buffer.index = i; //想要放入隊(duì)列的緩存 v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; v4l2_buffer.memory = V4L2_MEMORY_MMAP;     ret = ioctl(fd, VIDIOC_QBUF, &v4l2_buffer);    if(ret < 0)    {        printf("Unable to queue buffer.\n");        return -1;    }}

9)啟動(dòng) 或 停止數(shù)據(jù)流

VIDIOC_STREAMON, VIDIOC_STREAMOFF

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;ioctl (fd, VIDIOC_STREAMON, &type);

5. v4l2設(shè)備抓幀程序編寫

v4l2設(shè)備的命令比較多,其實(shí)常用的并不是很多,下面通過一個(gè)實(shí)例來詳細(xì)講解,如何操作v4l2設(shè)備。

1)設(shè)備配置

本例,將常用的攝像頭配置參數(shù)等裝成結(jié)構(gòu)體:

struct v4l2_dev{    int fd;   //videoO對(duì)應(yīng)的設(shè)備描述符    int sub_fd;     const char *path; //字符設(shè)備 /dev/videoO    const char *name; //攝像頭名稱    const char *subdev_path;//字符設(shè)備 /dev/v4l-subdev3    const char *out_type; //輸出圖像格式    enum v4l2_buf_type buf_type;//緩存類型    int format; //像素格式    int width;  //圖像寬度    int height; //圖像高度    unsigned int req_count; //緩存數(shù)量    enum v4l2_memory memory_type; //讀取圖像的方法,DMA還是MMAP    struct buffer *buffers; //緩沖區(qū)    unsigned long int timestamp;//時(shí)長度    int data_len;//圖像數(shù)據(jù)長度    unsigned char *out_data;//圖像數(shù)據(jù)};

本例填寫的攝像頭ov13850的配置信息如下:

struct v4l2_dev ov13850 = {    .fd = -1,    .sub_fd = -1,    .path = "/dev/video0",    .name = "ov13850",    .subdev_path = "/dev/v4l-subdev3",    .out_type = "nv12",    .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,    .format = V4L2_PIX_FMT_NV12,    .width = 800,    .height = 600,    .req_count = 4,    .memory_type = V4L2_MEMORY_MMAP,    .buffers = NULL,    .timestamp = 0,    .data_len = 0,    .out_data = NULL,};

2)v4l2設(shè)備一般操作流程(抓幀)

v4l2設(shè)備一般操作流程如下圖所示:

各功能對(duì)應(yīng)的ioctrl命令如下:

測(cè)試程序一口君已經(jīng)上傳到gitee:

https://gitee.com/yikoulinux/v4l2-appgit clone git@gitee.com:yikoulinux/v4l2-app.git

歡迎各位老鐵star。

3)程序執(zhí)行l(wèi)og

以下是在rk3568實(shí)際測(cè)試的log。

rk3568_r:/ # /data/capture                                       
/data/capture                                                    
Open /dev/video0 succeed - 3                                     
                                                                 
Open /dev/v4l-subdev3 succeed                                    
                                                                 
------- VIDIOC_QUERYCAP ----                                     
  driver: rkisp_v5                                               
  card: rkisp_mainpath                                           
  bus_info: platform:rkisp-vir0                                  
  version: 1.8.0                                                 
  capabilities: 84201000                                         
        Video Capture Mplane                                     
        Streaming                                                
                                                                 
VIDIOC_S_FMT succeed!                                            
width 800, height 600, size 720000, bytesperline 0, format NV12  
                                                                 
VIDIOC_REQBUFS succeed!                                          
                                                                 
Memory map succeed!                                              
                                                                 
VIDIOC_QBUF succeed!                                             
                                                                 
VIDIOC_STREAMON succeed!                                         
                                                                 
image: sequence = 0, timestamp = 1115378780                      
image: sequence = 1, timestamp = 1115511890                      
image: sequence = 2, timestamp = 1115645004                      
image: sequence = 3, timestamp = 1115778130                      
image: sequence = 4, timestamp = 1115911257                      
image: sequence = 5, timestamp = 1116044365                      
image: sequence = 6, timestamp = 1116177498                      
image: sequence = 7, timestamp = 1116310610                      
image: sequence = 8, timestamp = 1116443739                      
image: sequence = 9, timestamp = 1116576844                      
Save one frame to /data/ov13850.nv12 succeed!                    
                                                                 
VIDIOC_STREAMOFF succeed! 

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場(chǎng)。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 2
收藏 1
關(guān)注 181
成為作者 賺取收益
全部留言
0/200
成為第一個(gè)和作者交流的人吧