实时时间戳
MediaPipe 计算器图表通常用于处理视频流或音频流
专为交互式应用打造的框架MediaPipe 框架只需要
为连续数据包分配单调递增的时间戳。修改者
惯例,实时计算器和图表使用记录时间或
作为帧的时间戳,其中每个时间戳表示
自 Jan/1/1970:00:00:00
以来的微秒数。这允许来自各种来源的
按照全球一致的顺序进行处理。
实时安排
通常,每个计算器的所有输入包都会在给定的 时间戳可用。通常,当计算器开始计算时, 上一帧处理完成后,每个计算器生成 其输入已处理完当前帧。MediaPipe 调度器 会在满足这些条件后立即调用每个计算器。请参阅 同步。
时间戳边界
如果计算器没有针对指定时间戳生成任何输出数据包, 可以改为输出“时间戳边界”表示不会发送任何数据包 生成该时间戳此指示对于允许下游 计算器,即使该时间戳并未收到任何数据包, 特定视频流这对于实时 交互式应用程序,其中每个计算器必须 尽快开始处理
假设有一个如下所示的图表:
node {
calculator: "A"
input_stream: "alpha_in"
output_stream: "alpha"
}
node {
calculator: "B"
input_stream: "alpha"
input_stream: "foo"
output_stream: "beta"
}
假设:在时间戳 T
处,节点 A
在其输出流中未发送数据包
alpha
。节点 B
在时间戳 T
的 foo
中获取数据包,正在等待
alpha
中的时间戳 T
的数据包。如果 A
未向 B
发送时间戳边界
针对 alpha
的更新,B
将继续等待 alpha
中的数据包到达。
同时,foo
的数据包队列将在 T
、T+1
和
依此类推。
为了在流中输出数据包,计算器会使用 API 函数,
CalculatorContext::Outputs
和OutputStream::Add
。要改为输出
时间戳边界,计算器可以使用 API 函数
CalculatorContext::Outputs
和CalculatorContext::SetNextTimestampBound
。通过
指定边界上允许下一个数据包的最小时间戳,
指定输出流。当没有输出数据包时,计算器通常会
执行诸如以下操作:
cc->Outputs().Tag("output_frame").SetNextTimestampBound(
cc->InputTimestamp().NextAllowedInStream());
函数 Timestamp::NextAllowedInStream
会返回连续时间戳。
例如 Timestamp(1).NextAllowedInStream() == Timestamp(2)
。
传播时间戳边界
用于实时图表的计算器需要定义输出
基于输入时间戳边界的时间戳边界,以允许下游
计算器。一种常见的模式是计算器
输出数据包的时间戳与其输入数据包的时间戳相同。在此示例中
每次调用 Calculator::Process
时简单地输出一个数据包就足够了
定义输出时间戳边界。
不过,计算器无需遵循这种输出模式 时间戳,只需选择单调递增的输出 时间戳。因此,某些计算器必须计算时间戳边界 。MediaPipe 提供了多种工具,用于计算适当的时间戳 。
1. SetNextTimestampBound() 可用于为输出流指定时间戳边界 t +
1
。
cc->Outputs.Tag("OUT").SetNextTimestampBound(t.NextAllowedInStream());
或者,可以生成时间戳为 t
的空数据包,以指定
时间戳边界为 t + 1
。
cc->Outputs.Tag("OUT").Add(Packet(), t);
输入流的时间戳边界由数据包或空 发送一个数据包
Timestamp bound = cc->Inputs().Tag("IN").Value().Timestamp();
2. 可以指定 TimestampOffset(),以自动复制 从输入流到输出流的时间戳边界。
cc->SetTimestampOffset(0);
此设置的优点是自动传播时间戳边界, 即使仅到达时间戳边界,且未调用 Calculator::Process。
3. 可指定 ProcessTimestampBounds() 以调用
每个新的“结算时间戳”为 Calculator::Process
,其中“结算时间”
timestamp”是当前时间戳边界以下的新最高时间戳。
不使用 ProcessTimestampBounds()
时,Calculator::Process
只能通过
一个或多个传入的数据包。
cc->SetProcessTimestampBounds(true);
此设置允许计算器执行自己的时间戳边界计算
即使仅更新输入时间戳也是如此。它可用于
可以复制 TimestampOffset()
的效果,但也可用于
计算在考虑其他因素的时间戳边界。
例如,要复制 SetTimestampOffset(0)
,计算器可以
执行以下操作:
absl::Status Open(CalculatorContext* cc) {
cc->SetProcessTimestampBounds(true);
}
absl::Status Process(CalculatorContext* cc) {
cc->Outputs.Tag("OUT").SetNextTimestampBound(
cc->InputTimestamp().NextAllowedInStream());
}
计算器安排::打开和计算器::关闭
已调用所有必需的输入侧包后,系统会调用 Calculator::Open
生成的内容。输入侧数据包可以由封装应用或
"侧包计算器"图表内部。可从
在图表之外使用 API 的 CalculatorGraph::Initialize
,
CalculatorGraph::StartRun
。边数据包可由
使用 CalculatorGraphConfig::OutputSidePackets
和
OutputSidePacket::Set
。
当所有输入流都变为 Done
时,系统会调用 Calculator::Close,
正在关闭或即将达到时间戳边界 Timestamp::Done
。
注意:如果图表完成所有待处理的计算器执行任务,
Done
,然后在某些流变为 Done
状态之前,MediaPipe 会调用
对 Calculator::Close
的剩余调用次数,以便每个计算器都能得出
最终输出。
使用 TimestampOffset
会对 Calculator::Close
有一些影响。答
指定 SetTimestampOffset(0)
的计算器会在设计上表明,
当其所有输入流都达到Timestamp::Done
时
已达到 Timestamp::Done
,因此无法进一步输出。
这样可防止此类计算器在计算过程中
Calculator::Close
。如果计算器在运行
Calculator::Close
,Calculator::Process
必须指定时间戳边界,例如
在查询期间,至少有一个时间戳(例如 Timestamp::Max
)保持可用状态
Calculator::Close
。也就是说,此类计算器通常无法
SetTimestampOffset(0)
,必须改为明确指定时间戳边界
使用 SetNextTimestampBounds()
。