Etkinlik ve çerçeve bildirim mekanizması

Dış Görünüm Sistemi'nin (EVS) önceki sürümünde, IEvsCameraStream arayüzde, yakalanan video karelerini yalnızca yayınlamak için tek bir geri çağırma yöntemi tanımlanıyordu. Bu, EVS hizmeti istemci uygulamalarını basitleştirirken istemcilerin herhangi bir akış olayı tespit etmesini ve dolayısıyla bunları düzgün bir şekilde ele almasını zorlaştırdı. EVS geliştirme deneyimini iyileştirmek için AOSP'de artık akış etkinliklerini yayınlamak üzere ek bir geri çağırma işlevi yer alıyor.

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

Bu yöntem, üç alandan oluşan EvsEventDesc değerini döndürür:

  • Etkinliğin türü.
  • Etkinliğin kaynağını tanımlayan dize.
  • Olası etkinlik bilgilerini içeren 4x 32 bit kelime verisi.
/**
 * 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;
};

Ayrıca, EVS ile diğer Android grafik bileşenleri arasındaki grafik arabellek açıklamasında herhangi bir farklılık olmaması için BufferDesc, android.hardware.graphics.common@1.2 arayüzünden içe aktarılan HardwareBuffer değerini kullanacak şekilde yeniden tanımlandı. HardwareBuffer, Android NDK'nın AHardwareBuffer_Desc işlevinin HIDL karşılığı olan HardwareBufferDescription öğesini bir arabellek tutamacıyla içerir.

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

Not: HardwareBufferDescription, on adet 32 bitlik kelime dizisi olarak tanımlanır. AHardwareBuffer_Desc türü olarak yayınlayıp içeriği doldurabilirsiniz.

EvsEventDesc, geliştiricinin olası ek bilgileri yerleştirebileceği birkaç akış etkinliğini ve 32 bitlik bir kelime yükü listeleyen bir enum EvsEventType yapısıdır. Örneğin, geliştirici akış hatası etkinliği için bir hata kodu yerleştirebilir.

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

Kare yayınlama

Yeni BufferDesc ile IEvsCameraStream, hizmet uygulamalarından kareleri ve akış etkinliklerini almak için yeni geri çağırma yöntemleri de sunar.

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

Çerçeve geri çağırma yönteminin daha yeni bir sürümü, birden fazla arabellek tanımlayıcısı sağlamak için tasarlanmıştır. Bu nedenle, EVS kamera uygulamaları birden fazla kaynağı yönetiyorsa tek bir çağrıyla birden fazla kare iletebilir.

Ayrıca, yayının sonunu bildirmek için kullanılan ve null çerçevesi gönderen önceki protokolün desteği sonlandırıldı ve STREAM_STOPPED etkinliğiyle değiştirildi.

Etkinlik bildirimi ardışık düzen şeması

Şekil 1. Etkinlik bildirimi sıra şeması

Etkinlik ve çerçeve bildirim mekanizmasını kullanma

İstemci tarafından uygulanan IEvsCameraStream sürümünü belirleme

Hizmet, aşağıdakileri aşağı aktarmayı deneyerek istemci tarafından uygulanan gelen IEvsCameraStream arayüzünün sürümünü tanımlayabilir:

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() geri çağırma işlevi

EvsEvent, notify() geri çağırma işlevi aracılığıyla iletilir ve istemci, türünü ayırıcıya göre tanımlayabilir (aşağıda gösterildiği gibi):

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'i kullanma

AHardwareBuffer_Desc Android NDK'nın, EGL/OpenGL ve Vulkan primitiflerine bağlanabilen yerel bir donanım arabelleğini temsil etmek için kullandığı veri türüdür. Önceki EVS BufferDesc'deki alt bellek meta verilerinin çoğunu içerir ve bu nedenle yeni BufferDesc tanımında onun yerini alır. Ancak bu, HIDL arayüzünde dizi olarak tanımlandığından üye değişkenlerini doğrudan dizine eklemek mümkün değildir. Bunun yerine, diziyi aşağıdaki gibi bir AHardwareBuffer_Desc türü olarak yayınlayabilirsiniz:

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;