ในระบบภาพจากภายนอก (EVS) เวอร์ชันก่อนหน้า IEvsCameraStream
อินเทอร์เฟซจะกำหนดเมธอดการเรียกกลับรายการเดียวเพื่อส่งเฟรมวิดีโอที่บันทึกไว้เท่านั้น แม้ว่าการติดตั้งใช้งานไคลเอ็นต์บริการ EVS นี้จะลดความซับซ้อนลง แต่ก็ทำให้ไคลเอ็นต์ระบุเหตุการณ์สตรีมมิงได้ยาก และจัดการเหตุการณ์เหล่านั้นอย่างเหมาะสมไม่ได้ ตอนนี้ AOSP มี Callback เพิ่มเติมเพื่อส่งเหตุการณ์สตรีมมิงแล้ว เพื่อปรับปรุงประสบการณ์การพัฒนา EVS
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
ที่ประกอบด้วย 3 ช่อง ดังนี้
- ประเภทของเหตุการณ์
- สตริงเพื่อระบุแหล่งที่มาของเหตุการณ์
- ข้อมูล Word 32 บิต 4 รายการเพื่อเก็บข้อมูลเหตุการณ์ที่เป็นไปได้
/** * 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 ของ AHardwareBuffer_Desc
ของ Android NDK ที่มีแฮนเดิลบัฟเฟอร์
/** * 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 บิต 10 คำ คุณอาจต้องแคสต์เป็นAHardwareBuffer_Desc
type
และป้อนเนื้อหา
EvsEventDesc
คือโครงสร้างของ enum EvsEventType
ซึ่งแสดงรายการเหตุการณ์สตรีมมิงหลายรายการและเพย์โหลดแบบ 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, };
การนำส่งเฟรม
IEvsCameraStream
ยังได้เปิดตัววิธีการเรียกกลับแบบใหม่เพื่อรับเฟรมและเหตุการณ์สตรีมมิงจากการใช้งานบริการด้วย BufferDesc
เวอร์ชันใหม่นี้
/** * 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
Event
รูปที่ 1 แผนภาพลำดับการแจ้งเตือนเหตุการณ์
ใช้กลไกการแจ้งเตือนเหตุการณ์และเฟรม
ระบุเวอร์ชันของ IEvsCameraStream ที่ไคลเอ็นต์นำมาใช้งาน
บริการสามารถระบุเวอร์ชันของอินเทอร์เฟซ IEvsCameraStream ที่เข้ามาซึ่งไคลเอ็นต์ติดตั้งใช้งานโดยพยายามดาวน์แคสต์
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()
EvsEvent
จะส่งผ่านผ่าน notify()
callback และจากนั้นไคลเอ็นต์จะระบุประเภทของ EvsEvent
ได้โดยอิงตามตัวระบุตามที่แสดงด้านล่าง
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 คุณจึงไม่สามารถจัดทําดัชนีตัวแปรสมาชิกได้โดยตรง
แต่คุณสามารถแคสต์อาร์เรย์เป็นประเภท 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;