جریان های زمان واقعی

مُهرهای زمان واقعی

نمودارهای ماشین حساب 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() مشخص کند.