文章目录
-
- 1、preface
- 2、V4L2、Subdev和media关系概述
-
- 1)总体关系
- 2)在V4L2系统中的subdev
- 3)使用media来组织各个subdev驱动程序
- 4)总体拓扑图
- [5)v4l2_device 、subdev、media_device结构图](#5)v4l2_device 、subdev、media_device结构图)
- 6)APP使用示例
- 3、media子系统源码分析
- 4、统筹subdev、media子系统的驱动程序
- 5、media子系统调试
-
- 1)设备节点
- [2)media-ctl 调试工具](#2)media-ctl 调试工具)
1、preface
1)资料快车
1)Linux Media子系统链路分析: https://www.cnblogs.com/jzcn/p/17822224.html
2)概述
1)Media子系统 : Linux内核中的一种媒体框架,用于拓扑结构的管理;因为由于音视频的快速发展,涉及的处理模块很多,硬件上可以有各种组合搭配(因为要满足嵌入式领域的各种产品的不同搭配),加上各个厂商的设计也不一样,Subdev子系统和Media子系统就应运而生;
2)Subdev和Media适用于什么场景?vin和vout都需要,图像处理的模块太多,并且不同厂商的硬件拓扑结构各不相同,因此需要借助Subdev和Media的帮助;
3)media子系统是一个辅助驱动模块,协助其它驱动模块记录/组织一些关联关系;
4)V4L2 是 media 子系统的一部分;
2、V4L2、Subdev和media关系概述
1)总体关系

1、注意每一个子系统不单单内部互相关联,也都有对用户态的接口;
2)在V4L2系统中的subdev
在V4L2系统中每一个模块都有独立的驱动程序(subdev)

3)使用media来组织各个subdev驱动程序

1、注意media子系统是帮助V4L2模块记录这些关系;
1)entity代表一个subdev驱动模块;pad来记录输入/输出信息;media_entity之间的连接被称为media_link;pipeline表示一条完整链路
2、在V4L2需要这些关联信息,则需要通过media子系统查询;
4)总体拓扑图

1、V853平台搭配GC2053摄像头模块 V4L2系统拓扑图;
2、可以使用media-ctl生成Media Controller 框架下设备拓扑结构的可视化图表
media-ctl -d /dev/media0 --print-dot > media0.dot
5)v4l2_device 、subdev、media_device结构图
1.v4l2_device
/android/vendor/amlogic/common/kernel/common_5.4/include/media/v4l2-device.h
struct v4l2_device {
struct media_device *mdev; //存放media device
struct list_head subdevs; //存放subdev
};
2. subdev、media_entity如何找到对方?
1)v4l2_subdev里含有media_entity
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
}
2)内核使用container_of()来反查subdev
6)APP使用示例
1.media/subdev/video_dev使用示例
/android/vendor/amlogic/common/arm_isp/test/v4l2_test_media/media-v4l2/*
3、media子系统源码分析
1)源码目录
/android/vendor/amlogic/common/kernel/common_5.4/include/media/media-device.h
/android/vendor/amlogic/common/kernel/common_5.4/drivers/media/mc/*
2)数据结构
1.media_gobj
/android/vendor/amlogic/common/kernel/common_5.4/include/media/media-entity.h
struct media_gobj {
struct media_device *mdev;
u32 id;
struct list_head list;
};
2.media_entity
/android/vendor/amlogic/common/kernel/common_5.4/include/media/media-entity.h
struct media_entity {
struct media_gobj graph_obj; //包含唯一的ID
char *name;
enum media_entity_type obj_type; //VIDEL_DEVICE、V4L2_SUBDEV
u32 function;
u16 num_pads;
u16 num_links;
u16 num_backlinks;
struct media_pad *pads;
struct media_entity_operations *ops;
struct media_pipeline *pipe;
}
3.media_entity_operations
/android/vendor/amlogic/common/kernel/common_5.4/include/media/media-entity.h
struct media_entity_operations {
int (*get_fwnode_pad)(struct fwnode_endpoint *endpoint);
int (*link_setup)(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote, u32 flags);
int (*link_validate)(struct media_link *link);
};
4.media_pipeline
/android/vendor/amlogic/common/kernel/common_5.4/include/media/media-entity.h
struct media_pipeline {
int streaming_count;
struct media_graph graph;
};
struct media_graph {
struct {
struct media_entity *entity;
struct list_head *link;
} stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
struct media_entity_enum ent_enum;
int top;
};
5.media_pad
/android/vendor/amlogic/common/kernel/common_5.4/include/media/media-entity.h
struct media_pad {
struct media_gobj graph_obj; /* must be first field in struct */
struct media_entity *entity;
u16 index; //media_entity的pads数组索引
enum media_pad_signal_type sig_type;
unsigned long flags;
};
6.media_link
/android/vendor/amlogic/common/kernel/common_5.4/include/media/media-entity.h
struct media_link {
struct media_gobj graph_obj;
struct list_head list;
union {
struct media_gobj *gobj0;
struct media_pad *source; //源
struct media_interface *intf;
};
union {
struct media_gobj *gobj1;
struct media_pad *sink; //目的地
struct media_entity *entity;
};
struct media_link *reverse;
unsigned long flags;
bool is_backlink;
};
3)数据结构拓扑图

4)源码分析
1.media子系统注册
/android/vendor/amlogic/common/kernel/common_5.4/include/media/media-device.h
media_device_register()
/android/vendor/amlogic/common/kernel/common_5.4/drivers/media/mc/mc-device.c
__media_device_register
struct media_devnode *devnode;
devnode->fops = &media_device_fops;
ret = media_devnode_register(mdev, devnode, owner);
cdev_init(&devnode->cdev, &media_devnode_fops);
ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1);//创建字符设备
2.media_device_fops
static const struct media_file_operations media_device_fops = {
.owner = THIS_MODULE,
.open = media_device_open,
.ioctl = media_device_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = media_device_compat_ioctl,
#endif /* CONFIG_COMPAT */
.release = media_device_close,
};
3.media_devnode_fops
/android/vendor/amlogic/common/kernel/common_5.4/drivers/media/mc/mc-devnode.c
static const struct file_operations media_devnode_fops = {
.owner = THIS_MODULE,
.read = media_read,
.write = media_write,
.open = media_open,
.unlocked_ioctl = media_ioctl,
};
5)驱动模块使用media子系统
media子系统是一个辅助性内核模块(记录信息),使用时必然存在别的模块的初始化流程里!
1.注册media子系统分为2个层次:
* 描述自己的media_entity:各个subdev里含有media_entity,但是多个media_entity之间的关系由更上层的驱动决定
* 描述media_entity之间的联系:更上层的、统筹的驱动:它知道各个subdev即各个media_entity之间的联系:link
1)描述自己,各个底层驱动构造subdev时,顺便初始里面的media_entity:比如这个media_entity有哪些pad
media_entity_pads_init(&sd->entity, SENSOR_PAD_NUM, si->sensor_pads);
2)注册自己:底层或上层注册subdev时,顺便注册media_entity:把media_entity记录在media_device里
v4l2_device_register_subdev
--struct media_entity *entity = &sd->entity;
--media_device_register_entity(v4l2_dev->mdev, entity);
3)和别人建立联系:subdev之上的驱动程序决定各个media_entity如何连接:比如调用media_create_pad_link创建连接
media_create_pad_link(source, SCALER_PAD_SOURCE,
sink, VIN_SD_PAD_SINK,
MEDIA_LNK_FL_ENABLED);
2.如何遍历pipeline?
media_entity_pipeline_start(sensor, camif->m_pipeline); //遍历所有使能的link,按照深度优先策略
注册之后各模块的关联

6)APP使用media子系统
1./android/vendor/amlogic/common/arm_isp/test/v4l2_test_media/media-v4l2/libmediactl.c
2.APP使用media子系统时,除了open之外,就只涉及5个ioctl:
* MEDIA_IOC_DEVICE_INFO
* MEDIA_IOC_ENUM_ENTITIES
* MEDIA_IOC_ENUM_LINKS
* MEDIA_IOC_SETUP_LINK
* MEDIA_IOC_G_TOPOLOGY
3.APP访问流程
App: ioctl
--------------
kernel:
media_devnode_fops.unlocked_ioctl, 即media_ioctl
__media_ioctl(filp, cmd, arg, devnode->fops->ioctl);
media_device_ioctl
const struct media_ioctl_info *info;
info = &ioctl_info[_IOC_NR(cmd)];
ret = info->arg_from_user(karg, arg, cmd);
ret = info->fn(dev, karg);
ret = info->arg_to_user(arg, karg, cmd);
4.APP使用media子系统可以找到对应的设备节点
4、统筹subdev、media子系统的驱动程序
1、基于subdev、media子系统的驱动程序,基本可以分为2层:
* 上层:注册各个subdev,确定各个subdev的联系
* 底层:构造各个subdev设备驱动
2、底层各个模块的驱动构造了自己的subdev,但是它们之间的联系必须由更高层的驱动来处理,更高层的驱动一般以芯片平台为单位,构造芯片平台自己的subdev拓扑,比如s3c_camif、V853 MIPI摄像头驱动
3、开发者可以在设备树里面指定拓扑关系;
4.s3c Camera Interface
s3c_camif_probe()
/android/vendor/amlogic/common/kernel/common_5.4/drivers/media/platform/s3c-camif/camif-core.c
--s3c_camif_create_subdev(camif);
--camif_media_dev_init(camif);
----media_device_init(md);
----v4l2_device_register(camif->dev, v4l2_dev);
--camif_register_sensor(camif);
--v4l2_device_register_subdev(&camif->v4l2_dev, &camif->subdev);
--v4l2_device_register_subdev_nodes(&camif->v4l2_dev);
--camif_register_video_nodes(camif);
--camif_create_media_links(camif); //创建各个subdv之间的联系
--media_device_register(&camif->media_dev);
5.V853 MIPI驱动
drivers\media\platform\sunxi-vin\vin.c
5、media子系统调试
1)设备节点

2)media-ctl 调试工具
1.手动建立连接
media-ctl -v -l '"gc2053_mipi":0->"sunxi_mipi.0":0[1]'
2.查看节点之间的拓扑关系
media-ctl -p -d /dev/media0
3.生成Media Controller 框架下设备拓扑结构的可视化图表
media-ctl -d /dev/media0 --print-dot > media0.dot