Mecanismo de notificação de eventos e quadros

Na versão anterior do Exterior View System (EVS), a interface IEvsCameraStream definia um único método de retorno de chamada para entregar apenas quadros de vídeo capturados. Embora isso tenha simplificado as implementações dos clientes do serviço SVE, também tornou difícil para os clientes identificar quaisquer incidentes de streaming e, portanto, tratá-los adequadamente. Para aprimorar a experiência de desenvolvimento do EVS, o AOSP agora contém um retorno de chamada adicional para entregar eventos de 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);
};

Este método fornece EvsEventDesc que consiste em três campos:

  • Tipo do evento.
  • String para identificar a origem do evento.
  • 4x dados de palavras de 32 bits para conter possíveis informações de eventos.
/**
 * 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;
};

E, para evitar qualquer divergência na descrição do buffer gráfico entre o EVS e outros componentes gráficos do Android, BufferDesc foi redefinido para usar HardwareBuffer importado da interface android.hardware.graphics.common@1.2. HardwareBuffer contém HardwareBufferDescription , que é a contraparte HIDL do AHardwareBuffer_Desc do Android NDK , com um identificador de 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
};

Nota: HardwareBufferDescription é definido como uma matriz de dez palavras de 32 bits. Você pode querer convertê-lo como tipo AHardwareBuffer_Desc e preencher o conteúdo.

EvsEventDesc é uma estrutura de enum EvsEventType , que lista vários eventos de streaming e uma carga útil de palavras de 32 bits, na qual o desenvolvedor pode colocar possíveis informações adicionais. Por exemplo, o desenvolvedor pode colocar um código de erro para o evento de erro 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,
};

Entrega de quadros

Com um novo BufferDesc , IEvsCameraStream também introduz novos métodos de retorno de chamada para receber os frames e eventos de streaming das implementações de serviço.

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

Uma versão mais recente de um método de retorno de chamada de quadro foi projetada para fornecer vários descritores de buffer. Portanto, as implementações de câmeras EVS podem encaminhar vários quadros por uma única chamada se gerenciarem múltiplas fontes.

Além disso, o protocolo anterior para notificar o fim do fluxo, que enviava o quadro nulo, foi descontinuado e substituído pelo evento STREAM_STOPPED .

Diagrama de sequência de notificação de eventos

Figura 1. Diagrama de sequência de notificação de eventos

Use mecanismo de notificação de eventos e quadros

Identifique a versão do IEvsCameraStream implementada pelo cliente

O serviço pode identificar a versão da interface IEvsCameraStream de entrada implementada pelo cliente tentando fazer 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
    ...
}

notificar() retorno de chamada

EvsEvent é passado através do callback notify() e o cliente pode então identificar seu tipo com base no discriminador, conforme mostrado abaixo:

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

Usar BufferDesc

AHardwareBuffer_Desc é o tipo de dados do Android NDK para representar um buffer de hardware nativo que pode ser vinculado a primitivos EGL/OpenGL e Vulkan. Ele contém a maior parte dos metadados do buffer do EVS BufferDesc anterior e, portanto, os substitui na nova definição do BufferDesc. No entanto, como é definido como um array na interface HIDL, não é possível indexar diretamente as variáveis ​​dos membros. Em vez disso, você pode converter o array como um tipo de AHardwareBuffer_Desc , conforme mostrado abaixo:

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;