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; //重点看这里,entity中的所有pad
struct list_head links; //重点看这里,entity与别的entity之间的所有link
const struct media_entity_operations *ops;
int stream_count;
int use_count;
struct media_pipeline *pipe;
union {
struct {
u32 major;
u32 minor;
} dev;
} info;
};
/**
* struct media_graph - Media graph traversal state
*
* @stack: Graph traversal stack; the stack contains information
* on the path the media entities to be walked and the
* links through which they were reached.
* @ent_enum: Visited entities
* @top: The top of the stack
*/
struct media_graph {
struct {
struct media_entity *entity;
struct list_head *link; //重点看这里,每个entity有多个link,根据这个变量进行深度分叉判断
} stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
struct media_entity_enum ent_enum; //重点看这里,用来判断某个entity是否被放入栈中
int top;
};
struct media_entity *media_graph_walk_next(struct media_graph *graph)
{
struct media_entity *entity;
if (stack_top(graph) == NULL)
return NULL;
/*
* Depth first search. Push entity to stack and continue from
* top of the stack until no more entities on the level can be
* found.
*/
while (link_top(graph) != &stack_top(graph)->links) //判断这个分支上有没有被遍历完
media_graph_walk_iter(graph);
entity = stack_pop(graph);
dev_dbg(entity->graph_obj.mdev->dev,
"walk: returning entity '%s'\n", entity->name);
return entity;
}
static void media_graph_walk_iter(struct media_graph *graph)
{
struct media_entity *entity = stack_top(graph);
struct media_link *link;
struct media_entity *next;
link = list_entry(link_top(graph), typeof(*link), list);
/* The link is not enabled so we do not follow. */
if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
link_top(graph) = link_top(graph)->next;
dev_dbg(entity->graph_obj.mdev->dev,
"walk: skipping disabled link '%s':%u -> '%s':%u\n",
link->source->entity->name, link->source->index,
link->sink->entity->name, link->sink->index);
return;
}
/* Get the entity in the other end of the link . */
next = media_entity_other(entity, link);
/* Has the entity already been visited? */
if (media_entity_enum_test_and_set(&graph->ent_enum, next)) { //如果已经被遍历过了,换节点上另一个分支,然后返回,下次再进来就是下个分支
link_top(graph) = link_top(graph)->next;
dev_dbg(entity->graph_obj.mdev->dev,
"walk: skipping entity '%s' (already seen)\n",
next->name);
return;
}
/* Push the new entity to stack and start over. */ //如果没被遍历,往更深一层
link_top(graph) = link_top(graph)->next;
stack_push(graph, next);
dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
next->name);
}