0 引言

初学者代码学习,感谢指正。

我们介绍v4l2的整体框架,整体框架从何而来,肯定是要看数据结构。看数据结构是如何关联的。就能知道v4l2的大体框架。

首先明确一个大体方向:
v4l2是主题,media_controller只是一个管理拓扑的工具,即使没有它,也能正常工作。它的主要作用,是帮忙链接整条链路,看看数据链是否打通。一般是__media_start_pipeline函数。

1 结构体

在这里插入图片描述
这里是几个核心结构体,他们通过如图所示的链表相互关联。能看到,基本都挂载到了v4l2-device这个结构体上,所以它是老大,也是最顶层的结构体。v4l2框架,实际就是围绕着它进行注册。

2 v4l2_device

struct v4l2_device {
    struct device *dev;
    struct media_device *mdev;
    struct list_head subdevs;
    spinlock_t lock;
    char name[V4L2_DEVICE_NAME_SIZE];
    void (*notify)(struct v4l2_subdev *sd,
            unsigned int notification, void *arg);
    struct v4l2_ctrl_handler *ctrl_handler;
    struct v4l2_prio_state prio;
    struct kref ref;
    void (*release)(struct v4l2_device *v4l2_dev);
};

它里面的核心是:
struct media_device *mdev;
struct list_head subdevs;
struct list_head subdevs,里面挂载了v4l2所有的子设备,当需要使用子系统的函数时,使用v4l2-call_xxx,即可调用。subdev里的const struct v4l2_subdev_ops *ops; 字段,即是这个subdev所支持的回调函数。

3 subdev

struct v4l2_subdev_ops {
    const struct v4l2_subdev_core_ops   *core;
    const struct v4l2_subdev_tuner_ops  *tuner;
    const struct v4l2_subdev_audio_ops  *audio;
    const struct v4l2_subdev_video_ops  *video;
    const struct v4l2_subdev_vbi_ops    *vbi;
    const struct v4l2_subdev_ir_ops     *ir;
    const struct v4l2_subdev_sensor_ops *sensor;
    const struct v4l2_subdev_pad_ops    *pad;
};

struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
    struct media_entity entity;
#endif
    struct list_head list;
    struct module *owner;
    bool owner_v4l2_dev;
    u32 flags;
    struct v4l2_device *v4l2_dev;
    const struct v4l2_subdev_ops *ops;
    const struct v4l2_subdev_internal_ops *internal_ops;
    struct v4l2_ctrl_handler *ctrl_handler;
    char name[V4L2_SUBDEV_NAME_SIZE];
    u32 grp_id;
    void *dev_priv;
    void *host_priv;
    struct video_device *devnode;
    struct device *dev;
    struct fwnode_handle *fwnode;
    struct list_head async_list;
    struct v4l2_async_subdev *asd;
    struct v4l2_async_notifier *notifier;
    struct v4l2_async_notifier *subdev_notifier;
    struct v4l2_subdev_platform_data *pdata;
    struct mutex *state_lock;
    /*
     * The fields below are private, and should only be accessed via
     * appropriate functions.
     */
    /*
     * TODO: active_state should most likely be changed from a pointer to an
     * embedded field. For the time being it's kept as a pointer to more
     * easily catch uses of active_state in the cases where the driver
     * doesn't support it.
     */
    struct v4l2_subdev_state *active_state;
};

V4L2中,为了使得多个子设备级联,创建了subdev结构体,里面的核心成员:
const struct v4l2_subdev_ops *ops;
const struct v4l2_subdev_internal_ops *internal_ops;
在创建subdev的时候,需要实现这两个函数指针,如 2所说,

当需要使用子系统的函数时,使用v4l2-call_xxx,即可调用。subdev里的const struct v4l2_subdev_ops *ops; 字段。

4 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;
};

struct subdev里,有一个* devnode指针,video_device通过它挂靠到v4l2_subdev里,它的核心功能,是数据的转运,以及向用户空间暴露/dev/videox设备文件。用户的所有操作,其实都是操作它。在v4l2-dev.c里,就是实现这个函数注册的的核心文件。里面的__video_reigser_device,注册了/dev/videox,以及提供了用户空间的ioctl(cmd)的分发。

4.1 videobuf

管理整个videobuf的是,

struct vb2_buffer {

    struct list_head    queued_entry;
    struct list_head    done_entry;
}

结构体。而vb2_queue *queue 才是实际干活的。

这个指针,指向实际的video_buf,负责整个数据的转运。一般会在申请的中断里,传输完成后,执行 vb2_buffer_done,标记完成,这时,完成的buf会挂载到 struct list_head done_entry; 里,这时,用户层就能收到完成的buf,取出数据了。

5 media_controller

5.1 media_device

media_controller一般以media_entity挂靠在v4l2_subdev里。而media_entity被media_device所管理。而v4l2_device又能被v4l2_device来索引到。这也正好论证了我们之前的绪论,v4l2-device来管理所有的子组件,它是骨架。

struct media_device{
	struct list_head entities;
	struct list_head pads;
	struct list_head links;
}

media_device的核心,就是上面三个链表,来管理所有的entity,pads,links。我们先来看entity。

5.2 media_entity

struct media_entity {
    struct media_gobj graph_obj;    /* must be first field in struct */
    const char *name;
    enum media_entity_type obj_type;
    u32 function;
    unsigned long flags;
    u16 num_pads;
    u16 num_links;
    u16 num_backlinks;
    int internal_idx;
    struct media_pad *pads;
    struct list_head links;
    const struct media_entity_operations *ops;
    int use_count;
    struct media_pipeline *pipe;
    union {
        struct {
            u32 major;
            u32 minor;
        } dev;
    } info;
};

entity里定义了标准的graph_obj,定义meida_entity的基础组件。然后就是pads和links。分别代表他们的功能和链接。

media_device又两个总的链表,来管理全部的pads和links。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐