Android EvsHal

一、EvsHal相关接口

IEvsCamera

一个IEvsCamera对象即代表一个Camera,主要接口为捕获图像

IEvsCamera文件路径:

hardware/interfaces/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCamera.aidl

IEvsCamera定义:

interface IEvsCamera {}

IEvsCamera方法:

getCameraInfo() generates (CameraDesc info):返回IEvsCamera对象所代表Camera的CameraDesc
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result):设置MaxFrames
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result):请求Camera传输 EVS camera frames 
oneway doneWithFrame(BufferDesc buffer):返回由IEvsCameraStream传递的frame
stopVideoStream():停止传递EVS camera frames. 
getExtendedInfo(int32 opaqueIdentifier) generates (int32 value):从HAL中获取driver-specific信息
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result):设置driver-specific value 给Evs Hal

IEvsCameraStream

客户端实现接口以接收异步传输的video frame

IEvsCameraStream文件路径:

hardware/interfaces/automotive/evs/aidl/android/hardware/automotive/evs/IEvsCameraStream.aidl

IEvsCameraStream定义:

oneway interface IEvsCameraStream {

IEvsCameraStream方法:

deliverFrame(BufferDesc buffer):从HAL接收调用,返回每次准备好的video frame

IEvsDisplay

EVS显示对象,可控制显示状态,并处理图像的实际呈现效果

IEvsDisplay文件路径:

hardware/interfaces/automotive/evs/aidl/android/hardware/automotive/evs/IEvsDisplay.aidl

IEvsDisplay定义:

interface IEvsDisplay {}

IEvsDisplay方法:

getDisplayInfo() generates (DisplayDesc info):返回EVS Display的基本信息
setDisplayState(DisplayState state) generates (EvsResult result):设置显示状态
getDisplayState() generates (DisplayState state): 获取显示状态
getTargetBuffer() generates (handle bufferHandle):返回一个与Display关联的处理frame buffer的handle
returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result):告诉Display相关buffer已准备好可供显示

IEvsEnumerator

负责枚举系统中可用的EVS硬件

IEvsEnumerator文件路径:

hardware/interfaces/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumerator.aidl

IEvsEnumerator定义:

interface IEvsEnumerator {}

IEvsEnumerator方法:

getCameraList() generates (vec<CameraDesc> cameras):返回一个包含系统中所有摄像机的描述的向量。CameraDesc结构体
openCamera(string camera_id) generates (IEvsCamera camera):获取一个以参数camera_idb标识的IEvsCamera对象
closeCamera(IEvsCamera camera):释放IEvsCamera对象,与openCamera相反
openDisplay() generates (IEvsDisplay display):获取一个以EVS Display单独交互的IEvsDisplay对象
closeDisplay(IEvsDisplay display):释放IEvsDisplay对象,与openDisplay相反
getDisplayState() generates (DisplayState state):获取当前Display状态

IEvsEnumeratorStatusCallback

Camera设备状态变更回调

IEvsEnumeratorStatusCallback文件路径:

hardware/interfaces/automotive/evs/aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.aidl

IEvsEnumeratorStatusCallback定义:

interface IEvsEnumeratorStatusCallback {}

IEvsEnumeratorStatusCallback方法:

void deviceStatusChanged(in android.hardware.automotive.evs.DeviceStatus[] status):Camera设备状态变化

二、EvsHal相关流程分析

EvsHal启动流程分析

EvsHal是一个独立的进程,在init.rc启动,如下是EvsHal的main函数:

//packages/service/Car/cpp/evs/sampleDriver/aidl/src/service.cpp
int main() {
    LOG(INFO) << "EVS Hardware Enumerator service is starting";


    const std::string displayServiceInstanceName =
            std::string(ICarDisplayProxy::descriptor) + std::string(kDisplayServiceInstanceName);
    if (!AServiceManager_isDeclared(displayServiceInstanceName.data())) {
        // TODO: We may just want to disable EVS display.
        LOG(ERROR) << displayServiceInstanceName << " is required.";
        return EXIT_FAILURE;
    }


    std::shared_ptr<ICarDisplayProxy> displayService = ICarDisplayProxy::fromBinder(
            ::ndk::SpAIBinder(AServiceManager_waitForService(displayServiceInstanceName.data())));
    if (!displayService) {
        LOG(ERROR) << "Cannot use " << displayServiceInstanceName << ".  Exiting.";
        return EXIT_FAILURE;
    }


    // Register our service -- if somebody is already registered by our name,
    // they will be killed (their thread pool will throw an exception).
    std::shared_ptr<EvsEnumerator> service =
            ndk::SharedRefBase::make<EvsEnumerator>(displayService);
    if (!service) {
        LOG(ERROR) << "Failed to instantiate the service";
        return EXIT_FAILURE;
    }


    std::atomic<bool> running{true};
    std::thread hotplugHandler(EvsEnumerator::EvsHotplugThread, service, std::ref(running)); //创建EvsHotplugThread线程


    const std::string instanceName =
            std::string(EvsEnumerator::descriptor) + std::string(kHwInstanceName);
    auto err = AServiceManager_addService(service->asBinder().get(), instanceName.data());
    if (err != EX_NONE) {
        LOG(ERROR) << "Failed to register " << instanceName << ", exception = " << err;
        return EXIT_FAILURE;
    }


    if (!ABinderProcess_setThreadPoolMaxThreadCount(kNumBinderThreads)) {
        LOG(ERROR) << "Failed to set thread pool";
        return EXIT_FAILURE;
    }


    ABinderProcess_startThreadPool();
    LOG(INFO) << "EVS Hardware Enumerator is ready";


    ABinderProcess_joinThreadPool();
    // In normal operation, we don't expect the thread pool to exit
    LOG(INFO) << "EVS Hardware Enumerator is shutting down";


    // Exit a hotplug device thread
    running = false;
    if (hotplugHandler.joinable()) {
        hotplugHandler.join();
    }


    return EXIT_SUCCESS;
}

创建并开始EvsHotplugThread线程:

//packages/services/Car/cpp/evs/sampleDriver/aidl/src/EvsEnumerator.cpp
void EvsEnumerator::EvsHotplugThread(std::shared_ptr<EvsEnumerator> service,
                                     std::atomic<bool>& running) {
    // Watch new video devices
    if (!service) {
        LOG(ERROR) << "EvsEnumerator is invalid";
        return;
    }


    auto notifyFd = inotify_init();
    if (notifyFd < 0) {
        LOG(ERROR) << "Failed to initialize inotify.  Exiting a thread loop";
        return;
    }


    int watchFd = inotify_add_watch(notifyFd, kDevicePath.data(), IN_CREATE | IN_DELETE);
    if (watchFd < 0) {
        LOG(ERROR) << "Failed to add a watch.  Exiting a thread loop";
        return;
    }


    LOG(INFO) << "Start monitoring new V4L2 devices";


    char eventBuf[kEventBufferSize] = {};
    while (running) {
        size_t len = read(notifyFd, eventBuf, sizeof(eventBuf));
        if (len < sizeof(struct inotify_event)) {
            // We have no valid event.
            continue;
        }


        size_t offset = 0;
        while (offset < len) {
            struct inotify_event* event =
                    reinterpret_cast<struct inotify_event*>(&eventBuf[offset]);
            offset += sizeof(struct inotify_event) + event->len;
            if (event->wd != watchFd || strncmp(kPrefix.data(), event->name, kPrefix.size())) {
                continue;
            }


            std::string deviceName = std::string(kDevicePath) + std::string(event->name);
            if (event->mask & IN_CREATE) {
                if (addCaptureDevice(deviceName)) {
                    service->notifyDeviceStatusChange(deviceName,
                                                      DeviceStatusType::CAMERA_AVAILABLE);
                }
            }


            if (event->mask & IN_DELETE) {
                if (removeCaptureDevice(deviceName)) {
                    service->notifyDeviceStatusChange(deviceName,
                                                      DeviceStatusType::CAMERA_NOT_AVAILABLE);
                }
            }
        }
    }
}

在EvsHotplugThread线程中循环的读取V4L2 devices状态,如果有新的设备调用如下方法:

1、调用addCaptureDevice方法,添加采集设备。

2、调用service(EvsEnumerator)的notifyDeviceStatusChange方法,通知设备状态变化。

下面分别进行分析:

EvsEnumerator addCaptureDevice

调用addCaptureDevice方法:

//packages/services/Car/cpp/evs/sampleDriver/aidl/src/EvsEnumerator.cpp
bool EvsEnumerator::addCaptureDevice(const std::string& deviceName) {
    if (!qualifyCaptureDevice(deviceName.data())) {
        LOG(DEBUG) << deviceName << " is not qualified for this EVS HAL implementation";
        return false;
    }


    CameraRecord cam(deviceName.data());
    if (sConfigManager) {
        std::unique_ptr<ConfigManager::CameraInfo>& camInfo =
                sConfigManager->getCameraInfo(deviceName); //获取Camera设备信息
        if (camInfo) {
            uint8_t* ptr = reinterpret_cast<uint8_t*>(camInfo->characteristics);
            const size_t len = get_camera_metadata_size(camInfo->characteristics);
            cam.desc.metadata.insert(cam.desc.metadata.end(), ptr, ptr + len);
        }
    }


    {
        std::lock_guard lock(sLock);
        // insert_or_assign() returns std::pair<std::unordered_map<>, bool>
        auto result = sCameraList.insert_or_assign(deviceName, std::move(cam));
        LOG(INFO) << deviceName << (std::get<1>(result) ? " is added" : " is modified");
    }


    return true;
}

调用qualifyCaptureDevice方法打开设备:

//packages/services/Car/cpp/evs/sampleDriver/aidl/src/EvsEnumerator.cpp
bool EvsEnumerator::qualifyCaptureDevice(const char* deviceName) {
    class FileHandleWrapper {
    public:
        FileHandleWrapper(int fd) { mFd = fd; }
        ~FileHandleWrapper() {
            if (mFd > 0) close(mFd);
        }
        operator int() const { return mFd; }


    private:
        int mFd = -1;
    };


    FileHandleWrapper fd = open(deviceName, O_RDWR, 0);
    if (fd < 0) {
        return false;
    }


    v4l2_capability caps;
    int result = ioctl(fd, VIDIOC_QUERYCAP, &caps);
    if (result < 0) {
        return false;
    }
    if (((caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) ||
        ((caps.capabilities & V4L2_CAP_STREAMING) == 0)) {
        return false;
    }


    // Enumerate the available capture formats (if any)
    v4l2_fmtdesc formatDescription;
    formatDescription.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    bool found = false;
    for (int i = 0; !found; ++i) {
        formatDescription.index = i;
        if (ioctl(fd, VIDIOC_ENUM_FMT, &formatDescription) == 0) {
            LOG(DEBUG) << "Format: 0x" << std::hex << formatDescription.pixelformat << " Type: 0x"
                       << std::hex << formatDescription.type
                       << " Desc: " << formatDescription.description << " Flags: 0x" << std::hex
                       << formatDescription.flags;
            switch (formatDescription.pixelformat) {
                case V4L2_PIX_FMT_YUYV:
                    found = true;
                    break;
                case V4L2_PIX_FMT_NV21:
                    found = true;
                    break;
                case V4L2_PIX_FMT_NV16:
                    found = true;
                    break;
                case V4L2_PIX_FMT_YVU420:
                    found = true;
                    break;
                case V4L2_PIX_FMT_RGB32:
                    found = true;
                    break;
#ifdef V4L2_PIX_FMT_ARGB32  // introduced with kernel v3.17
                case V4L2_PIX_FMT_ARGB32:
                    found = true;
                    break;
                case V4L2_PIX_FMT_XRGB32:
                    found = true;
                    break;
#endif  // V4L2_PIX_FMT_ARGB32
                default:
                    LOG(WARNING) << "Unsupported, " << std::hex << formatDescription.pixelformat;
                    break;
            }
        } else {
            // No more formats available.
            break;
        }
    }


    return found;
}

EvsEnumerator notifyDeviceStatusChange

调用service(EvsEnumerator)的notifyDeviceStatusChange方法,通知设备状态变化:

//packages/services/Car/cpp/evs/sampleDriver/aidl/src/EvsEnumerator.cpp
std::shared_ptr<aidlevs::IEvsEnumeratorStatusCallback> mCallback;
void EvsEnumerator::notifyDeviceStatusChange(const std::string_view& deviceName,
                                             DeviceStatusType type) {
    std::lock_guard lock(sLock);
    if (!mCallback) {
        return;
    }


    std::vector<DeviceStatus> status {{ .id = std::string(deviceName), .status = type }};
    if (!mCallback->deviceStatusChanged(status).isOk()) {
        LOG(WARNING) << "Failed to notify a device status change, name = " << deviceName
                     << ", type = " << static_cast<int>(type);
    }
}

调用mCallback(IEvsEnumeratorStatusCallback)的deviceStatusChanged方法,IEvsEnumeratorStatusCallback是个接口,在EvsDeviceStatusCallbackImpl中实现:

//packages/services/Car/cpp/evs/manager/aidl/src/Enumerator.cpp
std::shared_ptr<Enumerator> mEnumerator;
ScopedAStatus Enumerator::EvsDeviceStatusCallbackImpl::deviceStatusChanged(
        const std::vector<aidlevs::DeviceStatus>& list) {
    mEnumerator->broadcastDeviceStatusChange(list);
    return ScopedAStatus::ok();
}

调用mEnumerator的broadcastDeviceStatusChange方法:

//packages/services/Car/cpp/evs/manager/aidl/src/Enumerator.cpp
std::set<std::shared_ptr<aidlevs::IEvsEnumeratorStatusCallback>> mDeviceStatusCallbacks;
void Enumerator::broadcastDeviceStatusChange(const std::vector<aidlevs::DeviceStatus>& list) {
    std::lock_guard lock(mLock);
    auto it = mDeviceStatusCallbacks.begin();
    while (it != mDeviceStatusCallbacks.end()) {
        if (!(*it)->deviceStatusChanged(list).isOk()) {
            mDeviceStatusCallbacks.erase(it);
        } else {
            ++it;
        }
    }
}
  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值