مجموعات البث في الوقت الفعلي

الطوابع الزمنية في الوقت الفعلي

غالبًا ما تُستخدم الرسوم البيانية للحاسبة 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 وما إلى ذلك.

لإخراج حزمة من خلال عملية بث، تستخدِم الآلة الحاسبة دالّتَي واجهة برمجة التطبيقات CalculatorContext::Outputs وOutputStream::Add. بدلاً من ذلك لإخراج طابع زمني مرتبط ببث، يمكن للآلة الحاسبة استخدام دالّتَي واجهة برمجة التطبيقات 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);

ميزة هذا الإعداد هي ميزة نشر حدود الطابع الزمني تلقائيًا، حتى عند وصول حدود الطابع الزمني فقط ولا يتم استدعاء الآلة الحاسبة::Process.

3- يمكن تحديد ProcessTimestampBounds() من أجل استدعاء Calculator::Process لكل "طابع زمني تم ضبطه" جديد، حيث يكون "الطابع الزمني settset" هو أعلى طابع زمني جديد أسفل حدود الطابع الزمني الحالي. بدون 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());
}

جدولة الآلة الحاسبة::Open والآلة الحاسبة::Close

يتم استدعاء Calculator::Open عند إنشاء جميع الحزم الجانبية المطلوبة للإدخال. يمكن توفير الحُزم الجانبية للإدخال عن طريق تطبيق التضمين أو عن طريق "حاسبات الحزمة الجانبية" داخل الرسم البياني. يمكن تحديد الحِزم الجانبية من خارج الرسم البياني باستخدام CalculatorGraph::Initialize وCalculatorGraph::StartRun في واجهة برمجة التطبيقات. يمكن تحديد الحُزم الجانبية من خلال الحاسبات ضمن الرسم البياني باستخدام CalculatorGraphConfig::OutputSidePackets وOutputSidePacket::Set.

الآلة الحاسبة::يتم استدعاء الإغلاق عندما تصبح جميع مصادر الإدخال 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().