V4L2学习笔记
+ -

V4L2框架之v4l2_open

2024-03-05 79 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注册视频设备。其结构体如下:


struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER)
    struct media_entity entity;
    struct media_intf_devnode *intf_devnode;
    struct media_pipeline pipe;
#endif
    const struct v4l2_file_operations *fops;

    u32 device_caps;

    /* sysfs */
    struct device dev;
    struct cdev *cdev; //

    struct v4l2_device *v4l2_dev;
    struct device *dev_parent;

    struct v4l2_ctrl_handler *ctrl_handler;

    struct vb2_queue *queue;

    struct v4l2_prio_state *prio;

    /* device info */
    char name[32];
    enum vfl_devnode_type vfl_type;
    enum vfl_devnode_direction vfl_dir;
    int minor;
    u16 num;
    unsigned long flags;
    int index;

    /* V4L2 file handles */
    spinlock_t        fh_lock;
    struct list_head    fh_list;

    int dev_debug;

    v4l2_std_id tvnorms;

    /* callbacks */
    void (*release)(struct video_device *vdev);
    const struct v4l2_ioctl_ops *ioctl_ops;
    DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);

    struct mutex *lock;
};

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

vdev->cdev = cdev_alloc();
    if (vdev->cdev == NULL) {
        ret = -ENOMEM;
        goto cleanup;
    }
    vdev->cdev->ops = &v4l2_fops;
    vdev->cdev->owner = owner;
    ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);

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

static const struct file_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,
};

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

video_device全局数组与索引minor

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

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

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

    video_devices[vdev->minor] = vdev;

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

#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
    /* Keep the ranges for the first four types for historical
     * reasons.
     * Newer devices (not yet in place) should use the range
     * of 128-191 and just pick the first free minor there
     * (new style). */
    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;
    }
#endif

    /* Pick a device node number */
    mutex_lock(&videodev_lock);
    nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
    if (nr == minor_cnt)
        nr = devnode_find(vdev, 0, minor_cnt);
    if (nr == minor_cnt) {
        pr_err("could not get a free device node number\n");
        mutex_unlock(&videodev_lock);
        return -ENFILE;
    }
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
    /* 1-on-1 mapping of device node number to minor number */
    i = nr;
#else
    /* The device node number and minor numbers are independent, so
       we just find the first free minor number. */
    for (i = 0; i < VIDEO_NUM_DEVICES; i++)
        if (video_devices[i] == NULL)
            break;
    if (i == VIDEO_NUM_DEVICES) {
        mutex_unlock(&videodev_lock);
        pr_err("could not get a free minor\n");
        return -ENFILE;
    }
#endif
vdev->minor = i + minor_offset;

v4l2_open

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

static int v4l2_open(struct inode *inode, struct file *filp)
{
    struct video_device *vdev;
    int ret = 0;

    /* Check if the video device is available */
    mutex_lock(&videodev_lock);
    vdev = video_devdata(filp);
    /* return ENODEV if the video device has already been removed. */
    if (vdev == NULL || !video_is_registered(vdev)) {
        mutex_unlock(&videodev_lock);
        return -ENODEV;
    }
    /* and increase the device refcount */
    video_get(vdev);
    mutex_unlock(&videodev_lock);
    if (vdev->fops->open) {
        if (video_is_registered(vdev))
            ret = vdev->fops->open(filp);
        else
            ret = -ENODEV;
    }

    if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
        dprintk("%s: open (%d)\n",
            video_device_node_name(vdev), ret);
    /* decrease the refcount in case of an error */
    if (ret)
        video_put(vdev);
    return ret;
}

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

static inline struct inode *file_inode(const struct file *f)
{
    return f->f_inode;
}
static inline unsigned iminor(const struct inode *inode)
{
    return MINOR(inode->i_rdev);
}


struct video_device *video_devdata(struct file *file)
{
    return video_devices[iminor(file_inode(file))];
}

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

    if (vdev->fops->open) {
        if (video_is_registered(vdev))
            ret = vdev->fops->open(filp);
        else
            ret = -ENODEV;
    }

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......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

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

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