ב-Android 10 הוצגו ממשקי API אופציונליים לניהול מאגרים של camera HAL3, שמאפשרים לכם להטמיע לוגיקה של ניהול מאגרים כדי להשיג פשרות שונות בין זיכרון לבין חביון של לכידת תמונות בהטמעות של camera HAL.
ה-HAL של המצלמה דורש שבתור שלו ימתינו N בקשות (כאשר N שווה לעומק צינור עיבוד הנתונים), אבל לרוב הוא לא דורש את כל N קבוצות של מאגרי פלט בו-זמנית.
לדוגמה, יכול להיות ש-HAL יכלול שמונה בקשות בתור בצינור, אבל הוא יצטרך רק מאגרי פלט לשתי הבקשות בשלבים האחרונים של הצינור. במכשירים עם Android 9 ומטה, מסגרת המצלמה מקצה מאגרי נתונים כשמכניסים את הבקשה לתור ב-HAL, כך שיכולים להיות שישה סטים של מאגרי נתונים ב-HAL שלא נמצאים בשימוש. ב-Android 10, ממשקי ה-API לניהול מאגרים של HAL3 במצלמה מאפשרים להפריד את מאגרי הפלט כדי לפנות את ששת מאגרי המידע. השימוש ב-API הזה יכול לחסוך מאות מגה-בייט של זיכרון במכשירים מתקדמים, ויכול להיות שימושי גם במכשירים עם זיכרון מוגבל.
איור 1 מציג דיאגרמה של ממשק HAL של המצלמה במכשירים עם Android מגרסה 9 ומגרסאות קודמות. איור 2 מציג את הממשק של HAL המצלמה ב-Android 10 עם ממשקי ה-API לניהול מאגרים של HAL3 המצלמה שהוטמעו.
איור 1. ממשק Camera HAL ב-Android 9 ובגרסאות קודמות
איור 2. ממשק HAL של המצלמה ב-Android 10 באמצעות ממשקי ה-API לניהול מאגרים
הטמעה של ממשקי ה-API לניהול מאגרים
כדי להטמיע את ממשקי ה-API לניהול מאגרים, ה-HAL של המצלמה צריך:
- יישום HIDL
[email protected]
. - מגדירים את מפתח מאפייני המצלמה
android.info.supportedBufferManagementVersion
לערךHIDL_DEVICE_3_5
.
רכיב 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 של מצלמה לא מחזיקה יותר מאגרים מהנדרש, יכול להיות שההטמעה של השיטה הזו תהיה ריקה.
אחרי ש-framework המצלמה קורא ל-signalStreamFlush
, ה-framework מפסיק לשלוח בקשות חדשות לצילום ל-HAL של המצלמה עד שכל המאגרים מוחזרים ל-framework של המצלמה. כשכל המאגרים מוחזרים, קריאות השיטה requestStreamBuffers
נכשלות ומסגרת המצלמה יכולה להמשיך את העבודה שלה במצב נקי. לאחר מכן, מסגרת המצלמה קוראת לשיטה configureStreams
או לשיטה processCaptureRequest
. אם מסגרת המצלמה קוראת לשיטה configureStreams
, ה-HAL של המצלמה יכול להתחיל לבקש שוב מאגרי נתונים זמניים אחרי שהקריאה ל-configureStreams
חוזרת בהצלחה. אם מסגרת המצלמה קוראת לשיטה processCaptureRequest
, HAL של המצלמה יכול להתחיל לבקש מאגרי נתונים במהלך הקריאה ל-processCaptureRequest
.
הסמנטיקה שונה בין השיטה signalStreamFlush
לבין השיטה flush
. כשמפעילים את השיטה flush
, ה-HAL יכול לבטל בקשות צילום בהמתנה באמצעות ERROR_REQUEST
כדי לנקות את הצינור בהקדם האפשרי. כשמפעילים את השיטה signalStreamFlush
, שכבת ה-HAL צריכה לסיים את כל בקשות הצילום בהמתנה בצורה רגילה ולהחזיר את כל המאגרים למסגרת המצלמה.
הבדל נוסף בין קוד ה-method signalStreamFlush
לבין קודים אחרים הוא ש-signalStreamFlush
הוא קוד HIDL חד-כיווני, כלומר יכול להיות שקוד ה-framework של המצלמה יקרא לממשקי API חוסמים אחרים לפני ששכבת ה-HAL תקבל את הקריאה ל-signalStreamFlush
. המשמעות היא שה-method signalStreamFlush
ו-methods אחרים (במיוחד ה-method 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 של מצלמה חיצונית הוצג ב-Android 9 ואפשר למצוא אותו בעץ המקור בכתובת hardware/interfaces/camera/device/3.5/
.
ב-Android 10, הוא עודכן כך שיכלול את ExternalCameraDeviceSession.cpp
, הטמעה של ה-API לניהול מאגרים. HAL של המצלמה החיצונית הזו מיישם את אסטרטגיית החיסכון המקסימלית בזיכרון שמוזכרת באסטרטגיות לניהול מאגרים בכמה מאות שורות של קוד C++.