V4L2框架分析

? ? ? ?V4L2是Video for linux2的簡稱,為linux中關于視頻設備的內核驅動。v4L2是針對uvc(USB Video Class)免驅usb設備的編程框架,主要用于采集usb攝像頭等。

? ? ? 下圖是V4L2的框架,首先系統核心層分配設置注冊一個名為cdev結構體變量(cdev結構體是video_device結構體里的一部分),并設置cdev->ops = v4l2_fops;在硬件層我們分配設置注冊了一個名為vfd結構體變量(video_device結構體),并設置vfd->fops = &vivi_fops,vfd->ioctl_ops ?= &vivi_ioctl_ops;當應用程序(APP)調用read、open等函數時,會調用到v4l2_fops里的read、open函數,然后v4l2_fops里的read、open函數會再調用到硬件層相關的vfd->fops里的read、open函數。ioctl函數也類似。

? ? ? ? 下面我們從程序入手來分析V4L2的框架,本文借助Linux內核目錄下的drivers\medio\video里的虛擬視頻驅動程序vivi.c(這段代碼使用v4l2 api模擬真實的視頻設備)來分析V4L2的框架。它的總體框架如下所示:

vivi_initvivi_create_instancev4l2_device_register   // 不是主要, 只是用于初始化一些東西,比如自旋鎖、引用計數video_device_alloc// 設置1. vfd:.fops           = &vivi_fops,.ioctl_ops 	= &vivi_ioctl_ops,.release	= video_device_release,2.vfd->v4l2_dev = &dev->v4l2_dev;3. 設置"ctrl屬性"(用于APP的ioctl):v4l2_ctrl_handler_init(hdl, 11);dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,V4L2_CID_CONTRAST, 0, 255, 1, 16);                        video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)__video_register_devicevdev->cdev = cdev_alloc();vdev->cdev->ops = &v4l2_fops;cdev_addvideo_device[vdev->minor] = vdev;if (vdev->ctrl_handler == NULL)vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;

①我們從vivi.c里的vivi_init函數入手發現它調用了v4l2_device_register,該函數用于初始化一些東西,比如自旋鎖、引用計數,這個并不是必需的;②調用了video_device_alloc分配video_device結構體并對其進行相應的設置,例如

.fops? ? ? ? ? ? ?= &vivi_fops,
.ioctl_ops ?? ?= &vivi_ioctl_ops,
.release? ? ? ?= video_device_release,

等設置,然后video_register_device注冊該結構體;

③video_register_device函數調用了__video_register_device實現了如下操作:

vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
cdev_add
? ? ? ? ? ? ? ??
video_device[vdev->minor] = vdev;

if (vdev->ctrl_handler == NULL)
? ? vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;

?

?

上圖是vivi_create_instance函數的一部分,首先分配一個video_device結構體的變量vfd,然后設置*vfd = vivi_template;其中vivi_template是一個video_device的結構體變量,它本身設置好了一些如.fops之類信息(如下圖),此操作便相當于設置

?1. vfd:

.fops? ? ? ? ? ? ?= &vivi_fops,
.ioctl_ops ?? ?= &vivi_ioctl_ops,
.release? ? ? ?= video_device_release,

static struct video_device vivi_template = {.name		= "vivi",.fops           = &vivi_fops,.ioctl_ops 	= &vivi_ioctl_ops,.release	= video_device_release,.tvnorms              = V4L2_STD_525_60,.current_norm         = V4L2_STD_NTSC_M,
};

然后進入video_register_device函數,下面是video_register_device里的一部分源碼,首先分配一個cdev結構體

然后設置cdev->ops = &v4l2_fops;v4l2_fops本身指向了一些函數(如下圖),這樣cdev便也指向了這些函數,當APP調用read函數時,便會調用cdev里面的read函數

static const struct file_operations v4l2_fops = {.owner = THIS_MODULE,.read = v4l2_read,.write = v4l2_write,.open = v4l2_open,.get_unmapped_area = v4l2_get_unmapped_area,.mmap = v4l2_mmap,.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl = v4l2_compat_ioctl32,
#endif.release = v4l2_release,.poll = v4l2_poll,.llseek = no_llseek,
};

cdev里面的read函數如下圖,首先根據filp獲取到video_device結構體,然后判斷該video_device結構體里的read函數是否存在,若存在則調用它,所以最后便調用到了前面我們設置的vfd.fops里的read函數。

?

?

?

?

相比open、read函數,ioctl的調用過程更復雜一些,下面我們來看一下(我們以VIDIOC_QUERYCAP為例)。下圖是v4l2_fops里的.unlocked_ioctl指向的v4l2_ioctl函數。

它調用了前面vivi_template的fops里面的ioctl。

vivi_template的fops里面的ioctl里調用到下圖的__video_do_ioctl函數,該函數最終調用到vfd里的ioctl_ops成員里面的函數,即vivi_ioctl_ops里的函數

比如調用的是?VIDIOC_QUERYCAP,則最終會調用到下面的函數。

/* ------------------------------------------------------------------IOCTL vidioc handling------------------------------------------------------------------*/
static int vidioc_querycap(struct file *file, void  *priv,struct v4l2_capability *cap)
{struct vivi_dev *dev = video_drvdata(file);strcpy(cap->driver, "vivi");strcpy(cap->card, "vivi");strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));cap->version = VIVI_VERSION;cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \V4L2_CAP_READWRITE;return 0;
}

?

?

總結:ioctl的調用比open、read多了一層,當APP調用ioctl函數時,便會調用cdev里面的ioctl函數,然后調用到了前面我們設置的vfd.fops里的ioctl函數,即和read、open函數同一結構體里的v4l2_ioctl,然后最終再去調用到和??

.fops ? ? ? ? ? = &vivi_fops,同一結構體里的
.ioctl_ops ?? ?= &vivi_ioctl_ops,里對應的函數。

?

?

相關文章:

https://blog.csdn.net/qingkongyeyue/article/details/53447331

https://blog.csdn.net/qingkongyeyue/article/details/52372960

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384507.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384507.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384507.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux下IO多路復用之select函數的使用

select函數的作用: 如果我們的程序里有兩個需要阻塞的地方,例如要從服務器讀數據,同時還要從鍵盤上讀數據(若不采用阻塞而用查詢的方式則大量占用系統資源)。這個時候我們就有兩處阻塞,你當然可以用多線程或…

條件變量實現線程同步

(1) 什么是條件變量實現線程同步?   假如我們的程序中有兩個線程,一個是生產者線程,另一個是消費者線程,生產者線程每隔一段時間把數據寫入到緩沖區buffer中,而消費者線程則每隔一段時間從buffer中取出數據,為了避免…

mjpg-streamer框架分析

mjpg-streamer程框架圖如下所示: 程序運行起來后,主進程根據傳入的參數設置的輸入輸出通道打開對應的輸入輸出動態鏈接庫,并依次調用以下函數 1、輸入---倉庫-----輸出(mjpg-streamer.h) (1)gl…

用strace工具跟蹤系統調用

Linux下可以用strace工具查看應用程序的系統調用。 strace -h 查看能調用的參數 1.strace -o xwatv.log xwatv //-o xwatv.log 是指定將跟蹤信息存放在xwatv.log中,xwatv是指要跟蹤的命令或應用程序 2.把生成的log文件拷貝回windows下進行分析 主要分析open…

linux字符驅動之概念介紹

一、字符驅動框架 問:應用程序open、read、write如何找到驅動程序的open、read、write函數? 答:應用程序的open、read、write是在C庫里面實現的,它里面通過swi val指令去觸發一個異常,這個異常就會進入到內核空間,在內…

linux字符驅動之自動創建設備節點

上一節中,我們是手工創建設備節點,大家肯定也會覺得這樣做太麻煩了。 上一節文章鏈接:https://blog.csdn.net/qq_37659294/article/details/104302700 問:能不能讓系統自動創建設備節點? 答:可以&#x…

linux字符驅動之點亮LED

上一節中,我們講解了如何自動創建設備節點,這一節我們在上一節的基礎上,實現點亮LED。 上一節文章鏈接:https://blog.csdn.net/qq_37659294/article/details/104308284 驅動里面能夠用很多種方法實現LED驅動,其中有本…

USB攝像頭視頻監控項目學習筆記

一個攝像頭監控應用程序的系統調用如下所示: /* open * VIDIOC_QUERYCAP 確定它是否視頻捕捉設備,支持哪種接口(streaming/read,write) * VIDIOC_ENUM_FMT 查詢支持哪種格式 * VIDIOC_S_FMT 設置攝像頭使用哪種格式 * VIDIOC_REQBUFS 申請buffer 對于 str…

圖片縮放算法

項目背景:博主之前做過一個攝像頭采集數據,然后在LCD上顯示視頻數據的項目,假如我們攝像頭采集的一幀數據的分辨率比我們的LCD的分辨率要大,那么LCD則無法顯示整個圖像,這時候我們就要把這么一幀圖片進行縮放&#xff…

數碼相框項目之顯示一張可放大、縮小、拖拽的圖片

之前我做過一個電子相框的項目,涉及到的重難點主要為:在LCD上放大、縮小、移動圖片。 首先我們得明白的一點是:無論是放大或縮小,實際上都是對原圖進行等比例的縮小,然后在LCD上面顯示,只不過縮小的程度不…

TCP協議-如何保證傳輸可靠性

TCP協議傳輸的特點主要就是面向字節流、傳輸可靠、面向連接。這篇博客,我們就重點討論一下TCP協議如何確保傳輸的可靠性的。 確保傳輸可靠性的方式 TCP協議保證數據傳輸可靠性的方式主要有: 校驗和序列號確認應答超時重傳連接管理流量控制擁塞控制 校…

TCP協議-握手與揮手

認識TCP協議 TCP全稱為“傳輸控制協議”,這是傳輸層的一個協議,對數據的傳輸進行一個詳細的控制。 特點: 面向字節流安全可靠面向連接 TCP協議段格式 源端口號與目的端口號:這里與UDP的一樣,每個數據都要知道從哪個…

ASOC注冊過程

一、什么是ASOC 在嵌入式系統里面的聲卡驅動為ASOC(ALSA System on Chip) ,它是在ALSA 驅動程序上封裝的一層,分為3大部分,Machine,Platform和Codec ,三部分的關系如下圖所示:其中Machine是指我…

ASOC調用過程

上一篇文章我們將了嵌入式系統注冊聲卡的過程:https://blog.csdn.net/qq_37659294/article/details/104748747 這篇文章我們以打開一個聲卡的播放節點為例,講解一下在APP調用open時,最終會如何調用到硬件相關的函數。 在上一篇文章最后我們說…

編寫聲卡驅動(框架)

在前面兩篇文章中,我們分別講了嵌入式Linux系統聲卡注冊的過程和調用的過程: https://blog.csdn.net/qq_37659294/article/details/104748747 https://blog.csdn.net/qq_37659294/article/details/104802868 講了那么多,我們最終的目的無非…

聲卡學習筆記

分享幾篇關于韋東山聲卡驅動的學習筆記,作者寫得非常詳細。 ALSA驅動框架:https://blog.csdn.net/qingkongyeyue/article/details/52328991 ASoC驅動框架:https://blog.csdn.net/qingkongyeyue/article/details/52349120 ASoC驅動重要結構…

路由器、交換機、集線器的區別

https://blog.csdn.net/weibo1230123/article/details/82779040

$PATH環境變量的作用

echo $PATH 顯示當前PATH環境變量,該變量的值由一系列以冒號分隔的目錄名組成,如:/usr/local/bin:/bin:/usr/bin。(冒號:是路徑分隔符) 在執行一個程序的時候如果沒有PATH的話,就需要寫出路徑名(絕對或者相對&#xf…

dmesg

https://blog.csdn.net/zm_21/article/details/31760569

進程上下文與中斷上下文的理解

一.什么是內核態和用戶態 內核態:在內核空間執行,通常是驅動程序,中斷相關程序,內核調度程序,內存管理及其操作程序。 用戶態:用戶程序運行空間。 二.什么是進程上下文與中斷上下文 1.進程上下文&#xf…