Mécanisme de notification d'événements et de trames

Dans la version précédente d'Exterior View System (EVS), l'interface IEvsCameraStream définissait une seule méthode de rappel pour fournir uniquement les images vidéo capturées. Bien que cela simplifie la mise en œuvre des clients du service EVS, cela rend également difficile pour les clients d'identifier les incidents de streaming et, par conséquent, de les gérer correctement. Pour améliorer l'expérience de développement EVS, AOSP contient désormais un rappel supplémentaire pour diffuser des événements en 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);
};

Cette méthode fournit EvsEventDesc qui se compose de trois champs :

  • Type d'événement.
  • Chaîne permettant d'identifier l'origine de l'événement.
  • 4x données de mots de 32 bits pour contenir d'éventuelles informations sur les événements.
/**
 * 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;
};

Et, pour éviter toute divergence dans la description du tampon graphique entre EVS et d'autres composants graphiques Android, BufferDesc a été redéfini pour utiliser HardwareBuffer importé depuis l'interface android.hardware.graphics.common@1.2. HardwareBuffer contient HardwareBufferDescription , qui est l'homologue HIDL de AHardwareBuffer_Desc d'Android NDK , avec un handle de tampon.

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

Remarque : HardwareBufferDescription est défini comme un tableau de dix mots de 32 bits. Vous souhaiterez peut-être le convertir en type AHardwareBuffer_Desc et remplir le contenu.

EvsEventDesc est une structure d' enum EvsEventType , qui répertorie plusieurs événements de streaming et une charge utile de mots de 32 bits, dans laquelle le développeur peut placer d'éventuelles informations supplémentaires. Par exemple, le développeur peut placer un code d'erreur pour l'événement d'erreur de 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,
};

Livraison du cadre

Avec un nouveau BufferDesc , IEvsCameraStream introduit également de nouvelles méthodes de rappel pour recevoir les images et les événements de streaming des implémentations de service.

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

Une version plus récente d'une méthode de rappel de trame est conçue pour fournir plusieurs descripteurs de tampon. Par conséquent, les implémentations de caméra EVS peuvent transférer plusieurs images par un seul appel si elles gèrent plusieurs sources.

De plus, le protocole précédent permettant de notifier la fin du flux, qui envoyait la trame nulle, a été obsolète et remplacé par l'événement STREAM_STOPPED .

Diagramme de séquence de notification d'événement

Figure 1. Diagramme de séquence de notification d'événement

Utiliser le mécanisme de notification d'événements et de trames

Identifier la version de IEvsCameraStream implémentée par le client

Le service peut identifier la version de l'interface IEvsCameraStream entrante implémentée par le client en tentant de 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 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
    ...
}

rappel notify()

EvsEvent est transmis via le rappel notify() et le client peut ensuite identifier son type en fonction du discriminateur, comme indiqué ci-dessous :

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

Utiliser BufferDesc

AHardwareBuffer_Desc est le type de données d'Android NDK pour représenter un tampon matériel natif qui peut être lié aux primitives EGL/OpenGL et Vulkan. Il contient la plupart des métadonnées de tampon du précédent EVS BufferDesc et, par conséquent, les remplace dans la nouvelle définition de BufferDesc. Cependant, comme il s'agit d'un tableau dans l'interface HIDL, il n'est pas possible d'indexer directement les variables membres. Au lieu de cela, vous pouvez convertir le tableau en un type de AHardwareBuffer_Desc , comme indiqué ci-dessous :

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;