本文均屬自己閱讀源碼的點(diǎn)滴總結(jié),轉(zhuǎn)賬請(qǐng)注明出處謝謝。 歡迎和大家交流。qq:1037701636 email:gzzaigcn2012@gmail.com
前沿:2014年的博文就從這篇文章開(kāi)始吧,又一次回到linux,過(guò)去的一年從dm3730再到dm6437,這次來(lái)到了全志的A31 4核處理器,每一次都是全新的事物,但是偶然間還是可以感受到對(duì)新事物的消化能力更強(qiáng)了,學(xué)習(xí)的速度也更快了。也許這正是所謂的經(jīng)驗(yàn),所謂的軟實(shí)力吧。
linux下的視頻v4l2在很久之前的博文DM6446的視頻前端VPFE的驅(qū)動(dòng)大框架解析等幾篇中介紹了整個(gè)基于應(yīng)用層的視頻采集流程解析。由于最近再次看了3.3的內(nèi)核版本后,有了更進(jìn)一步的收獲,和大家在這里分享。
1.V4L2 驅(qū)動(dòng)中的核心結(jié)構(gòu)體 v4l2_device;一個(gè)v4l2的總設(shè)備。 v4l2_sbudev:來(lái)描述camera等sensor設(shè)備,一般是指掛接在總線(xiàn)(i2c)上的攝像頭 video_device:實(shí)際和處理器采集口相關(guān)的配置,一般該設(shè)備會(huì)完成注冊(cè)以/dev/video0,video1的字符設(shè)備注冊(cè)的形式暴露給應(yīng)用層。
video_device的重要性在于它具備承上啟下的作用,驅(qū)動(dòng)實(shí)現(xiàn)的ioctl內(nèi)容,剛好則是為用戶(hù)的控制提供了內(nèi)核的實(shí)現(xiàn)。當(dāng)然內(nèi)核ioctl向下又是能控制相關(guān)的vfe和sensor,如下 static struct video_device vfe_template = { .name = "vfe", .fops = &vfe_fops, //用戶(hù)open的相關(guān)內(nèi)容 .ioctl_ops = &vfe_ioctl_ops,//用戶(hù)ioctl對(duì)應(yīng)的相關(guān)內(nèi)容 .release = video_device_release, };
static const struct v4l2_file_operations vfe_fops = { .owner = THIS_MODULE, .open = vfe_open, .release = vfe_close, .read = vfe_read, .poll = vfe_poll, .ioctl = video_ioctl2, //最終會(huì)調(diào)用v4l2_ioctl_ops這個(gè)實(shí)際處理器的相關(guān)處理邏輯 // //.unlocked_ioctl = .mmap = vfe_mmap, }; static const struct v4l2_ioctl_ops vfe_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_enum_framesizes = vidioc_enum_framesizes, .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 = vidioc_reqbufs,//video buffer緩存申請(qǐng) .vidioc_querybuf = vidioc_querybuf,//查詢(xún)buffer屬性,完成對(duì)用戶(hù)v4l2的設(shè)置,為mmap做準(zhǔn)備 .vidioc_qbuf = vidioc_qbuf,//入列 .vidioc_dqbuf = vidioc_dqbuf,//出列 .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_streamon = vidioc_streamon,//啟動(dòng)視頻采集 .vidioc_streamoff = vidioc_streamoff, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm, #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif }; video_device除了實(shí)現(xiàn)對(duì)基本的視頻端口的硬件初始化,還完成對(duì)相關(guān)的視頻采集緩存區(qū)的維護(hù),通過(guò)queue來(lái)維護(hù)采集邏輯,通過(guò)中斷來(lái)觸發(fā)處理。
2.視頻采集的最底層部分當(dāng)然是外設(shè)camera 不同的camera有不同的驅(qū)動(dòng),但是他都凌駕在i2c的控制器上。故實(shí)現(xiàn)camera的驅(qū)動(dòng),通常都是實(shí)現(xiàn)i2c_driver和i2c_client的相關(guān)內(nèi)容。這里相關(guān)的i2c_adapter(和處理器自己的i2c總線(xiàn)特性相關(guān),比如A31有4路i2c,故有4個(gè) adapter),相關(guān)內(nèi)容可以看博文Linux下DM644x設(shè)備驅(qū)動(dòng)I2C之總線(xiàn)驅(qū)動(dòng)(一)詳解。 比如camera ov5640的驅(qū)動(dòng)架構(gòu)很簡(jiǎn)單,但是為了和專(zhuān)門(mén)的視頻采集掛接在一起,他作為i2c_client的同時(shí)也是v4l2_sbudev子設(shè)備。 static const struct v4l2_subdev_ops sensor_ops = { .core = &sensor_core_ops, .video = &sensor_video_ops, }; 這個(gè)結(jié)構(gòu)體是作為v4l2子設(shè)備的op,會(huì)通過(guò)video device的ioctl來(lái)調(diào)用實(shí)現(xiàn)。 在video的驅(qū)動(dòng)中,可以看到如下API: v4l2_i2c_new_subdev_b oard():生成一個(gè)新的i2c的v4l2子設(shè)備,內(nèi)部核心:是建立一個(gè)i2c_board_info(表明板級(jí)上的一個(gè)i2c client),并將其完成設(shè)備的注冊(cè),這會(huì)調(diào)用對(duì)應(yīng)的camera驅(qū)動(dòng)的probe函數(shù)。這里會(huì)調(diào)用函數(shù): v4l2_i2c_subdev_init(sd, client, &sensor_ops);//subdevice建立,與i2c client建立聯(lián)系。 從上面的這個(gè)API的實(shí)現(xiàn),建立了subdev和client的關(guān)系后,video這邊就可以通過(guò)用戶(hù)傳入的ioctl命令來(lái)對(duì)subdev進(jìn)行控制如: v4l2_subdev_call內(nèi)部會(huì)調(diào)用i2c_client的驅(qū)動(dòng)處理即上文中的sensor_ops中的core和video過(guò)程。
到此為止,video device,subdev, sensor之間的關(guān)系基本理通,調(diào)用的順序合理而且緊密,如下圖所示。 圖1: A31 linux內(nèi)核視頻采集驅(qū)動(dòng)架構(gòu)
|
|
來(lái)自: barry525 > 《全志攝像頭數(shù)據(jù)流》