กลไกการแจ้งเตือนเหตุการณ์และเฟรม

ใน Exterior View System (EVS) รุ่นก่อนหน้า IEvsCameraStream อินเทอร์เฟซที่กำหนดเมธอด Callback เดียวเพื่อส่งวิดีโอที่บันทึกไว้ เฟรมเท่านั้น แม้ว่าการใช้บริการ EVS ของลูกค้าจะง่ายขึ้น แต่ ทำให้ลูกค้าระบุเหตุการณ์สตรีมได้ยาก ดังนั้น เพื่อจัดการอย่างเหมาะสม เพื่อปรับปรุงประสบการณ์การพัฒนา 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 ซึ่งประกอบด้วย 3 ช่อง

  • ประเภทของกิจกรรม
  • สตริงสำหรับระบุต้นทางของเหตุการณ์
  • ข้อมูลคำแบบ 4x 32 บิตเพื่อให้มีข้อมูลเหตุการณ์ที่เป็นไปได้
/**
 * 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 บิต 10 คำ คุณอาจต้องแคสต์เป็นประเภทAHardwareBuffer_Desc แล้วใส่เนื้อหาลงไป

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
,
};

การนำส่งเฟรม

มี BufferDesc ใหม่ IEvsCameraStream ด้วย แนะนำเมธอด Callback ใหม่เพื่อรับเฟรมและเหตุการณ์สตรีมมิง จากการติดตั้งใช้งานบริการ

/**
 * 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);
};

เวอร์ชันใหม่ของ Method Callback ของเฟรมออกแบบมาเพื่อแสดง ตัวบ่งชี้บัฟเฟอร์หลายรายการ ดังนั้น การใช้งานกล้อง EVS จึงสามารถส่งต่อ หลายเฟรมตามการเรียกครั้งเดียว หากโค้ดจัดการแหล่งที่มาหลายแหล่ง

นอกจากนี้ โปรโตคอลก่อนหน้านี้ที่ใช้แจ้งเตือนเกี่ยวกับช่วงท้ายของสตรีม ซึ่งก็คือ การส่งเฟรม Null เลิกใช้งานแล้วและแทนที่ด้วย STREAM_STOPPED กิจกรรม

แผนภาพลำดับการแจ้งเตือนเหตุการณ์

รูปที่ 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() Callback

EvsEvent ผ่านการติดต่อกลับของ notify() และ ไคลเอ็นต์จะระบุประเภทของตนตาม Disriminator ตามที่ปรากฏด้านล่าง

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 Primes ซึ่งมีข้อมูลเมตาส่วนใหญ่ของบัฟเฟอร์จากก่อนหน้านี้ ด้วยเหตุนี้ 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;