Android(安卓)Camera2 Hal3(一)初始化
前段时间在4412的开发板上面调通了camera 5.0 hardware,现在来梳理下camera框架。
我这里的camera device api版本使用的是3.0;camera module api版本使用的是2.3;CameraService会根据这个api版本初始化不同的client,例如这里将初始化Camera2Client。
mDevice.common.version = CAMERA_DEVICE_API_VERSION_3_0;camera_module_t HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = CAMERA_MODULE_API_VERSION_2_3, .hal_api_version = HARDWARE_HAL_API_VERSION, .id = CAMERA_HARDWARE_MODULE_ID, .name = "V4l2 Camera", }, .get_number_of_cameras = android::HalModule::getNumberOfCameras, .get_camera_info = android::HalModule::getCameraInfo, .set_callbacks = android::HalModule::setCallbacks,};
类说明:
CameraDeviceFactory:工具类,根据hal中选择的device版本来选择初始化Camera2Device或者Camera3Device;我这里是
CAMERA_DEVICE_API_VERSION_3_0,所以会初始化Camera3Device
CameraDeviceBase:Camera3Device和Camera2Device的基类。Camera2Client通过它来访问hardware
CameraService初始化
void CameraService::onFirstRef(){ LOG1("CameraService::onFirstRef"); hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&mModule) < 0 mNumberOfCameras = mModule->get_number_of_cameras(); //调用的是hal层的android::HalModule::getNumberOfCameras if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_1) { mModule->set_callbacks(this);//api版本大于等于2.1设置回调,我这里没有具体实现这个接口,直接在hal层中return OK } if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_2) { setUpVendorTags();//这里会调用camera_module_t的get_vendor_tag_ops,这个可以不实现 } CameraDeviceFactory::registerService(this);//将CameraService注册到CameraDeviceFactory中,用于调用CameraService中的接口 }}
开机过程
开机时候statusbar会去打开camera,读取一些信息。我们以CameraManager.getCameraCharacteristics为入口分析代码。
statusbar调用CameraManager.getCameraCharacteristics后,经过层层调用(如下bouml时序图)将调用CameraService端的connectHelperLocked函数,在这个函数里面会根据hardware传递过来的参数来决定初始化哪一种client。
CameraService::connectHelperLocked{int deviceVersion = getDeviceVersion(cameraId, &facing);//调用mModule->get_camera_info获取struct camera_info结构体信息,然后得到camera模块版本号switch(deviceVersion){case CAMERA_DEVICE_API_VERSION_2_0:......:2.0到3.2版本case CAMERA_DEVICE_API_VERSION_3_2:client = new Camera2Client(......);//由于api为CAMERA_DEVICE_API_VERSION_3_0,所以它的构造函数会去初始化Camera3Device}status_t status = connectFinishUnsafe(client, client->getRemote())}status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client , ...){status_t status = client->initialize(mModule);//这个函数将会调用Camera2ClientBase->initialize 然后调用Camera3Device->initialize 进行初始化,并为CameraMetadata的初始化做一个准备。}
下面来分析 client->initialize是是如何调用到Camera3Device->initialize ,进而初始化CameraMetadata相关的。
这里先来分析Camera2ClientBase中的mDevice指向的是哪一个类。
Camera2Client的类图如上图所示。查看源码可以知道Camera2Client的构造函数构造Camera2ClientBase,Camera2ClientBase的构造函数构造client(client是CameraService的内部类),Client的构造函数里面构造BasicClient(BasicClient是CameraService的内部类)。
这里面一个比较重要的构造过程是Camera2ClientBase的构造。
template <typename TClientBase>//TClientBase为CameraService::clientCamera2ClientBase<TClientBase>::Camera2ClientBase( const sp<CameraService>& cameraService,...... int servicePid): TClientBase(cameraService, remoteCallback, clientPackageName, cameraId, cameraFacing, clientPid, clientUid, servicePid),......{ mDevice = CameraDeviceFactory::createDevice(cameraId);......}
前面说过CameraDeviceFactory是一个工具类,它主要根据hal传递过来的camera device version来选择构造Camera2Device或者Camera3Device。
sp<CameraDeviceBase> CameraDeviceFactory::createDevice(int cameraId) { ...... switch (deviceVersion) { case CAMERA_DEVICE_API_VERSION_2_0: case CAMERA_DEVICE_API_VERSION_2_1: device = new Camera2Device(cameraId); break; case CAMERA_DEVICE_API_VERSION_3_0://我从hal传递的是这个值 case CAMERA_DEVICE_API_VERSION_3_1: case CAMERA_DEVICE_API_VERSION_3_2: device = new Camera3Device(cameraId);//所以初始化Camera3Device break; default:...... }}
所以,Camera2ClientBase中的mDevice指向的是Camera3Device。
从Camera2Client的类图可以看出:父类BasicClient的虚函数initialize只有client没有实现。因为Camera2Client有实现这个接口,所以client->initialize会先调用Camera2Client->initialize
Camera2Client::initialize(camera_module_t *module){res = Camera2ClientBase::initialize(module);//先执行父类Camera2ClientBase的}template <typename TClientBase>status_t Camera2ClientBase<TClientBase>::initialize(camera_module_t *module) { res = mDevice->initialize(module);//从上面分析可以看出这里调用的是Camera3Device->initialize}
接下来来分析前面说的Camera3Device->initialize是如何初始化CameraMetadata的。
先来介绍下CameraMetadata,它是一个工具类,从它的头文件可以看到一句英文介绍:A convenience wrapper around the C-based camera_metadata_t library. 针对基于C库的camera_metadata_t结构的便捷包装。从它的代码中可以看出它重载了=,里面是对于私有变量
camera_metadata_t *mBuffer的赋值操作;然后还实现了追加元数据的函数append。所以这个类本质上是为了维护camera_metadata_t而创造的。
/** * A convenience wrapper around the C-based camera_metadata_t library. */class CameraMetadata {CameraMetadata &operator=(const camera_metadata_t *buffer); private: camera_metadata_t *mBuffer; } CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) { if (CC_LIKELY(buffer != mBuffer)) { camera_metadata_t *newBuffer = clone_camera_metadata(buffer);...... } return *this;status_t CameraMetadata::append(const camera_metadata_t* other) {...... return append_camera_metadata(mBuffer, other);}}
在Camera3Device::initialize中调用到了camera_info结构的static_camera_characteristics(如下图Camera3Device::initialize调用所示),这个值在前面的camera_module_t HAL_MODULE_INFO_SYM被赋值,所以调用的是hal中对应的函数,我这里对应的函数是我hal中的camera_metadata_t *Camera::staticCharacteristics()
在hal的Camera::staticCharacteristics中,会生成一个CameraMetadata,然后设置摄像头分辨率,支持的图像格式,摄像头的水平角度等等。然后会返回给上层,保存在Camera3Device的mDeviceInfo(mDeviceInfo就是CameraMetadata)中。
camera_metadata_t *Camera::staticCharacteristics() {CameraMetadata cm; const int32_t sensorInfoPixelArraySize[] = { (int32_t)sensorRes.width, (int32_t)sensorRes.height }; cm.update(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, sensorInfoPixelArraySize, NELEM(sensorInfoPixelArraySize));//设置分辨率大小 static const int32_t scalerAvailableFormats[] = { HAL_PIXEL_FORMAT_RGBA_8888, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /* Non-preview one, must be last - see following code */ HAL_PIXEL_FORMAT_BLOB }; cm.update(ANDROID_SCALER_AVAILABLE_FORMATS, scalerAvailableFormats, NELEM(scalerAvailableFormats));//设置支持的格式 ......}
到了这里,我们已经知道了Cama2Client的构造和初始化(initialize)中会去调用hal层的代码创建CameraMetadata,然后得到摄像头的参数。接下来分析摄像头数据是在哪里解析的。
从状态栏关于camera的bouml调用中,我们可以看到初始化完Cama2Client,得到CameraMetadata后,会调用l.mParameters.initialize,元数据的解析就是在这里。l.mParameters.initialize实际上就是调用Parameters::initialize,只不过给它加了一把Mutex而已。
在调用 res = l.mParameters.initialize(&(mDevice->info()), mDeviceVersion);的时候,mDevice->info()作为参数传递进去,它其实是获取前面保存的Camera3Device::mDeviceInfo,也就是从底层初始化而来的CameraMetadata。下面举个例子看看Parameters是如何处理CameraMetadata。
tatus_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {res = getFilteredSizes(MAX_PREVIEW_SIZE, &availablePreviewSizes);//获取分辨率 for (size_t i = 0 ; i < availablePreviewSizes.size(); i++) { int newWidth = availablePreviewSizes[i].width; int newHeight = availablePreviewSizes[i].height; ...//将分辨率保存起来 } params.setPreviewSize(previewWidth, previewHeight);// CameraParameters2 params;}status_t Parameters::getFilteredSizes(Size limit, Vector<Size> *sizes) {camera_metadata_ro_entry_t availableProcessedSizes =staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, SIZE_COUNT);//获取分辨率}//Parameters从CameraMetadata中获取到底层传递过来的数据,通过其find函数去获取对应的数据段camera_metadata_ro_entry_t Parameters::staticInfo(uint32_t tag,size_t minCount, size_t maxCount, bool required){camera_metadata_ro_entry_t entry = info->find(tag);//这里的info就是CameraMetadata,也就是Parameters::initialize传递进来的参数}
可以看出,Parameters在初始化的时候去查找CameraMetadata里面的数据,获取如分辨率,数据格式等信息。然后将信息保存在自己的CameraParameters2成员中。
至此,我们已经明白了,在device api为CAMERA_DEVICE_API_VERSION_3_0,module api为CAMERA_MODULE_API_VERSION_2_3的时候,CameraService初始化了Camera2Client Camera3Device;然后Camera2Client通过Camera3Device去获取hal中关于摄像头的信息,并将信息保存在Camera3Device里面的CameraMetadata类型成员mDeviceInfo。随后Parameters::initialize会去解析CameraMetadata,然后保存在CameraParameters2类型成员params中。
下一章我们继续分析camera,分析预览过程
更多相关文章
- Android(安卓)开源框架选择
- 使用FileProvider共享文件
- Android调用摄像头拍照和从相册中选择(上传、更换头像)
- Android(安卓)Jetpack之Navigation源码分析
- 【Android(安卓)Developers Training】 20. 创建一个Fragment
- 【原创】【Android(安卓)Camera】—— 关于FaceDetection
- Android(安卓)Framework初步认识
- Android的OutOfMemory解决
- Android(安卓)中TransitionDrawable的使用