接下来将会了解Android HAL是如何与相机设备、Framework进行交互的,为了简单起见,我们使用androidP代码中的谷歌实例代码进行学习,代码路径为:android/hardware/libhardware/modules/camera/3_4。
一般的,各个平台的camera HAL将会有个 v4l2_camera_hal.cpp 文件。在这里,将是HAL对外的接口,该文件将会通过 HAL_MODULE_INFO_SYM
修饰一个 camera_module_t 结构体。camera Provider服务就是通过 HAL_MODULE_INFO_SYM
找到 camera_module_t,从而操作HAL。
在 v4l2_camera_hal.cpp 中定义了一个 V4L2CameraHAL 类的全局静态对象 gCameraHAL,所以在加载 HAL.so 时,将会调用 V4L2CameraHAL 类的构造函数。在构造函数中,主要是探测 /dev 目录下有多少个 video 节点且支持V4L2 video capture,并将探测结果保存在 V4L2CameraHAL.mCameras 容器中。
最终将返回全局静态对象 gCameraHAL 的 mCameras 成员大小。
最终根据传递进来的 id 将调用到全局静态对象 gCameraHAL 的 mCameras[id]->getInfo(info),此时将调用到 Camera::getInfo()。注意,mCameras[id]在全局静态变量 gCameraHAL 的构造函数中已经创建 V4L2Camera 对象。
为了支持Android框架保存原始图像文件,需要有关传感器特性的大量元数据。这包括诸如色彩空间和镜头阴影功能之类的信息。这些信息大部分都是相机子系统的静态属性,可以在配置输出管道或者提交请求之前进行查询。
设置回调函数,保存在 gCameraHAL.mCallbacks。mCallbacks为 camera_module_callbacks_t 类型,其中包含两个回调,一个是相机设备状态改变时的回调;一个是闪光灯状态改变时的回调。
在 camera_module_t 的comon成员中,通过 methods 指向了一个 hw_module_methods_t 类型变量。通过 hw_module_methods_t->open() ,我们最终调用到 Camera::openDevice() 函数(V4L2Camera是Camera的派生类,V4L2Camera没有覆盖openDevice()函数),从而和相机设备连接起来,该函数的参数 module 指向 HAL_MODULE_INFO_SYM.common,而 device 则是将返回给 Framework 的 camera device,device 指向 hw_device_t 类型对象。
在该函数中,将会通过调用 connect() 函数完成与相机设备的连接,接着将填充device,返回Framework。
而 connect() 将是调用到 V4L2Camera::connect()。V4L2Camera::connect() 则是创建一个 V4L2Wrapper::Connection 实例对象,在 V4L2Wrapper::Connection 的构造函数中,又将调用 V4L2Wrapper::Connect() 函数。
这一切,就这样就到了V4L2Wrapper::Connect() 。而在 V4L2Wrapper::Connect() 中,将会 open video节点,进行查询支持的格式以及分辨率等操作。
看完 v4l2_camera_hal.cpp 中的接口后,似乎上面就已经介绍完了,就没有其他接口控制设备了,那么 camera Provider服务进程又是如何多样操作相机设备的呢?下面继续看。
我们回头看 Camera::openDevice() 函数的实现:
int Camera::openDevice(const hw_module_t *module, hw_device_t **device)
{
ALOGI("%s:%d: Opening camera device", __func__, mId);
ATRACE_CALL();
android::Mutex::Autolock al(mDeviceLock);
if (mBusy) {
ALOGE("%s:%d: Error! Camera device already opened", __func__, mId);
return -EBUSY;
}
int connectResult = connect();
if (connectResult != 0) {
return connectResult;
}
mBusy = true;
mDevice.common.module = const_cast<hw_module_t*>(module);
/* 这里,是我们返回给Framework的 hw_device_t,那么这个
* mDevice 是什么呢,看 Camera 的构造函数
*/
*device = &mDevice.common;
return 0;
}
Camera::Camera(int id)
: mId(id),
mSettingsSet(false),
mBusy(false),
mCallbackOps(NULL),
mInFlightTracker(new RequestTracker)
{
memset(&mTemplates, 0, sizeof(mTemplates));
/* 在Camera 的构造函数中,初始化 common 成员的部分变量之后,
* 赋值了 ops 操作集,接下来再看看 ops 的类型
*/
memset(&mDevice, 0, sizeof(mDevice));
mDevice.common.tag = HARDWARE_DEVICE_TAG;
mDevice.common.version = CAMERA_DEVICE_API_VERSION_3_4;
mDevice.common.close = close_device;
mDevice.ops = const_cast<camera3_device_ops_t*>(&sOps);
mDevice.priv = this;
}
/* 从 mDevice.ops 的定义类型来看,很像就是操作相机设备的一些接口函数,
* 我们怎么确认我们的猜测是否正确呢,看 camera Provider 服务进程的调用
*/
typedef struct camera3_device_ops {
int (*initialize)(const struct camera3_device *,
const camera3_callback_ops_t *callback_ops);
int (*configure_streams)(const struct camera3_device *,
camera3_stream_configuration_t *stream_list);
int (*register_stream_buffers)(const struct camera3_device *,
const camera3_stream_buffer_set_t *buffer_set);
int (*process_capture_request)(const struct camera3_device *,
camera3_capture_request_t *request);
void (*get_metadata_vendor_tag_ops)(const struct camera3_device*,
vendor_tag_query_ops_t* ops);
void (*dump)(const struct camera3_device *, int fd);
int (*flush)(const struct camera3_device *);
void *reserved[8];
} camera3_device_ops_t;
/* camera Provider 服务进程的调用 */
/* 通过查看 CameraDeviceSession 类的实现,可以了解到,
* 在创建流、处理Framework请求等操作,都是通过 Camera::openDevice()
* 返回的 device 进行操作的,一般以以下的方式进行调用:
*/
mDevice->ops->initialize(mDevice, this);
mDevice->ops->dump(mDevice, fd->data[0]);
mDevice->ops->construct_default_request_settings(mDevice, (int) type);
mDevice->ops->configure_streams(mDevice, &stream_list);
mDevice->ops->process_capture_request(mDevice, &halRequest);
mDevice->ops->flush(mDevice);
所以通过以上分析得知,camera Provider 服务通过返回的 device 得到 camera3_device_ops_t 操作集,所以可以操作配置相机设备。下面再分析,这些操作集函数都进行了什么操作。
const camera3_device_ops_t Camera::sOps = {
.initialize = default_camera_hal::initialize,
.configure_streams = default_camera_hal::configure_streams,
.register_stream_buffers = nullptr,
.construct_default_request_settings
= default_camera_hal::construct_default_request_settings,
.process_capture_request = default_camera_hal::process_capture_request,
.get_metadata_vendor_tag_ops = nullptr,
.dump = default_camera_hal::dump,
.flush = default_camera_hal::flush,
.reserved = {0},
};
从上面我们了解到 initialize() 函数指针赋值为 default_camera_hal::initialize()。
namespace default_camera_hal {
extern "C" {
// Get handle to camera from device priv data
static Camera *camdev_to_camera(const camera3_device_t *dev)
{
/* 实际上通过转换为 camera3_device_t 类型,
* 再获取 priv 成员转换为 Camera 类型指针,可
* 回头查看 Camera 的构造函数以及 openDevice()
*/
return reinterpret_cast<Camera*>(dev->priv);
}
static int initialize(const camera3_device_t *dev,
const camera3_callback_ops_t *callback_ops)
{
/* 调用到 Camera::initialize() */
return camdev_to_camera(dev)->initialize(callback_ops);
}
} // extern "C"
} // namespace default_camera_hal
int Camera::initialize(const camera3_callback_ops_t *callback_ops)
{
int res;
ALOGV("%s:%d: callback_ops=%p", __func__, mId, callback_ops);
/* 在Framework层,调用 initialize() 函数时,传递了
* CameraDeviceSession 类对象的this指针,所以这里的
* callback_ops 指向 CameraDeviceSession实例对象地
* 址,而 CameraDeviceSession 类继承于 camera3_callback_ops,
* 所以这里就可以对接起来了
*/
mCallbackOps = callback_ops;
// per-device specific initialization
/* Camera类的 initDevice() 函数是纯虚函数,将会调用
* V4L2Camera::initDevice(),接着创建
* V4L2Camera::enqueueRequestBuffers() 线程和
* V4L2Camera::dequeueRequestBuffers() 线程
*/
res = initDevice();
if (res != 0) {
ALOGE("%s:%d: Failed to initialize device!", __func__, mId);
return res;
}
return 0;
}
如上介绍,在camera HAL,将会通过 mCallbackOps 将状态等信息反馈到 Framework。我们可以查看,在 CameraDeviceSession 类的构造函数可以看到以下信息:
/* camera3_callback_ops 对象将初始化为以下值 */
camera3_callback_ops({&sProcessCaptureResult, &sNotify})
typedef struct camera3_callback_ops {
void (*process_capture_result)(const struct camera3_callback_ops *,
const camera3_capture_result_t *result);
void (*notify)(const struct camera3_callback_ops *,
const camera3_notify_msg_t *msg);
} camera3_callback_ops_t;
而在 V4L2Camera::initDevice() 函数中,则是创建处理Framework 请求的线程。
与 initialize() 类似,将会调用至 Camera::configureStreams(camera3_stream_configuration_t *stream_config)
。这个调用将使用stream_list中定义的数据流信息来代替之前的数据流配置。在initialize()之后,使用process_capture_request()提交请求之前,这个函数至少被调用一次。在了解 configureStreams() 的具体操作前,我们先看看,函数参数的具体定义是怎样的。
typedef struct camera3_stream_configuration {
/* Framework请求的stream总数,至少为1,而且至少有一个具有输出能力的流 */
uint32_t num_streams;
/* 指向Framework配置的stream */
camera3_stream_t **streams;
uint32_t operation_mode;
const camera_metadata_t *session_parameters;
} camera3_stream_configuration_t;
typedef struct camera3_stream {
int stream_type;
uint32_t width;
uint32_t height;
int format;
uint32_t usage;
uint32_t max_buffers;
void *priv;
android_dataspace_t data_space;
int rotation;
const char* physical_camera_id;
/* reserved for future use */
void *reserved[6];
} camera3_stream_t;
从 camera3_stream_configuration_t 的定义我们可以了解到,主要就是配置相机硬件输出的格式、分辨率、buf数量、以及stream的类型等。
而 configureStreams() 进行了什么操作呢?
int Camera::configureStreams(camera3_stream_configuration_t *stream_config)
{
/* 检查参数是否正确、有效 */
int res = validateStreamConfiguration(stream_config);
if (res) {
ALOGE("%s:%d: Failed to validate stream set", __func__, mId);
} else {
/* 设置stream */
res = setupStreams(stream_config);
if (res) {
ALOGE("%s:%d: Failed to setup stream set", __func__, mId);
}
}
if (!res) {
/* 保存相应的配置 */
mInFlightTracker->SetStreamConfiguration(*stream_config);
// Must provide new settings for the new configuration.
mSettingsSet = false;
} else if (res != -EINVAL) {
// Fatal error, the old configuration is invalid.
mInFlightTracker->ClearStreamConfiguration();
}
// On a non-fatal error the old configuration, if any, remains valid.
return res;
}
在 setupStreams() 函数又进行了什么操作呢,检查当前的多个stream的格式、分辨率等参数是否一致,然后设置格式、申请buf等。
简单总结 configureStreams() 进行了什么操作:
该函数将调用至 Camera::constructDefaultRequestSettings(),上面有提到过,Framework将会通过一些请求操作camera HAL,但是可能各个平台的HAL有个别差异,所以需要Framework在提交请求前,先获取默认请求的设置模板(实质是 CameraMetadata),从而再精确化设置具体的参数,该函数就是构造默认请求设置的。
constructDefaultRequestSettings() 函数主要进行以下操作:
显然的,从该函数名我们就知道,它是负责处理Framework发过来的请求的,下面我们来看看,调用至 Camera::processCaptureRequest() 后又是怎么处理的?
Camera::processCaptureRequest() 主要进行以下操作:
上面我们说到,当HAL接收到Framework请求操作时,将会把请求信息添加到 request_queue_ 队列再通过条件变量通知到 V4L2Camera::enqueueRequestBuffers() 函数(在 Camera::initialize() 中已经创建线程运行该函数了)。
enqueueRequestBuffers() 操作如下:
以上,HAL与Framework完成了交互。
dump() 函数则是dump各种设置参数等操作,而 flush() 则是进行清除 mInFlightTracker 中保存的各个请求以及通过 V4L2Wrapper::StreamOff() 函数关闭相机设备流传输以及清除buffer等。
在 V4L2Camera::initStaticInfo() 中,将会初始化一些配置信息,就是在这里进行初始化操作的。详细可参考 天才2012 的:Android Camera API2中采用CameraMetadata用于从APP到HAL的参数交互 。
Android Camera