צ'אטים בזמן אמת

חותמות זמן בזמן אמת

לרוב משתמשים בתרשימים של מחשבון MediaPipe כדי לעבד שידורי וידאו או אודיו פריימים לאפליקציות אינטראקטיביות. ל-framework של MediaPipe נדרש רק של חבילות עוקבות מוקצות חותמות זמן שגדלות באופן מונוטוני. על ידי במחשבונים ובגרפים בזמן אמת משתמשים בזמן ההקלטה או זמן ההצגה של כל פריים כחותמת הזמן שלו, כשכל חותמת זמן מציינת את המיקרו-שניות מאז Jan/1/1970:00:00:00. כך מתאפשרת שליחת חבילות מערכים שונים למקורות שיעובדו בסדר גלובלי עקבי.

תזמון בזמן אמת

בדרך כלל, כל מחשבון פועל מיד לאחר שכל חבילות הקלט שלו עבור מערך נתונים מסוים חותמת זמן מסוימת תהפוך לזמינה. בדרך כלל, מצב כזה קורה כאשר המחשבון סיים לעבד את הפריים הקודם, וכל אחד מהמחשבונים הפיק תהליכי הקלט שלו סיימו לעבד את הפריים הנוכחי. תזמון MediaPipe מפעיל כל מחשבון ברגע שהתנאים האלה מתקיימים. צפייה סנכרון – לקבלת פרטים נוספים.

גבולות חותמות זמן

כשמחשבון לא מפיק חבילות פלט לחותמת זמן נתונה, במקום זאת, הוא יכול להציג 'חותמת זמן שקשורה לחותמת זמן' שמציין שאף חבילה לא שהופק עבור חותמת הזמן הזו. החיווי הזה הכרחי כדי לאפשר שימוש במורד הזרם (downstream) כדי להריץ את המחשבונים בחותמת הזמן הזו, למרות שלא התקבלה שום חבילה שידורים מסוימים בחותמת הזמן הזו. זה חשוב במיוחד בזמן אמת גרפים באפליקציות אינטראקטיביות, שבהן חשוב מאוד שכל מחשבון את העיבוד בהקדם האפשרי.

נבחן תרשים כמו:

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);

היתרון של ההגדרה הזאת הוא הפצת גבולות של חותמות זמן באופן אוטומטי, גם כשמופיעים רק גבולות חותמת זמן והמערכת לא מפעילה את המחשבון::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());
}

תזמון של המחשבון::Open and Calculator::Close

Calculator::Open הופעל לאחר שכל חבילות הקלט הנדרשות לקלט כבר שהופק. ניתן לספק חבילות צדדיות קלט על ידי האפליקציה המצורפת או על ידי "מחשבון צד-נתונים" בתוך התרשים. ניתן לציין חבילות צדדיות מתוך מחוץ לתרשים באמצעות CalculatorGraph::Initialize של ה-API 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().