一、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;
}
}
}