1. node bypass介绍
node bypass 是高通做的一套框架,目的为了减少不必要的拷贝。目前我们如果不能使用某个node 时,是使用copy 的方式将数据从inport 拷贝到outport。
使用bypass 后当前node 的inport 端口的imagebuffer 地址直接传给下一个node的inport ,此时直接地址传递就不需要拷贝,即减少拷贝又不影响下一个node的工作。
2.如何配置node的bypass功能
2.1 xml 文件设置
2.1.1 属性设置
bypass 是node的一种属性,所以首先需要在xml中配置这种属性,bypass 属性ID 是11。具体ID对应属性功能可参考下图:
static const NodeProperty NodePropertyNodeClass = 11; ///< Node class -
配置属性的代码如下:
<NodeProperty> <NodePropertyId>11</NodePropertyId> <NodePropertyDataType>UINT</NodePropertyDataType> <NodePropertyValue>1</NodePropertyValue> </NodeProperty>
2.1.2 源端口设置
bypass 时因为需要将节点的inport端口的地址传递下去,所以需要从inport 端口中选择使用需要传递的那一个,配置代码如下:
<BypassPortSrcId>1</BypassPortSrcId>
中间数字就是选择的端口号。
注意: 如果忘记配置端口号 使用时会出现图片花纹,图片变绿等现象。
2.1.3 node id 设置
bypass 功能的代码实现对node NodeInstanceId id 有了一定的要求,后面执行的node需要比前面的node 的id值小。导致这样设置的原因是因为在node 开启bypass 时当node创建时他需要知道后面含有几个bypass node,代码实现是通过子node 回调父node函数通知父node下面有多少个bypass
这样就导致必须子node先执行统计他的下边有多少个bypass功能开启的node。所以要求子node必须先创建,但是xml文件在转换的时候是根据id号来决定生成结构体的顺序的,如下图所示:
可以看到 对于 255类型node 在结构体中是按照id号 4,5,6,7,8,9从小到大排序下来的。
为什么需要子节点统计bypass 的数量这个和bypass代码实现中有个索引值有关,在后面的介绍fence代码中会介绍。
2.1.4 实例
以 SATJpegEncode1 这条pipeline 为例 介绍下xml中 使能bypass node 。 这条pipeline 软件算法node 执行顺序如下图:
因为上面的node id值要比下面的大,distortioncorrection node 配置如下
<Node> <NodeProperty> <NodePropertyId>1</NodePropertyId> <NodePropertyDataType>STRING</NodePropertyDataType> <NodePropertyValue>com.arcsoft.node.distortioncorrection</NodePropertyValue> </NodeProperty> <NodeProperty> <NodePropertyId>11</NodePropertyId> <NodePropertyDataType>UINT</NodePropertyDataType> <NodePropertyValue>1</NodePropertyValue> </NodeProperty> <NodeName>ChiExternalNode</NodeName> <NodeId>255</NodeId> <NodeInstance>ChiNodeInstanceName9</NodeInstance> <NodeInstanceId>9</NodeInstanceId> </Node>
skinbeautifier node 配置如下:
<Node> <NodeProperty> <NodePropertyId>1</NodePropertyId> <NodePropertyDataType>STRING</NodePropertyDataType> <NodePropertyValue>com.arcsoft.node.skinbeautifier</NodePropertyValue> </NodeProperty> <NodeProperty> <NodePropertyId>11</NodePropertyId> <NodePropertyDataType>UINT</NodePropertyDataType> <NodePropertyValue>1</NodePropertyValue> </NodeProperty> <NodeProperty> <NodePropertyId>NodePropertyXiaomiChiCaps</NodePropertyId> <NodePropertyDataType>UINT</NodePropertyDataType> <NodePropertyValue>16</NodePropertyValue> </NodeProperty> <NodeName>ChiExternalNode</NodeName> <NodeId>255</NodeId> <NodeInstance>ChiNodeInstanceName8</NodeInstance> <NodeInstanceId>8</NodeInstanceId> </Node>
配置完成node NodeInstanceId id和 NodePropertyId id 下面就是需要配置bypass 使用的inport。如下:
<Link> <SrcPort> <PortName>IPEOutputPortDisplay</PortName> <PortId>8</PortId> <NodeName>IPE</NodeName> <NodeId>65538</NodeId> <NodeInstance>IPEInstanceName4</NodeInstance> <NodeInstanceId>4</NodeInstanceId> </SrcPort> <DstPort> <PortName>ChiNodeInputPortFull</PortName> <PortId>0</PortId> //下面的BypassPortSrcId 是根据这里决定的 <NodeName>ChiExternalNode</NodeName> <NodeId>255</NodeId> <NodeInstance>ChiNodeInstanceName9</NodeInstance> <NodeInstanceId>9</NodeInstanceId> </DstPort> <BufferProperties> <BufferFormat>ChiFormatYUV420NV12</BufferFormat> <BufferImmediateAllocCount>1</BufferImmediateAllocCount> <BufferQueueDepth>8</BufferQueueDepth> <BufferHeap>Ion</BufferHeap> <BufferFlags>BufferMemFlagHw</BufferFlags> <BufferFlags>BufferMemFlagLockable</BufferFlags> <BufferFlags>BufferMemFlagCache</BufferFlags> </BufferProperties> </Link> <Link> <SrcPort> <PortName>ChiNodeOutputPortFull</PortName> <PortId>0</PortId> <NodeName>ChiExternalNode</NodeName> <NodeId>255</NodeId> <NodeInstance>ChiNodeInstanceName9</NodeInstance> <NodeInstanceId>9</NodeInstanceId> <BypassPortSrcId>0</BypassPortSrcId> </SrcPort> <DstPort> <PortName>ChiNodeInputPortFull</PortName> <PortId>0</PortId> <NodeName>ChiExternalNode</NodeName> <NodeId>255</NodeId> <NodeInstance>ChiNodeInstanceName8</NodeInstance> <NodeInstanceId>8</NodeInstanceId> </DstPort> <BufferProperties> <BufferFormat>ChiFormatYUV420NV12</BufferFormat> <BufferImmediateAllocCount>1</BufferImmediateAllocCount> <BufferQueueDepth>8</BufferQueueDepth> <BufferHeap>Ion</BufferHeap> <BufferFlags>BufferMemFlagLockable</BufferFlags> <BufferFlags>BufferMemFlagCache</BufferFlags> </BufferProperties> </Link>
BypassPortSrcId 配置 的数是根据需要被bypass的节点的inport决定的。 已经使用蓝色标记出来。
2.2 node 相关代码中的配置
软件的node 也就是类型是255 的node 有的已经做了bypass 功能,有的没有做,需要根据情况修改node代码。但增加支持bypass代码是完全相同的,高通已经做好了框架。
以skinbeautifier node 为例。 在skinbeautifier 的camxchinodeSkinBeautifier.h 文件中增加 成员变量。
CHINODEFLAGS m_nodeFlags; ///< Node flags
增加函数
BOOL IsByssableNode() const { return m_nodeFlags.isBypassable; }
在camxchinodeSkinBeautifiler.cpp 的 Initialize 函数中增加
m_nodeFlags = pCreateInfo->nodeFlags;
这里的nodeFlags 会存放node 属性中当时定义的值,也就是在node xml 配置中我们给node 属性 id 11 配置为1 最后会被传输入到m_nodeFlags.isBypassable
在 processrequest 函数中 只需要通过IsByssableNode 函数是不是bypass 使能,使能后执行如下两句代码
pProcessRequestInfo->pBypassData[i].isBypassNeeded = TRUE; pProcessRequestInfo->pBypassData[i].selectedInputPortIndex = ChiNodeBypass;
注意: 如果node 的outport 链接的并不是其他node 而是sinkbuff,这个node 不能使用bypass 功能。最后一定是需要一个将数据写入到sinkbuffer中。