视频传输方式一: 以 IIC 协议, 通过 IO 口传输视频流:
视频传输方式二: 以 usb 接口传输视频流:
驱动: 字符设备驱动
怎么写驱动程序: 构造 file_operations
告诉内核
入口函数
出口函数
硬件相关层:
1, 将 usb 摄像头设备插到装有虚拟机的 pc 上, dmesg 会打印出一些发现 usb 摄像头设备的信息, 在内核中 grep 找到打印信息的具体位置;
2, 查找打印信息
3, 用 source insight 或其他阅读软件打开 uvc_driver.c 文件
- 3.1 -->struct uvc_driver
- --> uvc_probe:
- v4l2_device_register
- uvc_register_chains ---uvc_register_video--video_device video_register_device
- ---struct video_device *vdev;
- struct uvc_device *dev,
- vdev->v4l2_dev = &dev->vdev;
- vdev->fops = &uvc_fops;
- media_device_register
4, 在内核中有 v4l2-framework.txt 文档可以参考
5, 可以分析虚拟摄像头驱动: vivi.c
vivi_init-->vivi_create_instance-->video_device_alloc-->video_register_device-->__video_register_device-->vdev->cdev = cdev_alloc();--> cdev_add()
6, 在内核中已经提供了 file_operations v4l2_fops 的一些基本函数, 所以我们不需要写字符设备函数. 当应用层调用 ioctl 函数时, 调用 file_operations 中的 ioctl---.unlocked_ioctl = v4l2_ioctl,
- v4l2_ioctl------
- if (video_is_registered(vdev))
- ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
如果 video_device 已经被注册了, 就调用 video_device 里面的 fops 函数里面的 unlocked_ioctl 函数.
而 unlocked_ioctl 函数内核中已经写好了, 我们不需要再写 ---video_usercopy
- ----cmd_input_size(cmd);
- ----check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr);
---- 得到我们想要的
- static unsigned long cmd_input_size(unsigned int cmd)
- {
- /* Size of structure up to and including 'field' */
- #define CMDINSIZE(cmd, type, field) case VIDIOC_##cmd: return offsetof(struct v4l2_##type, field) + sizeof(((struct v4l2_##type *)0)->field);
- switch (cmd) {
- CMDINSIZE(ENUM_FMT, fmtdesc, type);
- CMDINSIZE(G_FMT, format, type);
- CMDINSIZE(QUERYBUF, buffer, length);
- CMDINSIZE(G_PARM, streamparm, type);
- CMDINSIZE(ENUMSTD, standard, index);
- CMDINSIZE(ENUMINPUT, input, index);
- CMDINSIZE(G_CTRL, control, id);
- CMDINSIZE(G_TUNER, tuner, index);
- CMDINSIZE(QUERYCTRL, queryctrl, id);
- CMDINSIZE(QUERYMENU, querymenu, index);
- CMDINSIZE(ENUMOUTPUT, output, index);
- CMDINSIZE(G_MODULATOR, modulator, index);
- CMDINSIZE(G_FREQUENCY, frequency, tuner);
- CMDINSIZE(CROPCAP, cropcap, type);
- CMDINSIZE(G_CROP, crop, type);
- CMDINSIZE(ENUMAUDIO, audio, index);
- CMDINSIZE(ENUMAUDOUT, audioout, index);
- CMDINSIZE(ENCODER_CMD, encoder_cmd, flags);
- CMDINSIZE(TRY_ENCODER_CMD, encoder_cmd, flags);
- CMDINSIZE(G_SLICED_VBI_CAP, sliced_vbi_cap, type);
- CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
- CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
- default:
- return _IOC_SIZE(cmd);
- }
- }
和
- static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
- void * __user *user_ptr, void ***kernel_ptr)
- {
- int ret = 0;
- switch (cmd) {
- case VIDIOC_QUERYBUF:
- case VIDIOC_QBUF:
- case VIDIOC_DQBUF: {
- struct v4l2_buffer *buf = parg;
- if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length> 0) {
- if (buf->length> VIDEO_MAX_PLANES) {
- ret = -EINVAL;
- break;
- }
- *user_ptr = (void __user *)buf->m.planes;
- *kernel_ptr = (void *)&buf->m.planes;
- *array_size = sizeof(struct v4l2_plane) * buf->length;
- ret = 1;
- }
- break;
- }
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS: {
- struct v4l2_ext_controls *ctrls = parg;
- if (ctrls->count != 0) {
- if (ctrls->count> V4L2_CID_MAX_CTRLS) {
- ret = -EINVAL;
- break;
- }
- *user_ptr = (void __user *)ctrls->controls;
- *kernel_ptr = (void *)&ctrls->controls;
- *array_size = sizeof(struct v4l2_ext_control)
- * ctrls->count;
- ret = 1;
- }
- break;
- }
- }
- return ret;
- }
7, 用 strace 可以获得程序执行过程中的系统调用
strace -o xawtv.log xawtv
xawtv 所涉及的系统调用就会记录在 xawtv.log 中
视频传输
来源: http://www.bubuko.com/infodetail-3148392.html