חותמות זמן בזמן אמת
לרוב משתמשים בתרשימים של מחשבון 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()
.