本文均屬自己閱讀源碼的點滴總結,轉賬請注明出處謝謝。
歡迎和大家交流。qq:1037701636 email:[email protected]
前沿:2014年的博文就從這篇文章開始吧,又一次回到linux,過去的一年從dm3730再到dm6437,這次來到了全志的A31 4核處理器,每一次都是全新的事物,但是偶然間還是可以感受到對新事物的消化能力更強了,學習的速度也更快了。也許這正是所謂的經驗,所謂的軟實力吧。
linux下的視訊v4l2在很久之前的博文DM6446的視訊前端VPFE的驅動大架構解析等幾篇中介紹了整個基于應用層的視訊采集流程解析。由于最近再次看了3.3的核心版本後,有了更進一步的收獲,和大家在這裡分享。
1.V4L2 驅動中的核心結構體
v4l2_device;一個v4l2的總裝置。
v4l2_sbudev:來描述camera等sensor裝置,一般是指挂接在總線(i2c)上的攝像頭
video_device:實際和處理器采集口相關的配置,一般該裝置會完成注冊以/dev/video0,video1的字元裝置注冊的形式暴露給應用層。
video_device的重要性在于它具備承上啟下的作用,驅動實作的ioctl内容,剛好則是為使用者的控制提供了核心的實作。當然核心ioctl向下又是能控制相關的vfe和sensor,如下
static struct video_device vfe_template = {
.name = "vfe",
.fops = &vfe_fops, //使用者open的相關内容
.ioctl_ops = &vfe_ioctl_ops,//使用者ioctl對應的相關内容 .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, //最終會調用v4l2_ioctl_ops這個實際處理器的相關處理邏輯 // //.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緩存申請
.vidioc_querybuf = vidioc_querybuf,//查詢buffer屬性,完成對使用者v4l2的設定,為mmap做準備
.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,//啟動視訊采集
.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除了實作對基本的視訊端口的硬體初始化,還完成對相關的視訊采集緩存區的維護,通過queue來維護采集邏輯,通過中斷來觸發處理。
2.視訊采集的最底層部分當然是外設camera
不同的camera有不同的驅動,但是他都淩駕在i2c的控制器上。故實作camera的驅動,通常都是實作i2c_driver和i2c_client的相關内容。這裡相關的i2c_adapter(和處理器自己的i2c總線特性相關,比如A31有4路i2c,故有4個 adapter),相關内容可以看博文Linux下DM644x裝置驅動I2C之總線驅動(一)詳解。
比如camera ov5640的驅動架構很簡單,但是為了和專門的視訊采集挂接在一起,他作為i2c_client的同時也是v4l2_sbudev子裝置。
static const struct v4l2_subdev_ops sensor_ops = {
.core = &sensor_core_ops,
.video = &sensor_video_ops,
};
這個結構體是作為v4l2子裝置的op,會通過video device的ioctl來調用實作。
在video的驅動中,可以看到如下API:
v4l2_i2c_new_subdev_b oard():生成一個新的i2c的v4l2子裝置,内部核心:是建立一個i2c_board_info(表明闆級上的一個i2c client),并将其完成裝置的注冊,這會調用對應的camera驅動的probe函數。這裡會調用函數:
v4l2_i2c_subdev_init(sd, client, &sensor_ops);//subdevice建立,與i2c client建立聯系。
從上面的這個API的實作,建立了subdev和client的關系後,video這邊就可以通過使用者傳入的ioctl指令來對subdev進行控制如:
v4l2_subdev_call内部會調用i2c_client的驅動處理即上文中的sensor_ops中的core和video過程。
到此為止,video device,subdev, sensor之間的關系基本理通,調用的順序合理而且緊密,如下圖所示。
圖1: A31 linux核心視訊采集驅動架構