Linux camera之Media子系统

文章目录

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
相关推荐
goxingman2 小时前
在 Linux 中查看磁盘运行占用(I/O 使用率)
linux·运维·chrome
小天源2 小时前
XShell一台控制多台操作详情
linux·运维·服务器
xu_yule2 小时前
网络和Linux网络-13(高级IO+多路转接)五种IO模型+select编程
linux·网络·c++·select·i/o
夜流冰2 小时前
编程参考 - Linux kernel代码查看
linux·运维·服务器
xu_yule2 小时前
网络和Linux网络-14(IO多路转接)poll和epoll编程-服务器
linux·运维·服务器·epoll·poll
timi先生2 小时前
全新的linux如何进行远程xshell操作?
linux·运维·服务器
陌上花开缓缓归以2 小时前
OPENWRT 端口link问题
linux·arm开发
Coder个人博客2 小时前
Linux6.19-ARM64 mm ioremap子模块深入分析
linux·安全·车载系统·系统架构·系统安全·鸿蒙系统·安全架构
程序员一点2 小时前
第4章:Linux 文件系统结构与路径管理
linux·运维·服务器