V4L2学习笔记
+ -

V4L2框架之v4l2_open

2024-03-05 244 0

V4L2整体框架如下图:
V4L2整体

图片来源于http://blog.csdn.net/leesagacious/article/details/49948163

其整体驱动框架分为三个层次:
第一个层为字符设备驱动程序,主要是上层应用创建视频设备节点。这一层是整个V4L2层框架的外包接口,应用层通过API函数之后,最先进入的是字符设备驱动的fops。字符设备驱动程序由V4L2框架统一管理,其使用这个字符设备提供统一的外包接口。
第二层是V4L2核心层,其核心是video_device设备,其完成了视上尖设备的核心抽象。
第三层是V4L2的下层回调接口,是与硬件相关的。

其实本人对此的理解相是:第一层的字符设备类似于windows的direct show,第二层为ks层,第三层为具体的物理设备驱动,如usbvideo.sys。

V4L2设备初始化可详见:https://www.usbzh.com/article/detail-166.html 其核心是通过uvc_register_video_device注册视频设备。其结构体如下:

  1. struct video_device
  2. {
  3. #if defined(CONFIG_MEDIA_CONTROLLER)
  4. struct media_entity entity;
  5. struct media_intf_devnode *intf_devnode;
  6. struct media_pipeline pipe;
  7. #endif
  8. const struct v4l2_file_operations *fops;
  9. u32 device_caps;
  10. /* sysfs */
  11. struct device dev;
  12. struct cdev *cdev; //
  13. struct v4l2_device *v4l2_dev;
  14. struct device *dev_parent;
  15. struct v4l2_ctrl_handler *ctrl_handler;
  16. struct vb2_queue *queue;
  17. struct v4l2_prio_state *prio;
  18. /* device info */
  19. char name[32];
  20. enum vfl_devnode_type vfl_type;
  21. enum vfl_devnode_direction vfl_dir;
  22. int minor;
  23. u16 num;
  24. unsigned long flags;
  25. int index;
  26. /* V4L2 file handles */
  27. spinlock_t fh_lock;
  28. struct list_head fh_list;
  29. int dev_debug;
  30. v4l2_std_id tvnorms;
  31. /* callbacks */
  32. void (*release)(struct video_device *vdev);
  33. const struct v4l2_ioctl_ops *ioctl_ops;
  34. DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
  35. struct mutex *lock;
  36. };

其字符设备在uvc_register_video_device中初始化如下:

  1. vdev->cdev = cdev_alloc();
  2. if (vdev->cdev == NULL) {
  3. ret = -ENOMEM;
  4. goto cleanup;
  5. }
  6. vdev->cdev->ops = &v4l2_fops;
  7. vdev->cdev->owner = owner;
  8. ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);

可见,其字符设备结构体是动态申请创建,其对应的OPS为v4l2_fops

  1. static const struct file_operations v4l2_fops = {
  2. .owner = THIS_MODULE,
  3. .read = v4l2_read,
  4. .write = v4l2_write,
  5. .open = v4l2_open,
  6. .get_unmapped_area = v4l2_get_unmapped_area,
  7. .mmap = v4l2_mmap,
  8. .unlocked_ioctl = v4l2_ioctl,
  9. #ifdef CONFIG_COMPAT
  10. .compat_ioctl = v4l2_compat_ioctl32,
  11. #endif
  12. .release = v4l2_release,
  13. .poll = v4l2_poll,
  14. .llseek = no_llseek,
  15. };

这就是V4L2视频设备对应用层的外包接口。

video_device全局数组与索引minor

在Windows内核中,设备一般是通过LIST_ENTRY链接在,但在Linux这就随其框架决定的。在V4L2中他其实就是一个数组,数组的索引就是vdev->minor

  1. #define VIDEO_NUM_DEVICES 256
  2. static struct video_device *video_devices[VIDEO_NUM_DEVICES];

而数组的索引就是vdev->minor

  1. video_devices[vdev->minor] = vdev;

而这个minor的来源于视频分类中查找一个空的索引。

  1. #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
  2. /* Keep the ranges for the first four types for historical
  3. * reasons.
  4. * Newer devices (not yet in place) should use the range
  5. * of 128-191 and just pick the first free minor there
  6. * (new style). */
  7. switch (type) {
  8. case VFL_TYPE_GRABBER:
  9. minor_offset = 0;
  10. minor_cnt = 64;
  11. break;
  12. case VFL_TYPE_RADIO:
  13. minor_offset = 64;
  14. minor_cnt = 64;
  15. break;
  16. case VFL_TYPE_VBI:
  17. minor_offset = 224;
  18. minor_cnt = 32;
  19. break;
  20. default:
  21. minor_offset = 128;
  22. minor_cnt = 64;
  23. break;
  24. }
  25. #endif
  26. /* Pick a device node number */
  27. mutex_lock(&videodev_lock);
  28. nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
  29. if (nr == minor_cnt)
  30. nr = devnode_find(vdev, 0, minor_cnt);
  31. if (nr == minor_cnt) {
  32. pr_err("could not get a free device node number\n");
  33. mutex_unlock(&videodev_lock);
  34. return -ENFILE;
  35. }
  36. #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
  37. /* 1-on-1 mapping of device node number to minor number */
  38. i = nr;
  39. #else
  40. /* The device node number and minor numbers are independent, so
  41. we just find the first free minor number. */
  42. for (i = 0; i < VIDEO_NUM_DEVICES; i++)
  43. if (video_devices[i] == NULL)
  44. break;
  45. if (i == VIDEO_NUM_DEVICES) {
  46. mutex_unlock(&videodev_lock);
  47. pr_err("could not get a free minor\n");
  48. return -ENFILE;
  49. }
  50. #endif
  51. vdev->minor = i + minor_offset;

v4l2_open

最后我们查看字符设备的v4l2_open

  1. static int v4l2_open(struct inode *inode, struct file *filp)
  2. {
  3. struct video_device *vdev;
  4. int ret = 0;
  5. /* Check if the video device is available */
  6. mutex_lock(&videodev_lock);
  7. vdev = video_devdata(filp);
  8. /* return ENODEV if the video device has already been removed. */
  9. if (vdev == NULL || !video_is_registered(vdev)) {
  10. mutex_unlock(&videodev_lock);
  11. return -ENODEV;
  12. }
  13. /* and increase the device refcount */
  14. video_get(vdev);
  15. mutex_unlock(&videodev_lock);
  16. if (vdev->fops->open) {
  17. if (video_is_registered(vdev))
  18. ret = vdev->fops->open(filp);
  19. else
  20. ret = -ENODEV;
  21. }
  22. if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
  23. dprintk("%s: open (%d)\n",
  24. video_device_node_name(vdev), ret);
  25. /* decrease the refcount in case of an error */
  26. if (ret)
  27. video_put(vdev);
  28. return ret;
  29. }

其就是通过minor使用video_devdata函数查找到对应的video_device

  1. static inline struct inode *file_inode(const struct file *f)
  2. {
  3. return f->f_inode;
  4. }
  5. static inline unsigned iminor(const struct inode *inode)
  6. {
  7. return MINOR(inode->i_rdev);
  8. }
  9. struct video_device *video_devdata(struct file *file)
  10. {
  11. return video_devices[iminor(file_inode(file))];
  12. }

最后将打开操作向下传递到vdev的open。

  1. if (vdev->fops->open) {
  2. if (video_is_registered(vdev))
  3. ret = vdev->fops->open(filp);
  4. else
  5. ret = -ENODEV;
  6. }

0 篇笔记 写笔记

Linux V4L2 UVC摄像头框架浅析
V4L2 :video for linux version 2 ,是 Linux 里一套标准的视频驱动,它支持 UVC 标准的摄像头。本文来分析一下它的核心框架。整个v4l2的框架分为三层:在应用层,我们可以在 /dev 目录发现 video0 类似的设备节点,上层的摄像头程序打开设备节点进行......
V4L2访问摄像头扩展单元命令
我们可以通过IOCTL访问扩展单元,调用方法如下:ioctl(fd, UVCIOC_CTRL_QUERY, struct uvc_xu_control_query *);访问不同的扩展命令只需要修改uvc_xu_control_query 结构体里面内容即可。uvc_xu_control_qu......
Linux系统V4L2访问UVC摄像头扩展单元命令
我们可以通过IOCTL访问扩展单元,调用方法如下:ioctl(fd, UVCIOC_CTRL_QUERY, struct uvc_xu_control_query *);访问不同的扩展命令只需要修改uvc_xu_control_query 结构体里面内容即可。uvc_xu_control_qu......
Linux打开V4L2摄像头并存储Camera数据流
Linux系统下打开UVC摄像头,并将从CAMERA读取到的数据存储在文件中。源代码版权归老吕、所有。感谢老吕、的无私贡献。v4l2_capture_demo.c#include #include #include
V4L2整体框架如下图:图片来源于http://blog.csdn.net/leesagacious/article/details/49948163其整体驱动框架分为三个层次:第一个层为字符设备驱动程序,主要是上层应用创建视频设备节点。这一层是整个V4L2层框架的外包接口,应用层通过API......
LINUX关于相机涉及到的东西有:V4L2 框架UVC驱动V4L2是视频的通用框架,其下可支持各类总线设备,如pci,i2c,usb等各种总线类型。其目录位于:E:linux-5.6.11linux-5.6.11driversdriversmedia在USB总线框架下,其使用的是......
以下内容仅代表个人观点,有很大概率不准确。作业初学者,仅为学习笔记而已,勿全当真。但本人会随着认识而修正本文错误的观点。Windows系统有驱动层级结构,Linux应该也有。作为初学者,需要多读多学,并对新学的知识进行总结。本人根据自己的理解对Linux系统UVC驱动栈进行绘制图。最底层的......
从 Linux&UVC驱动栈 https://www.usbzh.com/article/detail-1322.html 一文可知,UVC驱动其实是一个中间层驱动程序,其启着承上启下的功能。在UVC驱动的下层是USBCore驱动,其实现的是USB设备初始化及通讯相关的功能实现。在UVC......
在 Linux 内核中,针对视频设备的驱动一般会使用 Video4Linux2(V4L2)接口。在 V4L2 中,ioctl 是一个用于设备控制的系统调用,用来发送各种命令给设备驱动程序。对于 UVC(USB Video Class)摄像头的驱动,通常会使用 uvc_v4l2.c 这个文件。uvc......
VIDIOC_QUERYCAP请求使用api函数ioctl,最终进行LINUX&UVC驱动中,根据设备节点的不同,执行的回调函数不同。VIDIOC_QUERYCAP请求用于返回设备支持的功能属性信息,其对应的结构体v4l2_capability。struct v4l2_capabilit......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    您的支持,是我们前进的动力!