ממשקי API לניהול מאגר של מצלמה HAL3

אנדרואיד 10 מציגה ממשקי API לניהול חיץ אופציונליים של מצלמה HAL3 המאפשרים לך ליישם לוגיקה של ניהול מאגר כדי להשיג זיכרון שונה וללכוד פשרות חביון ביישומי HAL של מצלמה.

המצלמה HAL דורשת N בקשות (כאשר N שווה לעומק הצינור ) בתור בצינור שלה, אך לעתים קרובות היא אינה דורשת את כל N סטים של מאגרי פלט בו-זמנית.

לדוגמה, ל-HAL עשויות להיות שמונה בקשות בתור בצנרת, אך היא דורשת רק מאגרי פלט עבור שתי הבקשות בשלבים האחרונים של הצינור. במכשירים המריצים אנדרואיד 9 ומטה, מסגרת המצלמה מקצה מאגרים כאשר הבקשה ממוקמת בתור ב-HAL כך שייתכן שיש שש קבוצות של מאגרים ב-HAL שאינן בשימוש. באנדרואיד 10, ממשקי ה-API של ניהול מאגר של המצלמה HAL3 מאפשרים ניתוק של מאגרי הפלט כדי לפנות את שש קבוצות ה-buffers. זה יכול להוביל לחיסכון של מאות מגה בייט בזיכרון במכשירים מתקדמים ויכול להועיל גם למכשירים עם זיכרון נמוך.

איור 1 מציג תרשים של ממשק ה-HAL של המצלמה עבור מכשירים עם אנדרואיד 9 ומטה. איור 2 מציג את ממשק ה-HAL של המצלמה באנדרואיד 10 עם ממשקי ה-API לניהול מאגר HAL3 של המצלמה.

ניהול מאגר ב-9 ומטה

איור 1. ממשק HAL למצלמה באנדרואיד 9 ומטה

ניהול מאגר באנדרואיד 10

איור 2. ממשק HAL למצלמה באנדרואיד 10 באמצעות ממשקי API לניהול מאגר

הטמעת ממשקי API לניהול מאגר

כדי ליישם את ממשקי API לניהול מאגר, ה-HAL של המצלמה חייב:

המצלמה HAL משתמשת בשיטות requestStreamBuffers ו- returnStreamBuffers ב- ICameraDeviceCallback.hal כדי לבקש ולהחזיר מאגרים. ה-HAL חייב גם ליישם את שיטת signalStreamFlush ב- ICameraDeviceSession.hal כדי לאותת ל-HAL של המצלמה להחזיר מאגרים.

requestStreamBuffers

השתמש בשיטת requestStreamBuffers כדי לבקש מאגרים ממסגרת המצלמה. בעת שימוש בממשקי ה-API של ניהול מאגר HAL3 של המצלמה, בקשות לכידה ממסגרת המצלמה אינן מכילות מאגרי פלט, כלומר, השדה bufferId ב- StreamBuffer הוא 0 . לכן, ה-HAL של המצלמה חייב להשתמש requestStreamBuffers כדי לבקש מאגרים ממסגרת המצלמה.

שיטת requestStreamBuffers מאפשרת למתקשר לבקש מאגרים מרובים מזרמי פלט מרובים בשיחה אחת, מה שמאפשר פחות שיחות HIDL IPC. עם זאת, שיחות לוקחות יותר זמן כאשר מתבקשים יותר מאגרים בו-זמנית וזה עלול להשפיע לרעה על זמן האחזור הכולל של הבקשה לתוצאה. כמו כן, מכיוון שקריאות ל- requestStreamBuffers מסודרות בשירות המצלמה, מומלץ שה-HAL של המצלמה ישתמש בשרשור ייעודי בעדיפות גבוהה כדי לבקש מאגרים.

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

  • האפליקציה מתנתקת מזרם הפלט: זוהי שגיאה לא קטלנית. המצלמה HAL צריכה לשלוח ERROR_REQUEST עבור כל בקשת לכידה המכוונת לזרם מנותק ולהיות מוכנה לעבד בקשות עוקבות כרגיל.
  • פסק זמן: זה יכול להתרחש כאשר אפליקציה עסוקה בעיבוד אינטנסיבי תוך שמירה על כמה מאגרים. המצלמה HAL צריכה לשלוח ERROR_REQUEST עבור בקשות לכידה שלא ניתן למלא עקב שגיאת זמן קצוב ולהיות מוכנה לעבד בקשות עוקבות כרגיל.
  • מסגרת המצלמה מכינה תצורת זרם חדשה: ה-HAL של המצלמה צריך להמתין עד להשלמת שיחת configureStreams הבאה לפני שתקרא שוב requestStreamBuffers .
  • ה-HAL של המצלמה הגיע למגבלת המאגר שלו (שדה maxBuffers ): ה-HAL של המצלמה צריך להמתין עד שהוא יחזיר לפחות מאגר אחד מהזרם לפני שיקרא שוב requestStreamBuffers .

returnStreamBuffers

השתמש בשיטת returnStreamBuffers כדי להחזיר מאגרים נוספים למסגרת המצלמה. ה-HAL של המצלמה מחזיר בדרך כלל מאגרים למסגרת המצלמה באמצעות שיטת processCaptureResult , אך הוא יכול לתת חשבון רק לבקשות צילום שנשלחו ל-HAL של המצלמה. עם שיטת requestStreamBuffers , יישום ה-HAL של המצלמה יכול לשמור על יותר מאגרים ממה שהתבקש על ידי מסגרת המצלמה. זה הזמן שבו יש להשתמש בשיטת returnStreamBuffers . אם יישום HAL לעולם לא מחזיק יותר מאגרים מהמבוקש, יישום HAL של המצלמה אינו צריך לקרוא לשיטת returnStreamBuffers .

signalStreamFlush

שיטת signalStreamFlush נקראת על ידי מסגרת המצלמה כדי להודיע ​​למצלמה HAL להחזיר את כל המאגרים בהישג יד. זה נקרא בדרך כלל כאשר מסגרת המצלמה עומדת לקרוא ל- configureStreams ועליה לנקז את צינור לכידת המצלמה. בדומה לשיטת returnStreamBuffers , אם יישום HAL של מצלמה אינו מחזיק יותר מאגרים מהמבוקש, ניתן לבצע יישום ריק של שיטה זו.

לאחר שמסגרת המצלמה קוראת ל- signalStreamFlush , המסגרת מפסיקה לשלוח בקשות לכידה חדשות ל-HAL של המצלמה עד שכל המאגרים יוחזרו למסגרת המצלמה. כאשר כל המאגרים מוחזרים, קריאות השיטה requestStreamBuffers נכשלות, ומסגרת המצלמה יכולה להמשיך את עבודתה במצב נקי. מסגרת המצלמה קוראת לשיטת configureStreams או processCaptureRequest . אם מסגרת המצלמה קוראת לשיטת configureStreams , ה-HAL של המצלמה יכול להתחיל לבקש שוב מאגרים לאחר שהקריאה ל- configureStreams תחזור בהצלחה. אם מסגרת המצלמה קוראת לשיטת processCaptureRequest , המצלמה HAL יכולה להתחיל לבקש מאגרים במהלך קריאת processCaptureRequest .

הסמנטיקה שונה עבור שיטת signalStreamFlush ושיטת flush . כאשר שיטת flush נקראת, ה-HAL יכול לבטל בקשות לכידה ממתינות עם ERROR_REQUEST כדי לנקז את הצינור בהקדם האפשרי. כאשר קוראים לשיטת signalStreamFlush , ה-HAL חייב לסיים את כל בקשות הלכידה הממתינות בדרך כלל ולהחזיר את כל המאגרים למסגרת המצלמה.

הבדל נוסף בין שיטת signalStreamFlush לשיטות אחרות הוא ש- signalStreamFlush היא שיטת HIDL חד-כיוונית , מה שאומר שמסגרת המצלמה עשויה להתקשר לממשקי API חוסמים אחרים לפני שה-HAL יקבל את קריאת signalStreamFlush . המשמעות היא ששיטת signalStreamFlush ושיטות אחרות (במיוחד שיטת configureStreams ) עשויות להגיע ל-HAL של המצלמה בסדר שונה מהסדר שהם נקראו במסגרת המצלמה. כדי לטפל בבעיה אסינכרונית זו, השדה streamConfigCounter נוסף ל- StreamConfiguration והתווסף כארגומנט לשיטת signalStreamFlush . יישום ה-HAL של המצלמה צריך להשתמש בארגומנט streamConfigCounter כדי לקבוע אם קריאת signalStreamFlush מגיעה מאוחר יותר מהקריאה המתאימה ל- configureStreams . ראה איור 3 לדוגמא.

טיפול בשיחות שמגיעות באיחור

איור 3. כיצד המצלמה HAL צריכה לזהות ולטפל בשיחות signalStreamFlush שמגיעות באיחור

שינויים בהתנהגות בעת הטמעת ממשקי API לניהול מאגר

בעת שימוש בממשקי ה-API של ניהול מאגר כדי ליישם את לוגיקה של ניהול מאגר, שקול את השינויים הבאים בהתנהגות האפשרית ביישום HAL של המצלמה והמצלמה:

  • בקשות לכידה מגיעות ל-HAL של המצלמה מהר יותר ובתדירות גבוהה יותר: ללא ממשקי API לניהול מאגר, מסגרת המצלמה מבקשת מאגרי פלט עבור כל בקשת לכידה לפני שליחת בקשת לכידה ל-HAL של המצלמה. בעת שימוש בממשקי API לניהול מאגר, מסגרת המצלמה כבר לא צריכה לחכות למאגרים ולכן יכולה לשלוח בקשות לכידה אל המצלמה HAL מוקדם יותר.

    כמו כן, ללא ממשקי API לניהול מאגר, מסגרת המצלמה מפסיקה לשלוח בקשות לכידה אם אחד מזרמי הפלט של בקשת הלכידה הגיע למספר המרבי של מאגרים שה-HAL יכול להחזיק בו-זמנית (ערך זה מוגדר על ידי ה-HAL של המצלמה ב- שדה HalStream::maxBuffers בערך ההחזרה של קריאה של configureStreams ). עם ממשקי ה-API של ניהול מאגר, התנהגות החמצה הזו אינה קיימת יותר, והטמעת HAL של המצלמה אינה יכולה לקבל קריאות processCaptureRequest כאשר ל-HAL יש יותר מדי בקשות לכידה בתור.

  • זמן האחזור של שיחות requestStreamBuffers משתנה באופן משמעותי: ישנן סיבות רבות לכך ששיחה requestStreamBuffers עשויה להימשך זמן רב יותר מהממוצע. לדוגמה:

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

אסטרטגיות ניהול מאגר

ממשקי API לניהול מאגר מאפשרים ליישם סוגים שונים של אסטרטגיות ניהול מאגר. חלק מהדוגמאות הן:

  • תואם לאחור: ה-HAL מבקש מאגרים עבור בקשת לכידה במהלך קריאת processCaptureRequest . אסטרטגיה זו אינה מספקת חיסכון בזיכרון, אך יכולה לשמש כיישום ראשון של ממשקי ה-API לניהול מאגר, הדורשים מעט מאוד שינויים בקוד ב-HAL הקיים של המצלמה.
  • חיסכון מרבי בזיכרון: המצלמה HAL מבקשת רק מאגרי פלט מיד לפני שיש צורך במילוי אחד. אסטרטגיה זו מאפשרת חיסכון מירבי בזיכרון. החיסרון הפוטנציאלי הוא יותר תקלה בצנרת המצלמה כאשר בקשות מאגר לוקחות זמן בלתי רגיל לסיום.
  • מאוחסן במטמון: המצלמה HAL מאחסנת כמה מאגרים כך שסביר יותר שהוא יושפע מבקשת מאגר איטית מדי פעם.

המצלמה HAL יכולה לאמץ אסטרטגיות שונות עבור מקרי שימוש מסוימים, למשל, שימוש באסטרטגיית שמירת הזיכרון המקסימלית עבור מקרי שימוש המשתמשים בהרבה זיכרון ושימוש באסטרטגיה התואמת לאחור עבור מקרי שימוש אחרים.

יישום לדוגמה במצלמה החיצונית HAL

המצלמה החיצונית HAL הוצגה באנדרואיד 9 וניתן למצוא אותה בעץ המקור בכתובת hardware/interfaces/camera/device/3.5/ . באנדרואיד 10, הוא עודכן כך שיכלול את ExternalCameraDeviceSession.cpp , יישום של ממשק API לניהול מאגר. מצלמה חיצונית HAL זו מיישמת את אסטרטגיית החיסכון המקסימלית בזיכרון המוזכרת באסטרטגיות ניהול מאגר בכמה מאות שורות של קוד C++.