v4l2視頻驅動中關於vivi.c的個人分析(菜鳥入門,請輕拍!)

來源:互聯網
上載者:User

今天是2013-3-22,在前一段時間看了很多I2C以後(雖然沒有經過什麼實際檢驗,但是感覺還是對I2C有了一點點的瞭解),今天開始來學習學習有關視頻方面的東西。

首先我看的參考入門文檔:

http://zjbintsystem.blog.51cto.com/964211/464729

還有幾個datasheet,如:VPFE、VPBE以及TMS320DigitSubsystem

 

應用程式層是怎麼做的,先參看這個文檔,可以參看這個文檔:

http://www.rosoo.net/a/201001/8382.html

 

我覺得說清楚一個東西,把他的來龍去脈講清楚是比較困難的,但是按照以下幾個方面來講,效果一定不錯:是什麼,為什麼,怎麼樣。記得這是初中政治老師對我說的,但是我覺得在任何地方都是通的。

 

V4L2是什麼:video for linux 2的簡稱吧。所以就變成V4L2了。有2,當然之前有1了,至於未來怎麼樣,有沒有3,這個我就不管了。

 

為什麼要用V4L2:或者說有啥用呢。看這個:

參考文檔:http://dongyulong.blog.51cto.com/1451604/344987

V4L2主要用來搞視頻的。視頻並不是說我加個網路攝影機,然後往我畫的板子上一接,就可以在我的板子的LCD上顯示資料了。那我們要做什麼呢?要讓板子認識外設晶片(比如tvp5146),要對我採集到的視頻資料進行處理(這個是不是屬於應用程式層?)等等工作。V4L2就提供了許多這樣的介面。因為我們網路攝影機不同,板子晶片更不同,所以要有一套可移植的東東。我感覺大概是這樣。(才看兩天,以後有了更深刻的理解,再來補充更改吧。)

 

V4L2有一個重要的標頭檔,大部分文章都會說到:videodev2.h

注釋中都寫了:/**Video for Linux Two header file**/

 

這個標頭檔看的真蛋疼!

文檔:http://blog.csdn.net/hongtao_liu/article/details/5894089

這篇文檔寫的不錯,初步入門值得細看。

 

好幾天沒看了,都不知道該怎麼看了,真蛋疼。

給個連結:http://blog.csdn.net/shui1025701856/article/details/7459868

這個文章裡面說:V4L2驅動對使用者空間提供字元裝置,主裝置號為81,對於視頻裝置,其次裝置號為0-63.初次之外,次裝置號為64-127的radio裝置,次裝置號為192-223的teletext裝置,次裝置號為224-255的VBI裝置。

這個跟我剛才在v4l2-dev.c中看到的是相關的。

minor_offset是位移,minor_cnt表示的是裝置號的count。

即這段:switch (type) {

       case VFL_TYPE_GRABBER:

              minor_offset = 0;

              minor_cnt = 64;

              break;

       case VFL_TYPE_RADIO:

              minor_offset = 64;

              minor_cnt = 64;

              break;

       case VFL_TYPE_VBI:

              minor_offset = 224;

              minor_cnt = 32;

              break;

       default:

              minor_offset = 128;

              minor_cnt = 64;

              break;

       }

這裡並沒有給出192-223這一部分。

 

正如之前看的那個參考文檔中寫的那些:大部分是通過ioctl來進行控制的,而那些命令就定義在include/linux/videodev2.h中。

在命令中用到了一些像_IOR、_IOWR等相關的宏,按照CSDN上一個文章:

http://bbs.csdn.net/topics/240007617描述:是對ioctl命令號的宏轉換定義,用於對命令進行分類。

另外還有這個連結寫的較為詳細:http://www.groad.net/bbs/read.php?tid-1212.html

 

關於V4L2幾個比較重要的檔案為:

Include/linux/videodev2.h

Include/media/v4l2-dev.h

V4L2驅動核心實現檔案:driver/media/video/v4l2-dev.c

//video核心層:drivers/media/video/videodev.c

 

許多文章裡面提到了上面這個檔案videodev.c,在老版的2.x核心中似乎存在這個檔案,但是我是基於3.x核心看的,已經不存在這個檔案了,現在原來存在於其中的函數定義現在都已經在v4l2-dev.h中了,比如video_register_device和video_unregister_device函數。

而V4L2提供的統一的應用程式層的介面都已經實現在v4l2-dev.c檔案中。

static const structfile_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,

};

 

現在以vivi.c和v4l2來分析一下整個過程是如何?的吧。

假設我們現在有應用程式,其中使用了open、close、ioctl等函數。

應用程式層的調用,在核心中會調用到相對應的驅動函數。之前看到說V4L2其實就是又封裝了一層。感覺對這裡說的還不是很理解。

在v4l2-dev.c檔案中,有相應的驅動函數。當應用程式層執行open函數時,核心會執行v4l2_open函數。v4l2_open函數也是定義在v4l2-dev.c檔案中。

 

static int v4l2_open(struct inode *inode, struct file*filp);

傳進的參數為inode節點和檔案指標。

在v4l2_open函數中,定義了struct video_device結構體vdev,並調用video_devdata函數:vdev =video_devdata(filp);獲得視頻裝置結構體。

if(video_is_registered(vdev))

       ret = vdev->fops->open(filp);

如果裝置已經註冊過了,那麼就會去執行vdev->fops->open函數。

 

我們再來看vdev,即struct video_device結構體。

這個結構體的定義在v4l2-dev.h檔案中。

其中,包括:

/* device ops */

       const struct v4l2_file_operations*fops;

關於v4l2的裝置檔案操作集

 

/*sysfs */

       struct device dev;          /* v4ldevice */

       struct cdev *cdev;         /*character device */

在sysfs下建立裝置和字元裝置

 

/* Set either parent or v4l2_dev if your driver uses v4l2_device */

       structdevice *parent;           /* device parent*/

       struct v4l2_device *v4l2_dev;       /* v4l2_device parent */

 

/*ioctl callbacks */

       const struct v4l2_ioctl_ops*ioctl_ops;

關於ioctl的檔案操作函數。

 

在vivi.c中,我載入裝置驅動的時候,會執行module_init(vivi_init);在vivi_init中調用了vivi_create_instance函數。我們來看這個函數:

其中定義了structvideo_device *vfd;

struct vivi_dev *dev(這個應該就是自訂的裝置類型了);

 

在函數中調用函數v4l2_device_register註冊v4l2裝置。

後面:vfd = &dev->vdev;

讓vfd指標指向註冊的v4l2裝置。

 

接下來調用了兩個函數:video_set_drvdata(vfd,dev);

和video_register_device函數。註冊video device。

 

這兩個函數,第一個查到說是設定驅動程式專有資料;第二個函數之前分析過,是註冊video裝置的函數,比如是網路攝影機,或者是VBI裝置等等。

 

那麼回到一開始,現在我們應該就是傳遞了vfd這個參數了。

也就是實際上會執行v4l2_file_operations這個結構體中的相關驅動函數了,在本例中,在vivi.c檔案中有如下定義:

static const struct v4l2_file_operations vivi_fops = {

       .owner           =THIS_MODULE,

       .open           = v4l2_fh_open,

       .release        =vb2_fop_release,

       .read           =vb2_fop_read,

       .poll        =vb2_fop_poll,

       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */

       .mmap           =vb2_fop_mmap,

};

也就是實際上最終會執行v4l2_fh_open這個函數。

 

其餘的release、read、write等也是類似。但是好像ioctl不是一樣的。這裡繼續來分析一下:

我看的是3.6.x核心,跟2.6等核心還是有不少變化的,這個變化有哪些,我也搞不全。

 

當我在應用程式層調用ioctl的時候,在驅動層會調用相應的ioctl函數,但是這裡有點區別,因為在file_operations中我沒看到ioctl的定義,而有:

long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long);

long (*compat_ioctl)(struct file *, unsigned int, unsigned long);

百度之,這兩個跟ioctl的聲明:int(*ioctl)(struct inode *node, struct file *filp,unsigned int cmd, unsigned longarg);相比,主要是缺少了inode參數。

查看到兩個文檔:http://blog.sina.com.cn/s/blog_693301190100vyhh.html

http://blog.csdn.net/cbl709/article/details/7295772

其實沒什麼大的差別,就是參數少了一個而已。核心驅動中,會優先執行unlocked_ioctl函數,如果沒有unlocked_ioctl,那麼就會去執行ioctl函數。應用程式層是沒有差別的。

 

在v4l2-dev.c的v4l2_fops定義中,有:

.unlocked_ioctl = v4l2_ioctl,

#ifdef CONFIG_COMPAT

       .compat_ioctl= v4l2_compat_ioctl32,

#endif

在應用程式層執行ioctl時候,會執行v4l2_ioctl函數。

 

在v4l2_ioctl的函數定義中(仍然在v4l2-dev.c中):

if (video_is_registered(vdev))

       ret= vdev->fops->unlocked_ioctl(filp, cmd, arg);

註冊了video裝置後,會去執行video_device中fops的unlocked_ioctl函數。

 

再看我們的vivi.c檔案:

static const struct v4l2_file_operations vivi_fops = {

       .owner           =THIS_MODULE,

       .open           = v4l2_fh_open,

       .release        = vb2_fop_release,

       .read           =vb2_fop_read,

       .poll        =vb2_fop_poll,

       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */

       .mmap           =vb2_fop_mmap,

};   //之前好像貼過了。

對我們的vivi.c驅動程式來說:也就是會去執行video_ioctl2這個函數。

 

這個video_ioctl2函數是定義在v4l2-ioctl.c檔案中:

long video_ioctl2(structfile *file, unsigned int cmd, unsigned long arg)

{

       return video_usercopy(file, cmd, arg, __video_do_ioctl);

}

百度video_usercopy函數的作用說是將資訊傳送到使用者進程,執行__video_do_ioctl函數。

參考文檔:http://bbs.chinaunix.net/thread-2156911-1-1.html

 

跟蹤__video_do_ioctl函數:

static long__video_do_ioctl(struct file *file, unsigned int cmd, void *arg)

其中:struct video_device *vfd = video_devdata(file);

       const struct v4l2_ioctl_ops*ops = vfd->ioctl_ops;

也就是說;我在應用程式層執行ioctl時,一開始執行video_ioctl2函數,並傳遞file檔案指標,實際上調用了__video_do_ioctl函數,並實際上是執行了video_device中ioctl_ops的函數操作,也就是相應的v4l2-ioctl-ops函數操作。

 

在vivi.c中,有:

static const struct v4l2_ioctl_ops vivi_ioctl_ops = {

       .vidioc_querycap      =vidioc_querycap,

       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,

       .vidioc_g_fmt_vid_cap    = vidioc_g_fmt_vid_cap,

       .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,

       .vidioc_s_fmt_vid_cap    = vidioc_s_fmt_vid_cap,

       .vidioc_reqbufs       =vb2_ioctl_reqbufs,

       .vidioc_create_bufs   =vb2_ioctl_create_bufs,

       .vidioc_prepare_buf   =vb2_ioctl_prepare_buf,

       .vidioc_querybuf      =vb2_ioctl_querybuf,

       .vidioc_qbuf          =vb2_ioctl_qbuf,

       .vidioc_dqbuf         =vb2_ioctl_dqbuf,

       .vidioc_enum_input    = vidioc_enum_input,

       .vidioc_g_input       = vidioc_g_input,

       .vidioc_s_input       =vidioc_s_input,

       .vidioc_streamon      =vb2_ioctl_streamon,

       .vidioc_streamoff     =vb2_ioctl_streamoff,

       .vidioc_log_status    = v4l2_ctrl_log_status,

       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,

       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,

};

這個就對應了應用程式中的那些擷取視頻capability、開啟streamon、streamoff等命令吧。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.