Mecanismo de notificación de eventos y marcos.

En la versión anterior de Exterior View System (EVS), la interfaz IEvsCameraStream definió un único método de devolución de llamada para entregar únicamente fotogramas de vídeo capturados. Si bien esto simplificó las implementaciones de los clientes del servicio EVS, también dificultó que los clientes identificaran cualquier incidente de transmisión y, por lo tanto, manejarlos adecuadamente. Para mejorar la experiencia de desarrollo de EVS, AOSP ahora contiene una devolución de llamada adicional para ofrecer eventos 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);
};

Este método entrega EvsEventDesc que consta de tres campos:

  • Tipo de evento.
  • Cadena para identificar el origen del evento.
  • 4x datos de palabras de 32 bits para contener posible información 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;
};

Y, para evitar cualquier divergencia en la descripción del búfer de gráficos entre EVS y otros componentes gráficos de Android, BufferDesc se ha redefinido para utilizar HardwareBuffer importado desde la interfaz android.hardware.graphics.common@1.2. HardwareBuffer contiene HardwareBufferDescription , que es la contraparte HIDL de AHardwareBuffer_Desc de Android NDK , con un identificador de búfer.

/**
 * 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 se define como una matriz de diez palabras de 32 bits. Es posible que desee convertirlo como tipo AHardwareBuffer_Desc y completar el contenido.

EvsEventDesc es una estructura de enum EvsEventType , que enumera varios eventos de transmisión y una carga útil de palabras de 32 bits, en la que el desarrollador puede colocar posible información adicional. Por ejemplo, el desarrollador puede colocar un código de error para el evento de error de transmisión.

/**
 * 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 cuadros

Con un nuevo BufferDesc , IEvsCameraStream también introduce nuevos métodos de devolución de llamada para recibir fotogramas y eventos de transmisión de las implementaciones del servicio.

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

Una versión más nueva de un método de devolución de llamada de marco está diseñada para entregar múltiples descriptores de búfer. Por lo tanto, las implementaciones de cámaras EVS pueden reenviar múltiples cuadros mediante una sola llamada si administran múltiples fuentes.

Además, el protocolo anterior para notificar el final de la transmisión, que enviaba la trama nula, ha quedado obsoleto y reemplazado por el evento STREAM_STOPPED .

Diagrama de secuencia de notificación de eventos

Figura 1. Diagrama de secuencia de notificación de eventos

Utilice el mecanismo de notificación de eventos y marcos.

Identificar la versión de IEvsCameraStream implementada por el cliente

El servicio puede identificar la versión de la interfaz IEvsCameraStream entrante implementada por el cliente al intentar realizar el 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() devolución de llamada

EvsEvent se pasa a través de la devolución de llamada notify() y el cliente puede identificar su tipo según el discriminador, como se muestra a continuación:

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 es el tipo de datos del NDK de Android para representar un búfer de hardware nativo que se puede vincular a primitivas EGL/OpenGL y Vulkan. Contiene la mayoría de los metadatos del búfer del EVS BufferDesc anterior y, por lo tanto, los reemplaza en la nueva definición de BufferDesc. Sin embargo, como esto se define como una matriz en la interfaz HIDL, no es posible indexar las variables miembro directamente. En su lugar, puede convertir la matriz como un tipo de AHardwareBuffer_Desc , como se muestra a continuación:

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;