בגרסה הקודמת של מערכת התצוגה החיצונית (EVS),
IEvsCameraStream
בממשק הגדיר שיטת קריאה חוזרת (callback) יחידה לשליחת סרטון מוקלט
מסגרות בלבד. אומנם הטמעה פשוטה יותר של לקוחות שירות של רכב חשמלי (EVS), אבל היא גם
מקשה על הלקוחות לזהות אירועי סטרימינג, וכתוצאה מכך
כדי לטפל בהן כמו שצריך. כדי לשפר את חוויית הפיתוח של הרכב החשמלי, AOSP כולל עכשיו
קריאה חוזרת (callback) נוספת כדי להעביר אירועי סטרימינג.
package android.hardware.automotive.evs@1.1; import @1.0::IEvsCameraStream; /** * Implemented on client side to receive asynchronous video frame deliveries. */ interface IEvsCameraStream extends @1.0::IEvsCameraStream { /** * Receives calls from the HAL each time a video frame is ready for inspection. * Buffer handles received by this method must be returned via calls to * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call * to IEvsCamera::stopVideoStream(), this callback may continue to happen for * some time as the pipeline drains. Each frame must still be returned. * When the last frame in the stream has been delivered, STREAM_STOPPED * event must be delivered. No further frame deliveries may happen * thereafter. * * @param buffer a buffer descriptor of a delivered image frame. */ oneway deliverFrame_1_1(BufferDesc buffer); /** * Receives calls from the HAL each time an event happens. * * @param event EVS event with possible event information. */ oneway notify(EvsEvent event); };
השיטה הזו מספקת EvsEventDesc
שמורכב משלושה שדות:
- סוג האירוע.
- מחרוזת לזיהוי מקור האירוע.
- נתוני מילים באורך 4x32 ביט שמכילים מידע אפשרי על אירועים.
/** * Structure that describes informative events occurred during EVS is streaming */ struct EvsEvent { /** * Type of an informative event */ EvsEventType aType; /** * Device identifier */ string deviceId; /** * Possible additional information */ uint32_t[4] payload; };
וכדי למנוע סטייה בתיאור של מאגר הנתונים הגרפי בין הרכבים חשמליים (EVS)
ורכיבים גרפיים אחרים של Android, BufferDesc
הוגדר מחדש
יש להשתמש בקובץ HardwareBuffer
שמיובא מממשק android.hardware.graphics.common@1.2.
HardwareBuffer
מכיל/ה HardwareBufferDescription
, שהוא
מקבילה של HIDL ל-Android NDK
AHardwareBuffer_Desc
, עם נקודת אחיזה למאגר הנתונים הזמני.
/** * HIDL counterpart of AHardwareBuffer_Desc. * * An AHardwareBuffer_Desc object can be converted to and from a * HardwareBufferDescription object by memcpy(). * * @sa +ndk libnativewindow#AHardwareBuffer_Desc. */ typedef uint32_t[10] HardwareBufferDescription; /** * HIDL counterpart of AHardwareBuffer. * * AHardwareBuffer_createFromHandle() can be used to convert a HardwareBuffer * object to an AHardwareBuffer object. * * Conversely, AHardwareBuffer_getNativeHandle() can be used to extract a native * handle from an AHardwareBuffer object. Paired with AHardwareBuffer_Desc, * AHardwareBuffer_getNativeHandle() can be used to convert between * HardwareBuffer and AHardwareBuffer. * * @sa +ndk libnativewindow#AHardwareBuffer". */ struct HardwareBuffer { HardwareBufferDescription description; handle nativeHandle; } /** * Structure representing an image buffer through our APIs * * In addition to the handle to the graphics memory, need to retain * the properties of the buffer for easy reference and reconstruction of * an ANativeWindowBuffer object on the remote side of API calls. * Not least because OpenGL expect an ANativeWindowBuffer* for us as a * texture via eglCreateImageKHR(). */ struct BufferDesc { /** * HIDL counterpart of AHardwareBuffer_Desc. Please see * hardware/interfaces/graphics/common/1.2/types.hal for more details. */ HardwareBuffer buffer; /** * The size of a pixel in the units of bytes */ uint32_t pixelSize; /** * Opaque value from driver */ uint32_t bufferId; /** * Unique identifier of the physical camera device that produces this buffer. */ string deviceId; /** * Time that this buffer is being filled */ int64_t timestamp; /** * Frame metadata. This is opaque to EVS manager */ vec<uint8_t> metadata };
הערה: HardwareBufferDescription
מוגדר
שכולל עשר מילים של 32 ביט. כדאי להפעיל Cast שלו כסוג AHardwareBuffer_Desc
וממלאים את התוכן.
EvsEventDesc
הוא מבנה של enum EvsEventType
,
שמפרט כמה אירועי סטרימינג ומטען ייעודי (payload) של מילים באורך של 32 ביט, שבו
יכול לספק מידע נוסף אפשרי. לדוגמה, המפתח
יכול להציב קוד שגיאה עבור אירוע השגיאה בסטרימינג.
/** * Types of informative streaming events */ enum EvsEventType : uint32_t { /** * Video stream is started */ STREAM_STARTED = 0, /** * Video stream is stopped */ STREAM_STOPPED, /** * Video frame is dropped */ FRAME_DROPPED, /** * Timeout happens */ TIMEOUT, /** * Camera parameter is changed; payload contains a changed parameter ID and * its value */ PARAMETER_CHANGED, /** * Master role has become available */ MASTER_RELEASED, };
הצגת פריימים
עם BufferDesc
חדש, IEvsCameraStream
מציג שיטות חדשות להתקשרות חזרה כדי לקבל את הפריימים ואת אירועי הסטרימינג
בהטמעות השירותים.
/** * Implemented on client side to receive asynchronous streaming event deliveries. */ interface IEvsCameraStream extends @1.0::IEvsCameraStream { /** * Receives calls from the HAL each time video frames are ready for inspection. * Buffer handles received by this method must be returned via calls to * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call * to IEvsCamera::stopVideoStream(), this callback may continue to happen for * some time as the pipeline drains. Each frame must still be returned. * When the last frame in the stream has been delivered, STREAM_STOPPED * event must be delivered. No further frame deliveries may happen * thereafter. * * A camera device delivers the same number of frames as number of * backing physical camera devices; it means, a physical camera device * sends always a single frame and a logical camera device sends multiple * frames as many as the number of backing physical camera devices. * * @param buffer Buffer descriptors of delivered image frames. */ oneway deliverFrame_1_1(vec<BufferDesc> buffer); /** * Receives calls from the HAL each time an event happens. * * @param event EVS event with possible event information. */ oneway notify(EvsEventDesc event); };
גרסה חדשה יותר של שיטת קריאה חוזרת של פריים נועדה לספק תיאורי חיץ מרובים. לכן, הטמעות של מצלמות רכב חשמלי (EVS) יכולות להעביר כמה פריימים באמצעות קריאה אחת, אם היא מנהלת מספר מקורות.
בנוסף, הפרוטוקול הקודם כדי להודיע על סיום השידור, שהיה
שליחת מסגרת ה-null, הוצאה משימוש והוחלפה ב-STREAM_STOPPED
אירוע.
איור 1. תרשים של רצף התראות על אירועים
שימוש במנגנון לשליחת התראות לגבי אירועים ומסגרות
זיהוי הגרסה של IEvs CameraStream שהוטמע על ידי הלקוח
השירות יכול לזהות את הגרסה של ממשק IEvs CameraStream הנכנס הוטמע על ידי הלקוח על ידי ניסיון לבצע הורדה נמוכה יותר:
using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream; using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream; Return<EvsResult> EvsV4lCamera::startVideoStream( const sp<IEvsCameraStream_1_0>& stream) { IEvsCameraStream_1_0 aStream = stream; // Try to downcast. This succeeds if the client implements // IEvsCameraStream v1.1. IEvsCameraStream_1_1 aStream_1_1 = IEvsCameraStream_1_1::castFrom(aStream).withDefault(nullptr); if (aStream_1_1 == nullptr) { ALOGI("Start a stream for v1.0 client."); } else { ALOGI("Start a stream for v1.1 client."); } // Start a video stream ... }
notify() callback
EvsEvent
מועבר באמצעות קריאה חוזרת (callback) של notify()
ו
לאחר מכן הלקוח יכול לזהות את הסוג שלו על סמך המבדילה, באופן הבא:
Return<void> StreamHandler::notify(const EvsEvent& event) { ALOGD("Received an event id: %u", event.aType); // Handle each received event. switch(event.aType) { case EvsEventType::ERROR: // Do something to handle an error ... break; [More cases] } return Void(); }
שימוש ב-BufferDesc
AHardwareBuffer_Desc
הוא סוג הנתונים של Android NDK שמייצג מאגר נתונים זמני בחומרה שניתן לקשר
פרימיטיביים של EGL/OpenGL ו-Vulkan. היא מכילה את רוב המטא-נתונים של מאגר הנתונים הזמני
EVS BufferDesc ולכן הוא מחליף אותו בהגדרה החדשה BufferDesc החדשה. אבל, מאחר שכאן
מוגדר כמערך בממשק HIDL, לא ניתן להוסיף ישירות את המשתנים של החברים באינדקס.
במקום זאת, אפשר להפעיל Cast של המערך כסוג של AHardwareBuffer_Desc
, כמו בדוגמה הבאה:
BufferDesc bufDesc = {}; AHardwareBuffer_Desc* pDesc = reinterpret_cast<AHardwareBuffer_Desc *>(&bufDesc.buffer.description); pDesc->width = mVideo.getWidth(); pDesc->height = mVideo.getHeight(); pDesc->layers = 1; pDesc->format = mFormat; pDesc->usage = mUsage; pDesc->stride = mStride; bufDesc_1_1.buffer.nativeHandle = mBuffers[idx].handle; bufDesc_1_1.bufferId = idx;