车载EVS
车载相机HAL 包含外景系统 (EVS) 堆栈,且通常用于在搭载基于 Android 的车载信息娱乐 (IVI) 系统的汽车上为后视摄像头和环绕视图显示提供支持。
Android 还包含一个 EVS 专用的拍摄和显示驱动程序接口(位于 /hardware/interfaces/automotive/evs/1.0
)。
虽然可以基于现有 Android 相机和显示服务构建后视相机应用,但这样的应用可能会在 Android 启动过程中运行过于迟缓。
使用专用 HAL 可实现简化的接口,并清楚地说明原始设备制造商 (OEM) 需要实现什么才能支持 EVS 堆栈。
EVS系统架构
EVS Application
EVS Application示例应用 (/packages/services/Car/evs/apps/default/)。
该应用负责从 EVS 管理器请求视频帧,并将用于显示的已完成的帧发送回 EVS 管理器。EVS 和汽车服务可供使用后,它便立即由 init 启动(设置目标为在开机两 (2) 秒内启动)。原始设备制造商 (OEM) 可视需要修改或替换 EVS 应用。
C++的服务app:
service evs_app /system/bin/evs_appclass halpriority -20user automotive_evsgroup automotive_evsdisabled # will not automatically start with its class; must be explictly started.
EVS Manager
EVS Manager(/packages/services/Car/evs/manager/1.1/) 可提供 EVS 应用所需的构建块,以实现从简单的后视摄像头显示到 6DOF 多摄像头渲染的任何功能。
它的接口通过 HIDL 呈现,并且能够接受多个并发客户端。
其他应用和服务(特别是汽车服务)可以查询 EVS 管理器状态,以了解 EVS 系统何时处于活动状态。
启动rc文件:
service evs_manager /system/bin/android.automotive.evs.manager@1.1class halpriority -20user automotive_evsgroup automotive_evs systemdisabled # will not automatically start with its class; must be explictly started.
EVS HIDL
EVS HIDL用于执行接口的示例实现(生成合成测试图像并验证图像进行往返的过程)在 /hardware/interfaces/automotive/evs/1.0/default
中提供。
设备制造商 (OEM) 负责实现由 /hardware/interfaces/automotive/evs
中的 .hal 文件表示的 API。
这种实现负责从物理相机配置和收集数据,并通过 Gralloc 可识别的共享内存缓冲区传送这些数据。
实现的显示端负责提供可由应用填充(通常通过 EGL 渲染的方式)的共享内存缓冲区,并优先呈现已完成的帧(在任何可能会显示在物理显示设备上的其他内容之前)。
EVS 接口的供应商实现可以存储在 /vendor/… /device/… 或 hardware/…(例如 /hardware/[vendor]/[platform]/evs)下。
驱动程序
支持 EVS 堆栈的设备需要使用内核驱动程序。
设备制造商 (OEM) 无需创建新驱动程序,他们可以选择通过现有相机和/或显示硬件驱动程序来支持 EVS 所需的功能。
重复使用驱动程序可能会有好处,对于图像呈现可能需要与其他活动线程协调的显示驱动程序来说尤其如此。
Android 8.0 包含一个基于 v4l2 的示例驱动程序(在 packages/services/Car/evs/sampleDriver
中),该驱动程序依靠内核实现 v4l2 支持,并依靠 SurfaceFlinger 呈现输出图像。
EVS HAL接口说明
IEvsEnumerator
IEvsEnumerator的源码位置:/hardware/interfaces/automotive/evs/1.1/IEvsEnumerator.hal
/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.automotive.evs@1.0;import IEvsCamera;import IEvsDisplay;/** * Provides the mechanism for EVS camera discovery */interface IEvsEnumerator {/** * Returns a list of all EVS cameras available to the system * * @return cameras A list of cameras availale for EVS service. */getCameraList() generates (vec<CameraDesc> cameras);/** * Get the IEvsCamera associated with a cameraId from a CameraDesc * * Given a camera's unique cameraId from CameraDesc, returns the * IEvsCamera interface associated with the specified camera. When * done using the camera, the caller may release it by calling closeCamera(). * * @paramcameraIdA unique identifier of the camera. * @return carCamera EvsCamera object associated with a given cameraId. */openCamera(string cameraId) generates (IEvsCamera carCamera);/** * Return the specified IEvsCamera interface as no longer in use * * When the IEvsCamera object is no longer required, it must be released. * NOTE: Video streaming must be cleanly stopped before making this call. * * @paramcarCamera EvsCamera object to be closed. */closeCamera(IEvsCamera carCamera);/** * Get exclusive access to IEvsDisplay for the system * * There can be at most one EVS display object for the system and this function * requests access to it. If the EVS display is not available or is already in use, * the old instance shall be closed and give the new caller exclusive * access. * When done using the display, the caller may release it by calling closeDisplay(). * * @return display EvsDisplay object to be used. */openDisplay() generates (IEvsDisplay display);/** * Return the specified IEvsDisplay interface as no longer in use * * When the IEvsDisplay object is no longer required, it must be released. * NOTE: All buffers must have been returned to the display before making this call. * * @paramdisplay EvsDisplay object to be closed. */closeDisplay(IEvsDisplay display);/** * This call requests the current state of the display * * If there is no open display, this returns DisplayState::NOT_OPEN. otherwise, it returns * the actual state of the active display.This call is replicated on the IEvsEnumerator * interface in order to allow secondary clients to monitor the state of the EVS display * without acquiring exclusive ownership of the display. * * @return state Current DisplayState of this Display. */getDisplayState() generates (DisplayState state);};
getCameraList
getCameraList() generates (vec<CameraDesc> cameras);
负责枚举系统中可用的 EVS 硬件(一个或多个相机和单个显示设备)。
返回包含系统中所有相机的说明的矢量。
假设相机组是固定的且在启动时是可知的。如需详细了解相机说明,请参阅 CameraDesc。
CameraDesc:
struct CameraDesc {stringcamera_id;int32 vendor_flags; // Opaque value}
camera_id:
用于唯一标识指定相机的字符串。
该字符串可以是设备的内核设备名称,也可以是设备的名称,例如“rearview”。该字符串的值由 HAL 实现选择,并由上面的堆栈以不透明的方式使用。
vendor_flags:
用于以不透明的方式将特殊相机信息从驱动程序传送到自定义 EVS 应用的一种方法。这些信息未经解释即从驱动程序向上直通到 EVS 应用,可直接将其忽略。
openCamera
openCamera(string camera_id) generates (IEvsCamera camera);
获取用于与唯一 camera_id 字符串所标识的特定相机进行交互的接口对象。失败时返回 NULL。
尝试重新打开已打开的相机不会失败。
为了避免出现与应用启动和关闭相关的竞态条件,重新打开相机应该会关闭上一个实例,以满足新的请求。以这种方式被优先占用的相机实例必须置于不活动状态,等待最终销毁并响应任何请求以利用返回代码 OWNERSHIP_LOST 影响相机状态。
closeCamera
closeCamera(IEvsCamera camera);
释放 IEvsCamera 接口(与 openCamera() 调用相反)。必须通过依次调用 stopVideoStream() 和 closeCamera 停止相机的视频串流。
closeCamera
openDisplay() generates (IEvsDisplay display);
获取用于专门与系统的 EVS 显示进行交互的接口对象。
目前只有一个客户端可以持有 IEvsDisplay 的函数实例。
与 openCamera 中描述的激进式打开行为相似,您可以随时创建一个新的 IEvsDisplay 对象,并停用任何先前的实例。
无效的实例会继续存在并响应来自其所有者的函数调用,但不得在终止后执行任何变相的操作。
最终,客户端应用应注意到 OWNERSHIP_LOST 错误返回代码,并关闭和释放处于非活动状态的接口。
closeCamera
closeDisplay(IEvsDisplay display);
释放 IEvsDisplay 接口(与 openDisplay() 调用相反)。
通过 getTargetBuffer() 调用收到的待处理缓冲区必须在关闭显示之前返回给显示。
closeCamera
getDisplayState() generates (DisplayState state);
获取当前的显示状态。HAL 实现应报告实际的当前状态,该状态可能与最近请求的状态不同。
负责更改显示状态的逻辑应存在于设备层之上,从而使 HAL 实现无需自发更改显示状态。如果显示目前未被任何客户端持有(通过调用 openDisplay),则此函数会返回 NOT_OPEN。
否则,它会报告 EVS 显示的当前状态(请参阅 IEvsDisplay API)。
IEvsCamera
源码路径:/hardware/interfaces/automotive/evs/1.1/IEvsCamera.hal
/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.automotive.evs@1.1;import @1.0::IEvsCamera;import @1.0::IEvsDisplay;import @1.0::EvsResult;import IEvsCameraStream;/** * Represents a single camera and is the primary interface for capturing images. */interface IEvsCamera extends @1.0::IEvsCamera {/** * Returns the description of this camera. * * @return info The description of this camera.This must be the same value as *reported by EvsEnumerator::getCameraList_1_1(). */getCameraInfo_1_1() generates (CameraDesc info);/** * Returns the description of the physical camera device that backs this * logical camera. * * If a requested device does not either exist or back this logical device, * this method returns a null camera descriptor.And, if this is called on * a physical camera device, this method is the same as getCameraInfo_1_1() * method if a given device ID is matched.Otherwise, this will return a * null camera descriptor. * * @paramdeviceId Physical camera device identifier string. * @return info The description of a member physical camera device. *This must be the same value as reported by *EvsEnumerator::getCameraList_1_1(). */getPhysicalCameraInfo(string deviceId) generates (CameraDesc info);/** * Requests to pause EVS camera stream events. * * Like stopVideoStream(), events may continue to arrive for some time * after this call returns. Delivered frame buffers must be returned. * * @return result EvsResult::OK is returned if this call is successful. */pauseVideoStream() generates (EvsResult result);/** * Requests to resume EVS camera stream. * * @return result EvsResult::OK is returned if this call is successful. */resumeVideoStream() generates (EvsResult result);/** * Returns frame that were delivered by to the IEvsCameraStream. * * When done consuming a frame delivered to the IEvsCameraStream * interface, it must be returned to the IEvsCamera for reuse. * A small, finite number of buffers are available (possibly as small * as one), and if the supply is exhausted, no further frames may be * delivered until a buffer is returned. * * @parambuffer Buffers to be returned. * @return result Return EvsResult::OK if this call is successful. */doneWithFrame_1_1(vec<BufferDesc> buffer) generates (EvsResult result);/** * Requests to be a master client. * * When multiple clients subscribe to a single camera hardware and one of * them adjusts a camera parameter such as the contrast, it may disturb * other clients' operations.Therefore, the client must call this method * to be a master client.Once it becomes a master, it will be able to * change camera parameters until either it dies or explicitly gives up the * role. * * @return result EvsResult::OK if a master role is granted. *EvsResult::OWNERSHIP_LOST if there is already a *master client. */setMaster() generates (EvsResult result);/** * Sets to be a master client forcibly. * * The client, which owns the display, has a high priority and can take over * a master role from other clients without the display. * * @paramdisplay IEvsDisplay handle.If a given display is in either * NOT_VISIBLE, VISIBLE_ON_NEXT_FRAME, or VISIBLE state, the * calling client is considered as the high priority client * and therefore allowed to take over a master role from * existing master client. * * @return resultEvsResult::OK if a master role is granted. * EvsResult::INVALID_ARG if a given display handle is null * or in valid states. */forceMaster(IEvsDisplay display) generates (EvsResult result);/** * Retires from a master client role. * * @return result EvsResult::OK if this call is successful. *EvsResult::INVALID_ARG if the caller client is not a *master client. */unsetMaster() generates (EvsResult result);/** * Retrieves a list of parameters this camera supports. * * @return params A list of CameraParam that this camera supports. */getParameterList() generates (vec<CameraParam> params);/** * Requests a valid value range of a camera parameter * * @paramidThe identifier of camera parameter, CameraParam enum. * * @return min The lower bound of valid parameter value range. * @return max The upper bound of valid parameter value range. * @return stepThe resolution of values in valid range. */getIntParameterRange(CameraParam id)generates (int32_t min, int32_t max, int32_t step);/** * Requests to set a camera parameter. * * Only a request from the master client will be processed successfully. * When this method is called on a logical camera device, it will be forwarded * to each physical device and, if it fails to program any physical device, * it will return an error code with the same number of effective values as * the number of backing camera devices. * * @paramid The identifier of camera parameter, CameraParam enum. * valueA desired parameter value. * @return result EvsResult::OK if it succeeds to set a parameter. *EvsResult::INVALID_ARG if either the request is *not made by a master client, or a requested *parameter is not supported. *EvsResult::UNDERLYING_SERVICE_ERROR if it fails to *program a value by any other reason. * effectiveValue Programmed parameter values.This may differ *from what the client gives if, for example, the *driver does not support a target parameter. */setIntParameter(CameraParam id, int32_t value)generates (EvsResult result, vec<int32_t> effectiveValue);/** * Retrieves values of given camera parameter. * * @paramid The identifier of camera parameter, CameraParam enum. * @return result EvsResult::OK if it succeeds to read a parameter. *EvsResult::INVALID_ARG if either a requested parameter is *not supported. * valueValues of requested camera parameter, the same number of *values as backing camera devices. */getIntParameter(CameraParam id) generates(EvsResult result, vec<int32_t> value);/** * Request driver specific information from the HAL implementation. * * The values allowed for opaqueIdentifier are driver specific, * but no value passed in may crash the driver. The driver should * return EvsResult::INVALID_ARG for any unrecognized opaqueIdentifier. * * @paramopaqueIdentifier An unique identifier of the information to *request. * @return result EvsResult::OK if the driver recognizes a given *identifier. *EvsResult::INVALID_ARG, otherwise. * @return valueRequested information.Zero-size vector is *returned if the driver does not recognize a *given identifier. */getExtendedInfo_1_1(uint32_t opaqueIdentifier)generates (EvsResult result, vec<uint8_t> value);/** * Send a driver specific value to the HAL implementation. * * This extension is provided to facilitate car specific * extensions, but no HAL implementation may require this call * in order to function in a default state. * INVALID_ARG is returned if the opaqueValue is not meaningful to * the driver implementation. * * @paramopaqueIdentifier An unique identifier of the information to *program. * opaqueValueA value to program. * @return result EvsResult::OK is returned if this call is successful. *EvsResult::INVALID_ARG, otherwise. */setExtendedInfo_1_1(uint32_t opaqueIdentifier, vec<uint8_t> opaqueValue)generates (EvsResult result);/** * Import external buffers to capture frames * * This API must be called with a physical camera device identifier. * * @parambuffersA list of buffers allocated by the caller.EvsCamera *will use these buffers to capture frames, in addition to *other buffers already in its buffer pool. * @return result EvsResult::OK if it succeeds to import buffers. *EvsResult::UNDERLYING_SERVICE_ERROR if this is called *for logical camera devices or EVS fails to import *buffers. * deltaThe amount of buffer pool size changes after importing *given buffers. */importExternalBuffers(vec<BufferDesc> buffers)generates (EvsResult result, int32_t delta);};
getCameraInfo
getCameraInfo() generates (CameraDesc info);
返回此相机的 CameraDesc。
setMaxFramesInFlight
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);
指定要求相机支持的缓冲区链的深度。
IEvsCamera 的客户端可以同时持有数量如此多的帧。
如果数量如此多的帧已传送到接收器但 doneWithFrame 未将其返回,则视频流会跳过帧,直到返回缓冲区以供重新使用。该调用在任何时候返回都是合法的,即使视频流已在运行(这种情况下,应相应地在链中添加或移除缓冲区)。
如果未对此入口点进行任何调用,则 IEvsCamera 默认支持至少一个帧(更多的帧也可以接受)。
如果无法容纳请求的 bufferCount,该函数会返回 BUFFER_NOT_AVAILABLE 或其他相关的错误代码。在这种情况下,系统将继续使用先前设置的值运行。
startVideoStream
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
请求从此相机传送 EVS 相机帧。
IEvsCameraStream 开始接收带有新图像帧的定期调用,直到调用 stopVideoStream() 为止。
必须在调用 startVideoStream 后的 500 毫秒内开始传送帧,而且开始后,必须至少以 10 FPS 的速率生成帧。
实际上,启动视频流所需的时间需要根据各项后视摄像头启动时间要求进行计算。如果未启动视频流,则必须返回错误代码;否则返回 OK。
doneWithFrame
oneway doneWithFrame(BufferDesc buffer);
返回传送到 IEvsCameraStream 的帧。
传送到 IEvsCameraStream 接口的帧用完以后,必须被返回到 IEvsCamera 以供重新使用。
只有极少的数量有限(最少可能只有一个)的缓冲区可供使用;如果供应的缓冲区耗尽,则在返回缓冲区之前不再传送任何帧,这可能会导致产生跳过的帧(具有 null 句柄的缓冲区表示视频流结束,无需通过此函数返回)。
成功时返回 OK,否则返回相应错误代码(可能包括 INVALID_ARG 或 BUFFER_NOT_AVAILABLE)。
BufferDesc :
struct BufferDesc {uint32width;// Units of pixelsuint32height; // Units of pixelsuint32stride; // Units of pixelsuint32pixelSize;// Size of single pixel in bytesuint32format; // May contain values from android_pixel_format_tuint32usage;// May contain values from Gralloc.huint32bufferId; // Opaque valuehandlememHandle;// gralloc memory buffer handle}
BufferDesc 描述通过 API 传送的图像。
HAL 驱动程序负责填写此结构以描述图像缓冲区,而且 HAL 客户端应将此结构视为只读。
这些字段包含足够的信息供客户端重建 ANativeWindowBuffer 对象,因为可能需要通过 eglCreateImageKHR() 扩展才能将图像与 EGL 结合使用。
名称 | 含义 |
---|---|
width | 所呈现图像的宽度(以像素为单位)。 |
height | 所呈现图像的高度(以像素为单位)。 |
stride | 每行在存储设备中实际占用的像素数;用来计算行对齐的任何内边距。以像素表示,用于匹配 gralloc 为其缓冲区说明采用的惯例。 |
pixelSize | 由每个单独的像素占据的字节数;用于计算在图像中分隔开各个行所需的字节大小(以字节为单位的 stride = 以像素为单位的 stride * pixelSize)。 |
format | 图像使用的像素格式。提供的格式必须与平台的 OpenGL 实现相兼容。要通过兼容性测试,相机使用应首选 HAL_PIXEL_FORMAT_YCRCB_420_SP;显示应首选 RGBA 或 BGRA。 |
usage | 由 HAL 实现设置的用法标记。HAL 客户端应原封不动地传送这些标记(如需了解详情,请参阅 Gralloc.h 相关标记)。 |
bufferId | 由 HAL 实现指定的唯一值,用于在通过 HAL API 进行往返之后识别缓冲区。存储在该字段中的值可由 HAL 实现任意选择。 |
memHandle | 包含图像数据的底层内存缓冲区的句柄。HAL 实现可能会选择在此处存储 Gralloc 缓冲区句柄。 |
stopVideoStream
stopVideoStream();
停止传送 EVS 相机帧。
由于传送是异步的,在此调用返回后的一段时间内,系统可能会继续传送帧。
在将视频流关闭信号发送到 IEvsCameraStream 之前,所有帧均必须返回。对已停止或从未启动的视频流调用 stopVideoStream 是合法的,在这种情况下,系统会忽略该调用。
getExtendedInfo
getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);
从 HAL 实现中请求特定于驱动程序的信息。允许用于 opaqueIdentifier 的值是特定于驱动程序的,但传送任何值都不会使驱动程序崩溃。对于任何无法识别的 opaqueIdentifier,驱动程序应返回 0。
setExtendedInfo
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
将特定于驱动程序的值发送到 HAL 实现。
提供这项扩展的目的只是为了便于实现汽车专用扩展,而且任何 HAL 实现均不得要求该调用在默认状态下运行。
如果驱动程序识别出并接受值,则应返回 OK;否则应返回 INVALID_ARG 或其他有代表性的错误代码。
IEvsCameraStream
客户端实现此接口以接收异步传送的视频帧。
/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.hardware.automotive.evs@1.0;/** * Implemented on client side to receive asynchronous video frame deliveries. */interface 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(). 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, a NULL bufferHandle * must be delivered, signifying the end of the stream. No further frame * deliveries may happen thereafter. * * @param buffer a buffer descriptor of a delivered image frame. */oneway deliverFrame(BufferDesc buffer);};
####### deliverFrame
deliverFrame(BufferDesc buffer);
每次视频帧准备好进行检查时,都从 HAL 接收调用。
此方法接收的缓冲区句柄必须通过调用 IEvsCamera::doneWithFrame() 来返回。
当通过调用 IEvsCamera::stopVideoStream() 停止视频流时,此回调可能会在清空管道数据时持续一段时间。
每个帧仍必须返回;当传送完视频流中的最后一帧后,系统将传送一个 NULL bufferHandle,这表示视频流结束,不会再发生进一步的帧传递。
NULL bufferHandle 本身不需要通过 doneWithFrame() 发回,但是必须返回所有其他句柄
尽管专用缓冲区格式在技术上是可行的,但兼容性测试要求缓冲区采用以下五种受支持的格式之一:NV21 (YCrCb 4:2:0 Semi-Planar)
、YV12 (YCrCb 4:2:0 Planar)
、YUYV (YCrCb 4:2:2 Interleaved)
、RGBA (32 位 R:G:B:x)
、BGRA (32 位 B:G:R:x)
。所选格式必须是平台的 GLES 实现上的有效 GL 纹理源。
应用不得依赖于 bufferId 字段与 BufferDesc 结构中的 memHandle 之间的任何对应关系。一般而言,bufferId 值是 HAL 驱动程序实现的专用值,该实现可根据需要使用(以及重新使用)这些值。
参考
官网evs介绍