1.Calculators
每个计算器(calculators)都是图的一个节点。 我们描述了如何创建新的计算器,如何初始化计算器,如何执行其计算,输入和输出流,时间戳和选项。 图中的每个节点都实现为计算器。 图执行的大部分发生在其计算器内部。 计算器可以接收零个或多个输入流和/或侧分组,并产生零个或多个输出流和/或侧分组。
A calculator is created by defining a new sub-class of the CalculatorBase
class, implementing a number of methods, and registering the new sub-class with Mediapipe. At a minimum, a new calculator must implement the below four methods:
- GetContract()
calculators作者可以在GetContract()中指定计算器的预期输入和输出类型。 初始化图形后,框架将调用静态方法以验证连接的输入和输出的数据包类型是否与本规范中的信息匹配。
- Open()
图开始后,框架将调用Open()。 此时,输入侧数据包可用于计算器。 Open()解释节点配置操作(请参见图表),并准备计算器的按图运行状态。 此功能还可以将数据包写入计算器输出。 Open()期间的错误可能会终止图形运行。
具体逻辑:
The framework calls Open() to initialize the calculator.
If appropriate, Open() should call cc->SetOffset() or cc->Outputs().Get(id)->SetNextTimestampBound() to allow the framework to better optimize packet queueing.
- Process()
对于具有输入的计算器,只要至少一个输入流具有可用的数据包,框架就会反复调用Process()。 默认情况下,该框架保证所有输入都具有相同的时间戳(有关更多信息,请参见同步)。 启用并行执行时,可以同时调用多个Process()调用。 如果在Process()期间发生错误,则框架将调用Close(),并且图形运行将终止。
具体逻辑:
The framework calls Process() for every packet received on the input streams. The framework guarantees that cc>InputTimestamp() will increase with every call to Process(). An empty packet will be on the input stream if there is no packet on a particular input stream (but some other input stream has a packet).
- Close()
在所有对Process()的调用完成之后,或者当所有输入流关闭时,框架将调用Close()。 如果调用了Open()并成功调用了该函数,即使该图形由于错误而终止运行,也始终会调用此函数。 在Close()期间,没有任何输入流可以通过任何输入流使用,但是它仍然可以访问输入侧数据包,因此可以写入输出。 在Close()返回之后,应将计算器视为死节点。 图形完成运行后,计算器对象即被销毁。
具体逻辑:
The framework calls Close() after all calls to Process().
Calculate调用的基本逻辑如下:
The framework calls four primary functions on a calculator.On initialization of the graph, a static function is called.
GetContract() #The subclasses of CalculatorBase must implement GetContract
Then, for each run of the graph on a set of input side packets, the following sequence will occur.
Open()
Process() (repeatedly)
Close()
注意: 没有input的calculator 被称为sources, 和一般的non-sources在处理上有些许的差别。Calculators must be thread-compatible.
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Examples:
CalculatorBase的子类必须实现GetContract。没有它,就无法注册计算器。
请注意,尽管此函数是静态的,但注册宏可提供对每个子类的GetContract函数的访问。
static ::mediapipe::Status GetContract(CalculatorContract* cc);
1. GetContract
GetContract用该框架填写计算器合同,例如
作为对它将收到哪些数据包的期望。 调用此函数时,输入,输出和输入侧数据包的数量将已经由计算器图表确定。 您可以使用索引,标签或tag:index来访问输入流,输出流或输入侧数据包。
//Example (uses tags for inputs and indexes for outputs and input side packets):
cc->Inputs().Tag("VIDEO").Set<ImageFrame>("Input Image Frames.");
cc->Inputs().Tag("AUDIO").Set<Matrix>("Input Audio Frames.");
cc->Outputs().Index(0).Set<Matrix>("Output FooBar feature.");
cc->InputSidePackets().Index(0).Set<MyModel>(
"Model used for FooBar feature extraction.");
// Example (same number and type of outputs as inputs):
for (int i = 0; i < cc->Inputs().NumEntries(); ++i) {
// SetAny() 用来转换输入的类型
cc->Inputs().Index(i).SetAny(StrCat("Generic Input Stream ", i));
//转化输出与输入类型一致.
cc->Outputs().Index(i).SetSameAs(
&cc->Inputs().Index(i), StrCat("Generic Output Stream ", i));
}
2.Open
在新构造的任何Process()调用之前,会首先调用Open()函数。 子类可以重写此方法以执行必要的设置,并可能输出数据包和/或设置输出流的标头。
必须返回OkStatus()去显示成功:Must return ::mediapipe::OkStatus() to indicate success
如果失败了,会返回其他的Status状态,这时候Calculator 不会继续进行 Process() 或Close() ,并且你需要在析构函数中去掉分配的内存。