Mekanisme Pemberitahuan Acara dan Bingkai

Dalam rilis Exterior View System (EVS) sebelumnya, antarmuka IEvsCameraStream mendefinisikan metode callback tunggal untuk mengirimkan frame video yang diambil saja . Sementara implementasi klien layanan EVS yang disederhanakan ini, juga mempersulit klien untuk mengidentifikasi insiden streaming apa pun dan, oleh karena itu, untuk menanganinya dengan benar. Untuk meningkatkan pengalaman pengembangan EVS, AOSP sekarang berisi panggilan balik tambahan untuk mengirimkan acara streaming.

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

Metode ini memberikan EvsEventDesc yang terdiri dari tiga bidang:

  • Jenis acara.
  • String untuk mengidentifikasi asal acara.
  • Data kata 4x 32-bit untuk memuat informasi acara yang mungkin.
/**
 * 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;
};

Dan, untuk menghindari perbedaan dalam deskripsi buffer grafis antara EVS dan komponen grafis Android lainnya, BufferDesc telah didefinisikan ulang untuk menggunakan HardwareBuffer yang diimpor dari antarmuka android.hardware.graphics.common@1.2. HardwareBuffer berisi HardwareBufferDescription , yang merupakan mitra HIDL dari AHardwareBuffer_Desc Android NDK , dengan pegangan buffer.

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

Catatan: HardwareBufferDescription didefinisikan sebagai larik sepuluh kata 32-bit. Anda mungkin ingin memasukkannya sebagai tipe AHardwareBuffer_Desc dan mengisi isinya.

EvsEventDesc adalah struct dari enum EvsEventType , yang mencantumkan beberapa peristiwa streaming dan payload kata 32-bit, di mana pengembang dapat menempatkan kemungkinan informasi tambahan. Misalnya, pengembang dapat menempatkan kode kesalahan untuk peristiwa kesalahan streaming.

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

Pengiriman Bingkai

Dengan BufferDesc baru, IEvsCameraStream juga memperkenalkan metode panggilan balik baru untuk menerima frame dan acara streaming dari implementasi layanan.

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

Versi yang lebih baru dari metode panggilan balik bingkai dirancang untuk memberikan beberapa deskriptor buffer. Oleh karena itu, implementasi kamera EVS dapat meneruskan beberapa frame dengan satu panggilan jika mengelola banyak sumber.

Selain itu, protokol sebelumnya untuk memberitahukan akhir aliran, yang mengirimkan bingkai nol, telah ditinggalkan dan diganti dengan acara STREAM_STOPPED .

Diagram urutan pemberitahuan acara

Gambar 1. Diagram urutan pemberitahuan acara

Menggunakan Mekanisme Notifikasi Acara dan Bingkai

Mengidentifikasi Versi IevsCameraStream yang Diimplementasikan oleh Klien

Layanan dapat mengidentifikasi versi antarmuka IEvsCameraStream masuk yang diimplementasikan oleh klien dengan mencoba melakukan downcast:

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 will succeed 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
    ...
}

beri tahu() Panggilan balik

EvsEvent akan diteruskan melalui callback notify() dan klien kemudian dapat mengidentifikasi jenisnya berdasarkan diskriminator, seperti yang ditunjukkan di bawah ini:

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();
}

Menggunakan BufferDesc

AHardwareBuffer_Desc adalah tipe data Android NDK untuk mewakili buffer perangkat keras asli yang dapat diikat ke primitif EGL/OpenGL dan Vulkan. Ini berisi sebagian besar metadata buffer dari EVS BufferDesc sebelumnya dan, oleh karena itu, menggantikannya dalam definisi BufferDesc yang baru. Namun, karena ini didefinisikan sebagai larik dalam antarmuka HIDL, tidak mungkin untuk mengindeks variabel anggota secara langsung. Sebagai gantinya, Anda dapat mentransmisikan array sebagai tipe AHardwareBuffer_Desc , seperti yang ditunjukkan di bawah ini:

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;