مُهرهای زمان واقعی
نمودارهای ماشین حساب 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
یک بسته در foo
در مهر زمانی T
دریافت می کند و منتظر بسته ای به صورت 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
برای هر "مهر زمانی تسویه شده" جدید مشخص کرد، که در آن "زمان تسویه شده" بالاترین مُهر زمانی جدید زیر مرزهای مهر زمانی فعلی است. بدون 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
زمانی فراخوانی می شود که تمام بسته های جانبی ورودی مورد نیاز تولید شده باشند. بستههای جانبی ورودی را میتوان توسط برنامههای محصورکننده یا «محاسبگرهای بسته جانبی» در داخل نمودار ارائه کرد. بسته های جانبی را می توان از خارج از نمودار با استفاده از CalculatorGraph::Initialize
و CalculatorGraph::StartRun
API مشخص کرد. بسته های جانبی را می توان توسط ماشین حساب های داخل نمودار با استفاده از CalculatorGraphConfig::OutputSidePackets
و OutputSidePacket::Set
مشخص کرد.
Calculator::Close زمانی فراخوانی Done
که تمام جریانهای ورودی با بسته شدن یا رسیدن به مهر زمانی محدود شده، 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()
مشخص کند.