آلية إعلام الحدث والإطار

في الإصدار السابق من نظام العرض الخارجي (EVS)، حددت واجهة IEvsCameraStream طريقة رد اتصال واحدة لتقديم إطارات الفيديو الملتقطة فقط . على الرغم من أن هذا قد أدى إلى تبسيط عمليات تنفيذ عميل خدمة EVS، إلا أنه جعل من الصعب أيضًا على العملاء تحديد أي حوادث تدفق، وبالتالي التعامل معها بشكل صحيح. لتعزيز تجربة تطوير EVS، يحتوي AOSP الآن على رد اتصال إضافي لتقديم أحداث البث.

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

توفر هذه الطريقة EvsEventDesc الذي يتكون من ثلاثة حقول:

  • نوع الحدث.
  • سلسلة لتحديد أصل الحدث.
  • 4x بيانات كلمة 32 بت تحتوي على معلومات الحدث المحتملة.
/**
 * 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;
};

ولتجنب أي اختلاف في وصف المخزن المؤقت للرسومات بين EVS ومكونات Android الرسومية الأخرى، تمت إعادة تعريف BufferDesc لاستخدام HardwareBuffer المستورد من واجهة android.hardware.graphics.common@1.2. يحتوي HardwareBuffer على HardwareBufferDescription ، وهو نظير HIDL لنظام AHardwareBuffer_Desc الخاص بنظام Android NDK ، مع مقبض مخزن مؤقت.

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

ملاحظة: يتم تعريف HardwareBufferDescription على أنه مصفوفة مكونة من عشر كلمات بطول 32 بت. قد ترغب في تحويله إلى نوع AHardwareBuffer_Desc وملء المحتويات.

EvsEventDesc عبارة عن بنية من enum EvsEventType ، والتي تسرد العديد من أحداث البث وحمولة كلمات 32 بت، والتي يمكن للمطور أن يضع فيها معلومات إضافية محتملة. على سبيل المثال، يمكن للمطور وضع رمز خطأ لحدث خطأ الدفق.

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

تسليم الإطار

مع BufferDesc الجديد، يقدم IEvsCameraStream أيضًا طرق رد اتصال جديدة لتلقي الإطارات وأحداث التدفق من تطبيقات الخدمة.

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

تم تصميم إصدار أحدث من أسلوب رد اتصال الإطار لتقديم واصفات المخزن المؤقت المتعددة. لذلك، يمكن لتطبيقات كاميرا EVS إعادة توجيه إطارات متعددة من خلال مكالمة واحدة إذا كانت تدير مصادر متعددة.

أيضًا، تم إهمال البروتوكول السابق للإعلام بنهاية الدفق، والذي كان يرسل الإطار الفارغ، واستبداله بالحدث STREAM_STOPPED .

مخطط تسلسل إشعار الحدث

الشكل 1. مخطط تسلسل إشعار الحدث

استخدم آلية إعلام الحدث والإطار

تحديد إصدار IEvsCameraStream الذي تم تنفيذه بواسطة العميل

يمكن للخدمة التعرف على إصدار واجهة IEvsCameraStream الواردة التي ينفذها العميل من خلال محاولة البث الهابط:

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

إعلام () رد الاتصال

يتم تمرير EvsEvent من خلال رد اتصال notify() ويمكن للعميل بعد ذلك تحديد نوعه بناءً على أداة التمييز، كما هو موضح أدناه:

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

AHardwareBuffer_Desc هو نوع بيانات Android NDK لتمثيل المخزن المؤقت الأصلي للأجهزة الذي يمكن ربطه ببدائل EGL/OpenGL وVulkan. فهو يحتوي على معظم بيانات تعريف المخزن المؤقت من EVS BufferDesc السابق، وبالتالي، يستبدلها في تعريف BufferDesc الجديد. ومع ذلك، نظرًا لأنه يتم تعريفه على أنه مصفوفة في واجهة HIDL، فمن غير الممكن فهرسة متغيرات الأعضاء مباشرة. بدلًا من ذلك، يمكنك تحويل المصفوفة كنوع من AHardwareBuffer_Desc ، كما هو موضح أدناه:

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;