logo资料库

Evs学习文档.pdf

第1页 / 共13页
第2页 / 共13页
第3页 / 共13页
第4页 / 共13页
第5页 / 共13页
第6页 / 共13页
第7页 / 共13页
第8页 / 共13页
资料共13页,剩余部分请下载后查看
EVS (External View System) 外部查看系统 我的理解,就是可以将 外界摄像头的视频流快速显示到屏幕上的 一套系统。 那么为什么选择 EVS ,而不使用之前传统的 显示流程: 相比传统的 camera,Evs 的优点是什么: 可配置性: EVS 的 HAL 层 设计的要比完整的 camera HAL 层简单,并且在客户端,通过 config.json 对 camera 进行配置, 并且 google也提供了一些 demo,可以随意查看 CameraName_Backup、LaneView、right turn 摄像头。 快速启动: 因为车机开机后,camera 中的视频流要尽快显示到 display 上, EVS HAL 的设计,使 camera → display 的流程依赖性最小化,他完全又 native 代码实现,内 核一旦启动运行,他就可以去启动显示了, 它目前的相应时间为 2S 左右。 可扩展性: EVS 提供了一种安全的方式,来让应用通过只读的方式,获取车载摄像机的反馈,这样应用 端就可以由此实现 脸部识别,标志检测,路况报告等一些高级功能。 车机对 摄像头的要求性,比较高,要在用户打开车门后,尽早看到倒车影像,而使用 EVS 能使 用户尽早的看到影响。 EVS的流程 EVS 主要是 camera、application、display这三个 modle 进行交互,他的大概流程为: hal 层 camera 上报 视频图像 -----→ 应用层处理视频图像(实现人脸识别等功能) –-----→ display 显示视频图像 。 官方图如下:
它使用了 hal 的 技术,将这个流 程分为 三个层 次: application: 应用层, 由开发者实现 Evs manager: 向 应用层提供,相关接口服务 hardware_service: 向 manager 提供具体的接口实现 我对它流程,理解的图为: EVS Application EVS Manager EVS HardWard_Service Camera Driver Display Driver application 通过 Evs manager 与 hardware_service 通信,
获取操作 camera与 display的权限与 代理对象 IEvsCamera、IEvsDisplay, 通过 代理对象,实现 camera 与 display 的交互, 将 camera 的图像及时的显示到 display 上。 具体的流程为: 1、EvsManager与 Evs Hardward_service 的初始化 2、application 通过 Evs manager 获取 代理对象 IEvsCamera、IEvsDisplay 3、使用 IEvsCamera、IEvsDisplay 实现, 图像的获取与显示。 1、EvsManager与 Evs Hardward_service 的初始化 const static char kEvsServiceName[] = "EvsSharedEnumerator"; android::sp pEvs = IEvsEnumerator::getService(kEvsServiceName); 通过 getService 获取 名为"EvsSharedEnumerator"的 Evs Manager, Evs manager 应该是开机时注册到系统中的,他的注册流程为: const static char kManagedEnumeratorName[] = "EvsSharedEnumerator"; const static char kHardwareEnumeratorName[] = "EvsEnumeratorHw-Mock"; android::sp service = new Enumerator(); service→init(kHardwareEnumeratorName) status_t status = service->registerAsService(kManagedEnumeratorName); joinRpcThreadpool(); application 获取到的 IEvsEnumerator 代理,其实就是 Enumerator对象,他是在系统开机时通 过 registerAsService 函数注册到 系统中的, Enumerator 是在 init 中 获取 HardWard_Service的代理对象的: bool Enumerator::init(const char* hardwareServiceName) { sp mHwEnumerator = IevsEnumerator::getService(hardwareServiceName); bool result = (mHwEnumerator.get() != nullptr); return result; } hardwareServiceName == kHardwareEnumeratorName == "EvsEnumeratorHw-Mock" 在其 init 函数中 也是通过 getService 函数来获取 HardWard_Service 代理对象的, HardWare_Service 也是在系统开机,通过 init.rc时启动注册到系统中的: hardware/interfaces/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc service evs-hal-1-0 /vendor/bin/hw/android.hardware.automotive.evs@1.0-service class hal user cameraserver group camera
在 init.rc 中通过 android.hardware.automotive.evs@1.0-service,命令启动的 HardWard_Service const static char kEnumeratorServiceName[] = "EvsEnumeratorHw-Mock"; int main() { android::sp service = new EvsEnumerator(); configureRpcThreadpool(1, true /* callerWillJoin */); status_t status = service->registerAsService(kEnumeratorServiceName); if (status == OK) { joinRpcThreadpool(); } else { ALOGE("Could not register service %s (%d).", kEnumeratorServiceName, status); } return 1; } HardWard_Service 的实体实现为 HardWard的 EvsEnumerator 对象,在他的初始化函数中会, 将系统中的 camera 添加到 sCameraList 中,并且也通过 registerAsService 函数注册到 系统中, 然后等待 manager 的调用。 EvsEnumerator::EvsEnumerator() { sCameraList.emplace_back(EvsCamera::kCameraName_Backup); sCameraList.emplace_back("LaneView"); sCameraList.emplace_back("right turn"); } EvsEnumerator现在默认是支持三个 camera:后置、左、右 到此 Hardward Service 与 上层的 Evs manager、application都初始化完毕, application 可以通过 Evs manager 的代理对象,与 Hardward Service 进行交互,获取 Camera 与 Display 的代理对象,用以进行后续操作。 2、application 通过 Evs manager 获取 代理对象 IEvsCamera、IEvsDisplay sp pDisplay = pEvs→openDisplay(); sp mCurrentCamera = mEvs->openCamera(mCameraInfo[desiredState].cameraId); 通过 Evs Manager 的代理对象 IEvsEnumerator,来获取 camera 与 display 的代理对象: 因为系统最多只能有一个 EVS显示对象,所以需要通过此方法,获取独家访问 pEvs→openDisplay(): IEvsDisplay的权限,此方法在 Evs Manager 中的具体实现为: Return> Enumerator::openDisplay() { sp pActiveDisplay = mHwEnumerator->openDisplay(); mActiveDisplay = pActiveDisplay; return pActiveDisplay; }
Evs Manager 中会调用 HardWard Service 的 openDisplay 方法,获取 IEvsDisplay 对象,并将 其返回,HardWard Service 端 的实现为: Return> EvsEnumerator::openDisplay() { sp pActiveDisplay = sActiveDisplay.promote(); if (pActiveDisplay != nullptr) { closeDisplay(pActiveDisplay); } pActiveDisplay = new EvsDisplay(); sActiveDisplay = pActiveDisplay; return pActiveDisplay; } 因为系统中存在多个 Camera 所以使用此方法时,需要指定 要打开的 cameraId,而系 在 Hardward Service 的 openDisplay 方法中 会进行判断,如果之前已经有人 获取了 Display 权限,将其关闭。并创建一个新的 EvsDisplay 对象 将其返回, 而在 EvsDisplay 的构造方法中 会初始化一个用以与 surface 通信的 BufferDesc buffer。 到此 application就可以获取到 EvsDisplay 的代理对象 IEvsDisplay mEvs→openCamera(mCameraInfo[desiredState].cameraId): 统中所有的 CameraId是通过 mEvs→getCameraList(**) 获取到的: mEvs->getCameraList([this, &config] (hidl_vec cameraList) { for (auto&& cam: cameraList) { bool cameraConfigFound = false; for (auto&& info: config.getCameras()) { if (cam.cameraId == info.cameraId) { if (info.function.find("reverse") != std::string::npos) { mCameraInfo[State::REVERSE] = info; } if (info.function.find("right") != std::string::npos) { mCameraInfo[State::RIGHT] = info; } if (info.function.find("left") != std::string::npos) { mCameraInfo[State::LEFT] = info; } cameraConfigFound = true; break; } } } } ); getCameraList 的参数是一个 函数指针,它通过 Evs Manager 传入到 Hardward Service, 并由 Hardward Service 回调,将 cameraList 传入此回调函数。
在此 回调函数中,会去遍历 cameraList,并与 config.json 对比,如果 config.json 存在 cameraList 对应的 cameraId,那么将此 camera 放入 mCameraInfo 中。 Hardward Service 中 getCameraList 的具体实现为: Return EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { const unsigned numCameras = sCameraList.size(); std::vector descriptions; descriptions.reserve(numCameras); for (const auto& cam : sCameraList) { descriptions.push_back( cam.desc ); } hidl_vec hidlCameras(descriptions); _hidl_cb(hidlCameras); return Void(); } 在 Hardward 的 getCameraList 方法中,会回调传入的_hidl_cb 函数,并将 EvsEnumerator 初 始化 sCameraList 传过去。 到此 Application 就获取到所有包含所有 Camera Id 的 List 集合。 之后使用 openCamera 来打开指定 CameraId的 camera: sp mCurrentCamera = mEvs->openCamera(mCameraInfo[desiredState].cameraId); openCamera 会先调用到 Evs Manager 中 Enumerator.cpp 的 openCamera 方法: Return> Enumerator::openCamera(const hidl_string& cameraId) { sp hwCamera; for (auto &&cam : mCameras) { bool match = false; cam->getHwCamera()->getCameraInfo([cameraId, &match](CameraDesc desc) { if (desc.cameraId == cameraId) { match = true; } } ); if (match) { hwCamera = cam; break; } } if (hwCamera == nullptr) { sp device = mHwEnumerator->openCamera(cameraId); hwCamera = new HalCamera(device); } sp clientCamera; clientCamera = hwCamera->makeVirtualCamera(); mCameras.push_back(hwCamera); return clientCamera; }
在 Evs Manager Enumerator的 openCamera 方法中,做的操作有以下几点: 1、使用 getCameraInfo 方法对 cameraId 进行校验,检验 是否存在对应 CameraId 的相机 2、通过 mHwEnumerator 的 openCamera 方法,调用到 Hardward service 去打开对应 cameraId 的相机 3、将 Hardward service 返回的 IevsCamera 封装为 HalCamera 4、调用 HalCamera 的 makeVirtualCamera 方法,去配置 HardWard service camera 的 buffers 信息,并将返回值 return。 5、将 hwCamera 保存在 list集合中 mCameras 中, 之后分为两个流程 a、mHwEnumerator->openCamera b、 hwCamera->makeVirtualCamera() a、mHwEnumerator->openCamera,调用到Hardward service 去打开对应cameraId 的相机 openCamera 会调用到 Hardward EvsEnumerator 的 openCamera 函数 Return> EvsEnumerator::openCamera(const hidl_string& cameraId) { CameraRecord *pRecord = nullptr; for (auto &&cam : sCameraList) { if (cam.desc.cameraId == cameraId) { pRecord = &cam; break; } } if (!pRecord) { ALOGE("Requested camera %s not found", cameraId.c_str()); return nullptr; } sp pActiveCamera = pRecord->activeInstance.promote(); if (pActiveCamera != nullptr) { ALOGW("Killing previous camera because of new caller"); closeCamera(pActiveCamera); } pActiveCamera = new EvsCamera(cameraId.c_str()); pRecord->activeInstance = pActiveCamera; if (pActiveCamera == nullptr) { ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str()); } return pActiveCamera; } 在 Hardward 的 openCamera 方法中,会进行以下操作: 1、判断 传入的 cameraId 是否有效 2、对应的 cameraId是否已经打开,如果已经打开 closeCamera 3、创建 EvsCamera 对象,并将其返回给 EVS Manager 在 EvsCamera 的构造方法中,会初始化 camera 对应的参数:Width、Height、mFormat 。
到此 E 就获取到了 hardWard EvsCamera 的代理对象 IEvsCamera。 b、 hwCamera->makeVirtualCamera() makeVirtualCamera 方法的主要作用是去申请指定大小的图像缓冲区 sp HalCamera::makeVirtualCamera() { sp client = new VirtualCamera(this); if (client == nullptr) { return nullptr; } if (!changeFramesInFlight(client->getAllowedBuffers())) { client = nullptr; return nullptr; } mClients.push_back(client); return client; } 在此方法中,做的操作为: 1、将 hwCamera 封装为 VirtualCamera 对象 client 2、通过 changeFramesInFlight 去想底层申请指定大小的图像缓冲区 3、将 client 对象添加 进入 mClients //client→getAllowedBuffers() 默认值为1 changeFramesInFlight 为: bool HalCamera::changeFramesInFlight(int delta) { unsigned bufferCount = 0; for (auto&& client : mClients) { sp virtCam = client.promote(); if (virtCam != nullptr) { bufferCount += virtCam->getAllowedBuffers(); } } bufferCount += delta; if (bufferCount < 1) { bufferCount = 1; } Return result = mHwCamera→setMaxFramesInFlight(bufferCount); return success; 他会通过 mHwCamera 调用到 Hardward对端 EvsCamera 的 setMaxFramesInFlight 方法传入的 参数默认初始值为 1, 而在 Hardward 端也是经过一系列的调用,去申请对应大小的图像缓冲区 mBuffer 调用流程为: EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) } EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd)
分享到:
收藏