前面3篇我們講解了camera的基礎概念,MIPI協議,CSI2,常用命令等,本文帶領大家入門,如何用c語言編寫應用程式來操作攝像頭。 Linux下攝像頭驅動都是基於v4l2架構,要基於該架構編寫攝像頭的應用程式,必須先要搞清楚什麼是v4l2。 1. 什麼是v4l2 v4l2是video for L ...
前面3篇我們講解了camera的基礎概念,MIPI協議,CSI2,常用命令等,本文帶領大家入門,如何用c語言編寫應用程式來操作攝像頭。
Linux下攝像頭驅動都是基於v4l2架構,要基於該架構編寫攝像頭的應用程式,必須先要搞清楚什麼是v4l2。
1. 什麼是v4l2
v4l2是video for Linux 2的縮寫,是一套Linux內核視頻設備的驅動框架,該驅動框架為應用層提供一套統一的操作介面(一系列的ioctl)
https://linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/
官網有一個簡單的用於抓圖的程式capture.c。
本文後面基於該實例編寫一個最簡單的抓圖程式。
v4l2介面
V4L2 :video for linux 2 ,是 linux ⾥⼀套標準的視頻驅動,讓應⽤層可以像訪問普通⽂件⼀樣對/dev/videoX 節點進⾏ open 、 read 、 ioctl 等操作。
V4L2在設計時,是要支持很多廣泛的設備的,它們之中只有一部分在本質上是真正的視頻設備,可以支持多種設備,它可以有以下幾種介面:
1. video capture interface(捕獲):
視頻採集介面,這種介面應用於攝像頭,v4l2在最初設計的時候就是應用於這種功能
2. video output interface(輸出):
視頻輸出介面,將靜止圖像或圖像序列編碼為模擬視頻信號,通過此介面,應用程式可以控制編碼過程並將圖像從用戶空間移動到驅動程式
3. video overlay interface(預覽):
視頻直接傳輸介面,可以將採集到的視頻數據直接傳輸到顯示設備,不需要cpu參與,這種方式的顯示圖像的效率比其他方式高得多
本文主要講解如何使用capture功能。
2. 截取圖象的3種方法
1)用mmap(記憶體映射)方式截取視頻
mmap( )系統調用使得進程之間通過映射同一個普通文件實現共用記憶體。普通文件被映射到進程地址空間後,進程可以向訪問普通記憶體一樣對文件進行訪問,不必再調用read(),write()等操作。
兩個不同進程A、B共用記憶體的意思是,同一塊物理記憶體被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共用記憶體中數據的更新,反之亦然
採用共用記憶體通信的一個顯而易見的好處是效率高,因為進程可以直接讀寫記憶體,而不需要任何數據的拷貝
*(1)設置picture的屬性
*(2) 初始化video_mbuf,以得到所映射的buffer的信息
ioctl(vd->fd, VIDIOCGMBUF, &(vd->mbuf))
*(3)可以修改video_mmap和幀狀態的當前設置
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 //映射到調用進程地址空間的位元組數,它從被映射文件開頭offset個位元組開始算起
Prot //指定共用記憶體的訪問許可權 PROT_READ(可讀), PROT_WRITE (可寫), PROT_EXEC (可執行)
flags // MAP_SHARED MAP_PRIVATE中必選一個 // MAP_ FIXED不推薦使用addr //共記憶體享的起始地址,一般設0,表示由系統分配
Mmap( ) 返回值是系統實際分配的起始地址
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)) ;
若調用成功,開始一幀的截取,是非阻塞的,
是否截取完畢留給VIDIOCSYNC來判斷
*(6)調用VIDIOCSYNC等待一幀截取結束
if(ioctl(vd->fd, VIDIOCSYNC, &frame) < 0)
{
perror("v4l_sync:VIDIOCSYNC");
return -1;
}
若成功,表明一幀截取已完成。可以開始做下一次 VIDIOCMCAPTURE
frame是當前截取的幀的序號。
關於雙緩衝:
video_bmuf bmuf.frames = 2;
一幀被處理時可以採集另一幀
int frame; //當前採集的是哪一幀
int framestat[2]; //幀的狀態 沒開始採集|等待採集結束
幀的地址由vd->map + vd->mbuf.offsets[vd->frame]得到
採集工作結束後調用munmap取消綁定
munmap(vd->map, vd->mbuf.size)
2)視頻截取的第二種方法:直接讀設備
關於緩衝大小,圖象等的屬性須由使用者事先設置
int read (要訪問的文件描述符;指向要讀寫的信息的指針;應該讀寫的字元數);
返回值為實際讀寫的字元數
實例:
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 設備操作說明
對設備的大多數操作都是應用層通過調用ioctl實現的,
不同的命令需要操作不同的文件設備節點,
具體的需要根據拓撲結構來決定操作那個字元設備。
以下是瑞芯微rk3568平臺的攝像頭拓撲圖,移植了ov13850攝像頭。
- 其中攝像頭對應的此設備為: /dev/v4l-subdev3
- 應用層要配置通用配置、或者獲取圖像,需要操作設備 /dev/video0
- 有一些攝像頭專用的命令,我們可以操作 /dev/v4l-subdev3
ov13850攝像頭驅動中註冊了一些命令對應的回調函數:
這些回調函數都註冊到了V4L2架構中,我們可以通過字元設備 /dev/videox,、/dev/v4l-subdevx 直接或者間接訪問到這些回調函數。
V4L2定義了一些通用的命令,操作字元設備 /dev/videox即可調用,命令具體定義如下:
kernel\drivers\media\v4l2-core\v4l2-ioctl.c
可以通過數組名+命令對應的數值方式訪問對應的回調函數。
該數組定義如下:
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);
};
字元設備/dev/v4l-subdevx支持的命令如下:
@kernel\drivers\media\v4l2-core\v4l2-subdev.c
static 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;
}
這其中有一些命令是和字元設備 /dev/videox 的命令重覆的,
比如:VIDIOC_S_CTRL,
VIDIOC_SUBDEV_ 開頭的則是subdev私有的。
關於這些命令和回調函數,後續會再深入講解,對於應用程式開發,
我們首先搞清楚設備的拓撲結構,然後需要知道我們要執行的命令功能以及對應的是哪一個設備節點即可。
4. ioctl命令說明
參見結構體見
/usr/include/linux/videodev2.h
1)Querying Capabilities
查詢設備的功能
由於V4L2涵蓋了各種各樣的設備,因此並非API的所有方面都適用於所有類型的設備,在使用v4l2設備時,必須調用此API,獲得設備支持的功能(capture、output、overlay…)
ID | 描述 |
---|---|
VIDIOC_QUERYCAP | 查詢設備功能 |
struct v4l2_capability
{
u8 driver[16]; // 驅動名字
u8 card[32]; // 設備名字
u8 bus_info[32]; // 設備在系統中的位置
u32 version; // 驅動版本號
u32 capabilities; // 設備支持的操作
u32 reserved[4]; // 保留欄位
};
capabilities 常用值:
V4L2_CAP_VIDEO_CAPTURE // 是否支持圖像獲取
2)Application Priority
應用優先順序
當多個應用程式共用設備時,可能需要為它們分配不同的優先順序。視頻錄製應用程式可以例如阻止其他應用程式改變視頻控制或切換當前的電視頻道。
另一個目標是允許在後臺工作的低優先順序應用程式,這些應用程式可以被用戶控制的應用程式搶占,併在以後自動重新獲得對設備的控制
ID | 描述 |
---|---|
VIDIOC_G_PRIORITY | 獲取優先順序 |
VIDIOC_S_PRIORITY | 設置優先順序 |
3)Device Inputs and Outputs
輸入和輸出設備
ID | 描述 |
---|---|
VIDIOC_ENUMINPUT | 枚舉視頻輸入設備 |
VIDIOC_G_INPUT | 獲取當前的視頻輸入設備 |
VIDIOC_S_INPUT | 設置視頻輸入設備 |
VIDIOC_ENUMOUTPUT | 枚舉視頻輸出設備 |
VIDIOC_G_OUTPUT | 獲取當前視頻輸出設備 |
VIDIOC_S_OUTPUT | 設置視頻輸出設備 |
VIDIOC_ENUMAUDIO | 枚舉音頻輸入設備 |
VIDIOC_G_AUDIO | 獲取當前音頻輸入設備 |
VIDIOC_S_AUDIO | 設置音頻輸入設備 |
VIDIOC_ENUMAUDOUT | 枚舉音頻輸出設備 |
VIDIOC_G_OUTPUT | 獲取音頻輸出設備 |
VIDIOC_S_AUDOUT | 設置音頻輸出設備 |
VIDIOC_G_INPUT 和 VIDIOC_S_INPUT 用來查詢和選則當前的 input,一個 video 設備 節點可能對應多個視頻源,比如 saf7113 可以最多支持四路 cvbs 輸入,如果上層想在四 個cvbs視頻輸入間切換,那麼就要調用 ioctl(fd, VIDIOC_S_INPUT, &input) 來切換。
VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回當前的 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 分別列舉一個input或者 output的信息,我們使用一個v4l2_input結構體來存放查詢結果,這個結構體中有一個 index域用來指定你索要查詢的是第幾個input/ouput,如果你所查詢的這個input是當前正 在使用的,那麼在v4l2_input還會包含一些當前的狀態信息,如果所 查詢的input/output 不存在,那麼回返回EINVAL錯誤,所以,我們通過迴圈查找,直到返回錯誤來遍歷所有的 input/output. VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回當前的video input和output 的index.
4) Video Standards
視頻標準
ID | 描述 |
---|---|
VIDIOC_ENUMSTD | 枚舉設備支持的所有標準 |
VIDIOC_G_STD | 獲取當前正在使用的標準 |
VIDIOC_S_STD | 設置視頻標準 |
VIDIOC_QUERYSTD | 有的設備支持自動偵測輸入源的視頻標準,此ioctl獲取檢測到的標準 |
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];
};
當然世界上現在有多個視頻標準,如NTSC和PAL,他們又細分為好多種,那麼我們的設 備輸入/輸出究竟支持什麼樣的標準呢?我們的當前在使用的輸入和輸出正在使用的是哪 個標準呢?我們怎麼設置我們的某個輸入輸出使用的標準呢?這都是有方法的。
查詢我們的輸入支持什麼標準,首先就得找到當前的這個輸入的index,然後查出它的 屬性,在其屬性裡面可以得到該輸入所支持的標準,將它所支持的各個標準與所有的標準 的信息進行比較,就可以獲知所支持的各個標準的屬性。一個輸入所支持的標準應該是一 個集合,而這個集合是用bit與的方式用一個64位數字表示。因此我們所查到的是一個數字。
5) Camera Control Reference
控制屬性
ID | 描述 |
---|---|
VIDIOC_QUERYCTRL | 查詢指定的control詳細信息 |
VIDIOC_QUERYMENU | 查詢menu |
VIDIOC_G_CTRL | 獲取設備指定control的當前信息 |
VIDIOC_S_CTRL | 設置設備指定的control |
6) Image Format
圖像格式
圖像由多種格式YUV和RGB還有壓縮格式等等,其中每種格式又分有多種格式,比如RGB:RGB565、RGB888…
所以在使用設備時,需要對格式進行設置
ID | 描述 |
---|---|
VIDIOC_ENUM_FMT | 枚舉設備支持的圖像格式 |
VIDIOC_G_FMT | 獲取當前設備的圖像格式 |
VIDIOC_S_FMT | 設置圖像格式 |
VIDIOC_TRY_FMT | 測試設備是否支持此格式 |
查詢並顯示所有支持的格式:VIDIOC_ENUM_FMT
struct v4l2_fmtdesc
{
u32 index; // 要查詢的格式序號,應用程式設置
enum v4l2_buf_type type; // 幀類型,應用程式設置
u32 flags; // 是否為壓縮格式
u8 description[32]; // 格式名稱
u32 pixelformat; // 格式
u32 reserved[4]; // 保留
};
查看或設置當前格式: VIDIOC_G_FMT, VIDIOC_S_FMT
struct v4l2_format
{
enum v4l2_buf_type type; // 幀類型,應用程式設置
union fmt
{
struct v4l2_pix_format pix; // 視頻設備使用
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 | 獲取當前的裁剪矩陣 |
VIDIOC_S_CROP | 設置裁剪矩陣 |
Cropping 和 scaling 主要指的是圖像的取景範圍及圖片的比例縮放的支持。Crop 就 是把得到的數據作一定的裁剪和伸縮,裁剪可以只取樣我們可以得到的圖像大小的一部分, 剪裁的主要參數是位置、長度、寬度。而 scale 的設置是通過 VIDIOC_G_FMT 和 VIDIOC_S_FMT 來獲得和設置當前的 image 的長度,寬度來實現的。
看下圖:
我們可以假設 bounds 是 sensor 最大能捕捉到的圖像範圍,而 defrect 是設備預設 的最大取樣範圍,這個可以通過 VIDIOC_CROPCAP 的 ioctl 來獲得設備的 crap 相關的屬 性 v4l2_cropcap,其中的 bounds 就是這個 bounds,其實就是上限。每個設備都有個默 認的取樣範圍,就是 defrect,就是 default rect 的意思,它比 bounds 要小一些。這 個範圍也是通過 VIDIOC_CROPCAP 的 ioctl 來獲得的 v4l2_cropcap 結構中的 defrect 來表示的,我們可以通過 VIDIOC_G_CROP 和 VIDIOC_S_CROP 來獲取和設置設備當前的 crop 設置。
設置設備捕捉能力的參數
struct v4l2_cropcap
{
enum v4l2_buf_type type; // 數據流的類型,應用程式設置
struct v4l2_rect bounds; // 這是 camera 的鏡頭能捕捉到的視窗大小的局限
struct v4l2_rect defrect; // 定義預設視窗大小,包括起點位置及長,寬的大小,大小以像素為單位
struct v4l2_fract pixelaspect; // 定義了圖片的寬高比
};
設置視窗取景參數 VIDIOC_G_CROP 和 VIDIOC_S_CROP
struct v4l2_crop
{
enum v4l2_buf_type type;// 應用程式設置
struct v4l2_rect c;
}
8) buf Input/Output
數據的輸入和輸出
內核中使用緩存隊列對圖像數據進行管理,用戶空間獲取圖像數據有兩種方式,一種是通過read、write方式讀取內核空間的緩存,一種是將內核空間的緩存映射到用戶空間,即streaming。在操作v4l2設備時,通過VIDIOC_QUERYCAP獲取設備支持哪種方式。
streaming就是在內核空間中維護一個緩存隊列,然後將記憶體映射到用戶空間,應用讀取圖像數據就是一個不斷地出隊列和入隊列的過程,如下圖所示
ID | 描述 |
---|---|
VIDIOC_REQBUFS | 申請緩存 |
VIDIOC_QUERYBUF | 獲取緩存信息 |
VIDIOC_QBUF | 將緩存放入隊列中 |
VIDIOC_DQBUF | 將緩存從隊列中取出 |
1. 向設備申請緩衝區 VIDIOC_REQBUFS
struct v4l2_requestbuffers
{
u32 count; // 緩衝區內緩衝幀的數目
enum v4l2_buf_type type; // 緩衝幀數據格式
enum v4l2_memory memory; // 區別是記憶體映射還是用戶指針方式
u32 reserved[2];
};
enum v4l2_memoy
{
V4L2_MEMORY_MMAP, V4L2_MEMORY_USERPTR
};
獲取緩衝幀的地址,長度:VIDIOC_QUERYBUF
struct v4l2_buffer
{
u32 index; //buffer 序號
enum v4l2_buf_type type; //buffer 類型
u32 byteused; //buffer 中已使用的位元組數
u32 flags; // 區分是MMAP 還是USERPTR
enum v4l2_field field;
struct timeval timestamp; // 獲取第一個位元組時的系統時間
struct v4l2_timecode timecode;
u32 sequence; // 隊列中的序號
enum v4l2_memory memory; //IO 方式,被應用程式設置
union m
{
u32 offset; // 緩衝幀地址,只對MMAP 有效
unsigned long userptr;
};
u32 length; // 緩衝幀長度
u32 input;
u32 reserved;
};
2. 記憶體映射MMAP 及定義一個結構體來映射每個緩衝幀。
相關結構體:
struct buffer
{
void* start;
unsigned int length;
}*buffers;
相關函數:
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
參數:
addr 映射起始地址,一般為NULL ,讓內核自動選擇
length 被映射記憶體塊的長度
prot 標誌映射後能否被讀寫,其值為PROT_EXEC,PROT_READ,PROT_WRITE, PROT_NONE
flags 確定此記憶體映射能否被其他進程共用,MAP_SHARED,MAP_PRIVATE
fd,offset, 確定被映射的記憶體地址 返回成功映射後的地址,不成功返回MAP_FAILED ((void*)-1)
3.將所有的緩存放入隊列
struct v4l2_buffer v4l2_buffer;
for(i = 0; i < nr_bufs; i++)
{
memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
v4l2_buffer.index = i; //想要放入隊列的緩存
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)啟動 或 停止數據流
VIDIOC_STREAMON, VIDIOC_STREAMOFF
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl (fd, VIDIOC_STREAMON, &type);
5. v4l2設備抓幀程式編寫
v4l2設備的命令比較多,其實常用的並不是很多,下麵通過一個實例來詳細講解,如何操作v4l2設備。
1)設備配置
本例,將常用的攝像頭配置參數等裝成結構體:
struct v4l2_dev
{
int fd; //videoO對應的設備描述符
int sub_fd;
const char *path; //字元設備 /dev/videoO
const char *name; //攝像頭名稱
const char *subdev_path;//字元設備 /dev/v4l-subdev3
const char *out_type; //輸出圖像格式
enum v4l2_buf_type buf_type;//緩存類型
int format; //像素格式
int width; //圖像寬度
int height; //圖像高度
unsigned int req_count; //緩存數量
enum v4l2_memory memory_type; //讀取圖像的方法,DMA還是MMAP
struct buffer *buffers; //緩衝區
unsigned long int timestamp;//時長度
int data_len;//圖像數據長度
unsigned char *out_data;//圖像數據
};
本例填寫的攝像頭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設備一般操作流程(抓幀)
v4l2設備一般操作流程如下圖所示:
各功能對應的ioctrl命令如下:
測試程式一口君已經上傳到gitee:
https://gitee.com/yikoulinux/v4l2-app
git clone [email protected]:yikoulinux/v4l2-app.git
歡迎各位老鐵star。
3)程式執行log
以下是在瑞芯微rk3568實際測試的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!
文中各種mipi技術文檔,後臺回覆關鍵字:mipi
掌握了這些命令,我們就可以調試攝像頭了。
後面還會繼續更新幾篇Camera文章,
建議大家訂閱本專題!
也可以後臺留言,加一口君好友yikoupeng,
拉你進高質量技術交流群。
歡迎關註公眾號:一口Linux