日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

V4L2框架分析学习

發布時間:2025/3/21 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 V4L2框架分析学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Author:CJOK

Contact:cjok.liao#gmail.com

SinaWeibo:@廖野cjok

?

1、概述

Video4Linux2是Linux內核中關于視頻設備的內核驅動框架,為上層的訪問底層的視頻設備提供了統一的接口。凡是內核中的子系統都有抽象底層硬件的差異,為上層提供統一的接口和提取出公共代碼避免代碼冗余等好處。就像公司的老板一般都不會直接找底層的員工談話,而是找部門經理了解情況,一個是因為底層屌絲人數多,意見各有不同,措辭也不準,部門經理會把情況匯總后再向上匯報;二個是老板時間寶貴。

???????? V4L2支持三類設備:視頻輸入輸出設備、VBI設備和radio設備(其實還支持更多類型的設備,暫不討論),分別會在/dev目錄下產生videoX、radioX和vbiX設備節點。我們常見的視頻輸入設備主要是攝像頭,也是本文主要分析對象。下圖V4L2在Linux系統中的結構圖:



Linux系統中視頻輸入設備主要包括以下四個部分:

字符設備驅動程序核心:V4L2本身就是一個字符設備,具有字符設備所有的特性,暴露接口給用戶空間;

V4L2驅動核心:主要是構建一個內核中標準視頻設備驅動的框架,為視頻操作提供統一的接口函數;

平臺V4L2設備驅動:在V4L2框架下,根據平臺自身的特性實現與平臺相關的V4L2驅動部分,包括注冊video_device和v4l2_dev。

具體的sensor驅動:主要上電、提供工作時鐘、視頻圖像裁剪、流IO開啟等,實現各種設備控制方法供上層調用并注冊v4l2_subdev。

?

V4L2的核心源碼位于drivers/media/v4l2-core,源碼以實現的功能可以劃分為四類:

核心模塊實現:由v4l2-dev.c實現,主要作用申請字符主設備號、注冊class和提供video device注冊注銷等相關函數;

V4L2框架:由v4l2-device.c、v4l2-subdev.c、v4l2-fh.c、v4l2-ctrls.c等文件實現,構建V4L2框架;

Videobuf管理:由videobuf2-core.c、videobuf2-dma-contig.c、videobuf2-dma-sg.c、videobuf2-memops.c、videobuf2-vmalloc.c、v4l2-mem2mem.c等文件實現,完成videobuffer的分配、管理和注銷。

Ioctl框架:由v4l2-ioctl.c文件實現,構建V4L2ioctl的框架。

?

2、V4L2框架

???????? 結構體v4l2_device、video_device、v4l2_subdev和v4l2_fh是搭建框架的主要元素。下圖是V4L2框架的結構圖:


從上圖V4L2框架是一個標準的樹形結構,v4l2_device充當了父設備,通過鏈表把所有注冊到其下的子設備管理起來,這些設備可以是GRABBER、VBI或RADIO。V4l2_subdev是子設備,v4l2_subdev結構體包含了對設備操作的ops和ctrls,這部分代碼和硬件相關,需要驅動工程師根據硬件實現,像攝像頭設備需要實現控制上下電、讀取ID、飽和度、對比度和視頻數據流打開關閉的接口函數。Video_device用于創建子設備節點,把操作設備的接口暴露給用戶空間。V4l2_fh是每個子設備的文件句柄,在打開設備節點文件時設置,方便上層索引到v4l2_ctrl_handler,v4l2_ctrl_handler管理設備的ctrls,這些ctrls(攝像頭設備)包括調節飽和度、對比度和白平衡等。

?

v4l2_device

v4l2_device在v4l2框架中充當所有v4l2_subdev的父設備,管理著注冊在其下的子設備。以下是v4l2_device結構體原型(去掉了無關的成員):

struct v4l2_device {

???????? structlist_head subdevs;??? //用鏈表管理注冊的subdev

???????? charname[V4L2_DEVICE_NAME_SIZE];??? //device?名字

???????? structkref ref;????? //引用計數

???????? ……

};

可以看出v4l2_device的主要作用是管理注冊在其下的子設備,方便系統查找引用到。

V4l2_device的注冊和注銷:

int?v4l2_device_register(struct device*dev, struct v4l2_device *v4l2_dev)

static void v4l2_device_release(struct kref *ref)

?

V4l2_subdev

V4l2_subdev代表子設備,包含了子設備的相關屬性和操作。先來看下結構體原型:

struct v4l2_subdev {

???????? structv4l2_device *v4l2_dev;? //指向父設備

???????? //提供一些控制v4l2設備的接口

???????? conststruct v4l2_subdev_ops *ops;

???????? //V4L2框架提供的接口函數

???????? conststruct v4l2_subdev_internal_ops *internal_ops;

???????? //subdev控制接口

???????? structv4l2_ctrl_handler *ctrl_handler;

???????? /* namemust be unique */

???????? charname[V4L2_SUBDEV_NAME_SIZE];

???????? /*subdev device node */

???????? structvideo_device *devnode;??

};

每個子設備驅動都需要實現一個v4l2_subdev結構體,v4l2_subdev可以內嵌到其它結構體中,也可以獨立使用。結構體中包含了對子設備操作的成員v4l2_subdev_ops和v4l2_subdev_internal_ops。

v4l2_subdev_ops結構體原型如下:

struct v4l2_subdev_ops {

//視頻設備通用的操作:初始化、加載FW、上電和RESET

???????? conststruct v4l2_subdev_core_ops??????? *core;

//tuner特有的操作

???????? conststruct v4l2_subdev_tuner_ops????? *tuner;

//audio特有的操作

???????? conststruct v4l2_subdev_audio_ops????? *audio;

//視頻設備的特有操作:設置幀率、裁剪圖像、開關視頻流等

???????? conststruct?v4l2_subdev_video_ops????? *video;

……

};

視頻設備通常需要實現core和video成員,這兩個OPS中的操作都是可選的,但是對于視頻流設備video->s_stream(開啟或關閉流IO)必須要實現。

?

v4l2_subdev_internal_ops結構體原型如下:

struct?v4l2_subdev_internal_ops?{

??? //subdev注冊時被調用,讀取ICID來進行識別

???????? int(*registered)(struct v4l2_subdev *sd);

???????? void(*unregistered)(struct v4l2_subdev *sd);

//當設備節點被打開時調用,通常會給設備上電和設置視頻捕捉FMT

???????? int(*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);

???????? int(*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);

};

v4l2_subdev_internal_ops是向V4L2框架提供的接口,只能被V4L2框架層調用。在注冊或打開子設備時,進行一些輔助性操作。

?

Subdev的注冊和注銷

當我們把v4l2_subdev需要實現的成員都已經實現,就可以調用以下函數把子設備注冊到V4L2核心層:

int v4l2_device_register_subdev(struct v4l2_device*v4l2_dev, struct v4l2_subdev *sd)

當卸載子設備時,可以調用以下函數進行注銷:

void v4l2_device_unregister_subdev(struct v4l2_subdev*sd)

?

video_device

???????? video_device結構體用于在/dev目錄下生成設備節點文件,把操作設備的接口暴露給用戶空間。

struct video_device

{

???????? conststruct v4l2_file_operations *fops;??//V4L2設備操作集合

?

???????? /*sysfs */

???????? structdevice dev;???????????? /* v4l device */

???????? structcdev *cdev;??????????? //字符設備

?

???????? /* Seteither parent or v4l2_dev if your driver uses v4l2_device */

???????? structdevice *parent;????????????? /* deviceparent */

???????? structv4l2_device *v4l2_dev;????????? /*v4l2_device parent */

?

???????? /*Control handler associated with this device node. May be NULL. */

???????? structv4l2_ctrl_handler *ctrl_handler;

?

???????? /*?指向video buffer隊列*/

???????? structvb2_queue *queue;

?

???????? intvfl_type;????? /* device type */

???????? intminor;? //次設備號

?

???????? /* V4L2file handles */

???????? spinlock_t????????????????? fh_lock; /* Lock for allv4l2_fhs */

???????? structlist_head??????? fh_list; /* List ofstruct v4l2_fh */

?

???????? /*ioctl回調函數集,提供file_operations中的ioctl調用?*/

???????? conststruct v4l2_ioctl_ops *ioctl_ops;

???????? ……

};

Video_device分配和釋放,用于分配和釋放video_device結構體:

struct video_device *video_device_alloc(void)

void video_device_release(struct video_device *vdev)

?

video_device注冊和注銷,實現video_device結構體的相關成員后,就可以調用下面的接口進行注冊:

static inline int __must_checkvideo_register_device(struct video_device *vdev,

?????????????????? inttype, int nr)

void video_unregister_device(struct video_device*vdev);

vdev:需要注冊和注銷的video_device;

type:設備類型,包括VFL_TYPE_GRABBER、VFL_TYPE_VBI、VFL_TYPE_RADIO和VFL_TYPE_SUBDEV。

nr:設備節點名編號,如/dev/video[nr]。

?

v4l2_fh

?????????v4l2_fh是用來保存子設備的特有操作方法,也就是下面要分析到的v4l2_ctrl_handler,內核提供一組v4l2_fh的操作方法,通常在打開設備節點時進行v4l2_fh注冊。

初始化v4l2_fh,添加v4l2_ctrl_handler到v4l2_fh:

void v4l2_fh_init(struct v4l2_fh *fh, structvideo_device *vdev)

添加v4l2_fh到video_device,方便核心層調用到:

void v4l2_fh_add(struct v4l2_fh *fh)

?

v4l2_ctrl_handler

v4l2_ctrl_handler是用于保存子設備控制方法集的結構體,對于視頻設備這些ctrls包括設置亮度、飽和度、對比度和清晰度等,用鏈表的方式來保存ctrls,可以通過v4l2_ctrl_new_std函數向鏈表添加ctrls。

struct v4l2_ctrl *v4l2_ctrl_new_std(structv4l2_ctrl_handler *hdl,

??????????????????????????? conststruct v4l2_ctrl_ops *ops,

??????????????????????????? u32id, s32 min, s32 max, u32 step, s32 def)

hdl是初始化好的v4l2_ctrl_handler結構體;

ops是v4l2_ctrl_ops結構體,包含ctrls的具體實現;

id是通過IOCTL的arg參數傳過來的指令,定義在v4l2-controls.h文件;

min、max用來定義某操作對象的范圍。如:

v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS,-208, 127, 1, 0);

用戶空間可以通過ioctl的VIDIOC_S_CTRL指令調用到v4l2_ctrl_handler,id透過arg參數傳遞。

?

?

3、ioctl框架

???????? 你可能觀察到用戶空間對V4L2設備的操作基本都是ioctl來實現的,V4L2設備都有大量可操作的功能(配置寄存器),所以V4L2的ioctl也是十分龐大的。它是一個怎樣的框架,是怎么實現的呢?

???????? Ioctl框架是由v4l2_ioctl.c文件實現,文件中定義結構體數組v4l2_ioctls,可以看做是ioctl指令和回調函數的關系表。用戶空間調用系統調用ioctl,傳遞下來ioctl指令,然后通過查找此關系表找到對應回調函數。

以下是截取數組的兩項:

IOCTL_INFO_FNC(VIDIOC_QUERYBUF, v4l_querybuf,v4l_print_buffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_buffer, length)),

IOCTL_INFO_STD(VIDIOC_G_FBUF, vidioc_g_fbuf,v4l_print_framebuffer, 0),

???????? 內核提供兩個宏(IOCTL_INFO_FNCIOCTL_INFO_STD)來初始化結構體,參數依次是ioctl指令、回調函數或者v4l2_ioctl_ops結構體成員、debug函數、flag。如果回調函數是v4l2_ioctl_ops結構體成員,則使用IOCTL_INFO_STD;如果回調函數是v4l2_ioctl.c自己實現的,則使用IOCTL_INFO_FNC

?

IOCTL調用的流程圖如下:


? 用戶空間通過打開/dev/目錄下的設備節點,獲取到文件的file結構體,通過系統調用ioctl把cmd和arg傳入到內核。通過一系列的調用后最終會調用到__video_do_ioctl函數,然后通過cmd檢索v4l2_ioctls[],判斷是INFO_FL_STD還是INFO_FL_FUNC。如果是INFO_FL_STD會直接調用到視頻設備驅動中video_device->v4l2_ioctl_ops函數集。如果是INFO_FL_FUNC會先調用到v4l2自己實現的標準回調函數,然后根據arg再調用到video_device->v4l2_ioctl_ops或v4l2_fh->v4l2_ctrl_handler函數集。

?

?

4、IO訪問

V4L2支持三種不同IO訪問方式(內核中還支持了其它的訪問方式,暫不討論):

read和write,是基本幀IO訪問方式,通過read讀取每一幀數據,數據需要在內核和用戶之間拷貝,這種方式訪問速度可能會非常慢;

內存映射緩沖區(V4L2_MEMORY_MMAP),是在內核空間開辟緩沖區,應用通過mmap()系統調用映射到用戶地址空間。這些緩沖區可以是大而連續DMA緩沖區、通過vmalloc()創建的虛擬緩沖區,或者直接在設備的IO內存中開辟的緩沖區(如果硬件支持);

用戶空間緩沖區(V4L2_MEMORY_USERPTR),是用戶空間的應用中開辟緩沖區,用戶與內核空間之間交換緩沖區指針。很明顯,在這種情況下是不需要mmap()調用的,但驅動為有效的支持用戶空間緩沖區,其工作將也會更困難。

Read和write方式屬于幀IO訪問方式,每一幀都要通過IO操作,需要用戶和內核之間數據拷貝,而后兩種是流IO訪問方式,不需要內存拷貝,訪問速度比較快。內存映射緩沖區訪問方式是比較常用的方式。

內存映射緩存區方式

???????? 硬件層的數據流傳輸

???????? Camerasensor捕捉到圖像數據通過并口或MIPI傳輸到CAMIF(camera interface),CAMIF可以對圖像數據進行調整(翻轉、裁剪和格式轉換等)。然后DMA控制器設置DMA通道請求AHB將圖像數據傳到分配好的DMA緩沖區。


???????? 待圖像數據傳輸到DMA緩沖區之后,mmap操作把緩沖區映射到用戶空間,應用就可以直接訪問緩沖區的數據。

?

vb2_queue

為了使設備支持流IO這種方式,驅動需要實現struct vb2_queue,來看下這個結構體:

struct vb2_queue {

???????? enumv4l2_buf_type????????????????? type;? //buffer類型

???????? unsignedint??????????????????????? io_modes;? //訪問IO的方式:mmapuserptr etc

?

???????? conststruct vb2_ops???????????????? *ops;?? //buffer隊列操作函數集合

???????? conststruct vb2_mem_ops???? *mem_ops;? //buffer memory操作集合

?

???????? structvb2_buffer????????????? *bufs[VIDEO_MAX_FRAME];? //代表每個buffer

???????? unsignedint??????????????????????? num_buffers;??? //分配的buffer個數

……

};

Vb2_queue代表一個videobuffer隊列,vb2_buffer是這個隊列中的成員,vb2_mem_ops是緩沖內存的操作函數集,vb2_ops用來管理隊列。

?

vb2_mem_ops

???????? vb2_mem_ops包含了內存映射緩沖區、用戶空間緩沖區的內存操作方法:

struct?vb2_mem_ops?{

???????? void?????????? *(*alloc)(void *alloc_ctx, unsignedlong size);? //分配視頻緩存

???????? void?????????? (*put)(void *buf_priv);??????????? //釋放視頻緩存

//獲取用戶空間視頻緩沖區指針

???????? void?????????? *(*get_userptr)(void *alloc_ctx,unsigned long vaddr,?

?????????????????????????????????????????????? unsignedlong size, int write);

???????? void?????????? (*put_userptr)(void *buf_priv);?????? //釋放用戶空間視頻緩沖區指針

?

//用于緩存同步

???????? void?????????? (*prepare)(void *buf_priv);

???????? void?????????? (*finish)(void *buf_priv);

?

???????? void?????????? *(*vaddr)(void *buf_priv);

???????? void?????????? *(*cookie)(void *buf_priv);

???????? unsignedint???? (*num_users)(void *buf_priv);???????? //返回當期在用戶空間的buffer

?

???????? int????????????? (*mmap)(void *buf_priv, structvm_area_struct *vma);? //把緩沖區映射到用戶空間

};

???????? 這是一個相當龐大的結構體,這么多的結構體需要實現還不得累死,幸運的是內核都已經幫我們實現了。提供了三種類型的視頻緩存區操作方法:連續的DMA緩沖區、集散的DMA緩沖區以及vmalloc創建的緩沖區,分別由videobuf2-dma-contig.c、videobuf2-dma-sg.c和videobuf-vmalloc.c文件實現,可以根據實際情況來使用。

?

vb2_ops

???????? vb2_ops是用來管理buffer隊列的函數集合,包括隊列和緩沖區初始化

struct vb2_ops {

???????? //隊列初始化

???????? int(*queue_setup)(struct vb2_queue *q, const struct v4l2_format *fmt,

??????????????????????????? ?? unsigned int *num_buffers, unsigned int*num_planes,

??????????????????????????? ?? unsigned int sizes[], void *alloc_ctxs[]);

???????? //釋放和獲取設備操作鎖

???????? void(*wait_prepare)(struct vb2_queue *q);

???????? void(*wait_finish)(struct vb2_queue *q);

???????? //buffer的操作

???????? int(*buf_init)(struct vb2_buffer *vb);

???????? int(*buf_prepare)(struct vb2_buffer *vb);

???????? int(*buf_finish)(struct vb2_buffer *vb);

???????? void(*buf_cleanup)(struct vb2_buffer *vb);

//開始視頻流

???????? int(*start_streaming)(struct vb2_queue *q, unsigned int count);

//停止視頻流

???????? int(*stop_streaming)(struct vb2_queue *q);

//VB傳遞給驅動

???????? void(*buf_queue)(struct vb2_buffer *vb);

};

?

vb2_buffer是緩存隊列的基本單位,內嵌在其中v4l2_buffer是核心成員。當開始流IO時,幀以v4l2_buffer的格式在應用和驅動之間傳輸。一個緩沖區可以有三種狀態:

在驅動的傳入隊列中,驅動程序將會對此隊列中的緩沖區進行處理,用戶空間通過IOCTL:VIDIOC_QBUF把緩沖區放入到隊列。對于一個視頻捕獲設備,傳入隊列中的緩沖區是空的,驅動會往其中填充數據;

在驅動的傳出隊列中,這些緩沖區已由驅動處理過,對于一個視頻捕獲設備,緩存區已經填充了視頻數據,正等用戶空間來認領;

用戶空間狀態的隊列,已經通過IOCTL:VIDIOC_DQBUF傳出到用戶空間的緩沖區,此時緩沖區由用戶空間擁有,驅動無法訪問。

這三種狀態的切換如下圖所示:

v4l2_buffer結構如下:

struct v4l2_buffer {

???????? __u32????????????????????????? index;? //buffer?序號

???????? __u32????????????????????????? type;?? //buffer類型

???????? __u32????????????????????????? bytesused;??緩沖區已使用byte

???????? __u32????????????????????????? flags;

???????? __u32????????????????????????? field;

???????? structtimeval?????????? timestamp;? //時間戳,代表幀捕獲的時間

???????? structv4l2_timecode?????? timecode;

???????? __u32????????????????????????? sequence;

?

???????? /*memory location */

???????? __u32????????????????????????? memory;? //表示緩沖區是內存映射緩沖區還是用戶空間緩沖區

???????? union {

?????????????????? __u32?????????? offset;? //內核緩沖區的位置

?????????????????? unsignedlong?? userptr;?? //緩沖區的用戶空間地址

?????????????????? structv4l2_plane *planes;

?????????????????? __s32???????????????? fd;

???????? } m;

???????? __u32????????????????????????? length;?? //緩沖區大小,單位byte

};

當用戶空間拿到v4l2_buffer,可以獲取到緩沖區的相關信息。Byteused是圖像數據所占的字節數,如果是V4L2_MEMORY_MMAP方式,m.offset是內核空間圖像數據存放的開始地址,會傳遞給mmap函數作為一個偏移,通過mmap映射返回一個緩沖區指針p,p+byteused是圖像數據在進程的虛擬地址空間所占區域;如果是用戶指針緩沖區的方式,可以獲取的圖像數據開始地址的指針m.userptr,userptr是一個用戶空間的指針,userptr+byteused便是所占的虛擬地址空間,應用可以直接訪問。

?

5、用戶空間訪問設備

下面通過內核映射緩沖區方式訪問視頻設備(capturedevice)的流程。

1>????打開設備文件

fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

dev_name[/dev/videoX]

2>????查詢設備支持的能力

Struct v4l2_capability? cap;

ioctl(fd, VIDIOC_QUERYCAP, &cap)

3>????設置視頻捕獲格式

fmt.type= V4L2_BUF_TYPE_VIDEO_CAPTURE;

fmt.fmt.pix.width?????? = 640;

fmt.fmt.pix.height????? = 480;

fmt.fmt.pix.pixelformat= V4L2_PIX_FMT_YUYV;? //像素格式

fmt.fmt.pix.field?????? = V4L2_FIELD_INTERLACED;

ioctl(fd,VIDIOC_S_FMT, & fmt)

4>????向驅動申請緩沖區

Struct? v4l2_requestbuffers req;

req.count= 4;? //緩沖個數

req.type= V4L2_BUF_TYPE_VIDEO_CAPTURE;

req.memory= V4L2_MEMORY_MMAP;

if(-1 == xioctl(fd, VIDIOC_REQBUFS, &req))

5>????獲取每個緩沖區的信息,映射到用戶空間

structbuffer {

??????? void??*start;

??????? size_t?length;

} *buffers;

buffers = calloc(req.count, sizeof(*buffers));

?

for (n_buffers= 0; n_buffers < req.count; ++n_buffers) {

struct? v4l2_buffer buf;

?

buf.type??????? = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory????? = V4L2_MEMORY_MMAP;

buf.index?????? = n_buffers;

if (-1 ==xioctl(fd, VIDIOC_QUERYBUF, & buf))

???????????????????????errno_exit("VIDIOC_QUERYBUF");

buffers[n_buffers].length= buf.length;

buffers[n_buffers].start=

??????? mmap(NULL /* start anywhere */,

??????? buf.length,

??????? PROT_READ | PROT_WRITE /* required */,

??????? MAP_SHARED /* recommended */,

??????? fd, buf.m.offset);

?}

6>????把緩沖區放入到傳入隊列上,打開流IO,開始視頻采集

for (i =0; i < n_buffers; ++i) {

??? struct?v4l2_buffer buf;

??? buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

??? buf.memory = V4L2_MEMORY_MMAP;

??? buf.index = i;

?

??? if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))

????????? errno_exit("VIDIOC_QBUF");

?}

?type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

?if (-1 == xioctl(fd, VIDIOC_STREAMON, & type))

7> ?調用select監測文件描述符,緩沖區的數據是否填充好,然后對視頻數據

?????? ?for (;;) {

??????????????????????? fd_set fds;

??????????????????????? struct timeval tv;

??????????????????????? int r;

?

??????????????????????? FD_ZERO(&amp;fds);

??????????????????????? FD_SET(fd,&amp;fds);

?

??????????????????????? /* Timeout. */

??????????????????????? tv.tv_sec = 2;

???????????? ???????????tv.tv_usec = 0;

??????????????????????????????????????????????????????? //監測文件描述是否變化

??????????????????????? r = select(fd + 1,& fds, NULL, NULL, & tv);

?

??????????????????????? if (-1 == r) {

??????????????????????????????? if (EINTR ==errno)

???????????????????????????????????????continue;

???????????????????????????????errno_exit("select");

??????????????????????? }

?

??????????????????????? if (0 == r) {

??????????????????????????????? fprintf(stderr,"select timeout\n");

???????????????????????????????exit(EXIT_FAILURE);

??????????????????????? }

??????????????????????????????????????????????????????? //對視頻數據進行處理

??????????????????????? if (read_frame())

??????????????????????????????? break;

??????????????????????? /* EAGAIN - continueselect loop. */

???????????????}

?

8>????取出已經填充好的緩沖,獲取到視頻數據的大小,然后對數據進行處理。這里取出的緩沖只包含緩沖區的信息,并沒有進行視頻數據拷貝。

buf.type= V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory= V4L2_MEMORY_MMAP;

if (-1 ==ioctl(fd, VIDIOC_DQBUF, & buf)) ???//取出緩沖

?????????? errno_exit("VIDIOC_QBUF");

process_image(buffers[buf.index].start,buf.bytesused);?? //視頻數據處理

if (-1 ==xioctl(fd, VIDIOC_QBUF, & buf))? //然后又放入到傳入隊列

???? errno_exit("VIDIOC_QBUF");

9>????停止視頻采集

type =V4L2_BUF_TYPE_VIDEO_CAPTURE;

ioctl(fd,VIDIOC_STREAMOff, & type);

10>?關閉設備

Close(fd);

?

暫時分析到這里,后續在更新!

Reference:

http://lxr.linux.no/linux+v3.8.8/Documentation/video4linux/v4l2-framework.txt

http://lxr.linux.no/linux+v3.9/Documentation/DocBook/media/v4l/capture.c.xml

http://linuxtv.org/downloads/v4l-dvb-apis/vidioc-reqbufs.html

http://lwn.net/Articles/203924/

http://lxr.linux.no/linux+v3.9.1/drivers/media/platform/vivi.c

總結

以上是生活随笔為你收集整理的V4L2框架分析学习的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。