前段时间在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.03.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,分析预览过程

更多相关文章

  1. Android(安卓)开源框架选择
  2. 使用FileProvider共享文件
  3. Android调用摄像头拍照和从相册中选择(上传、更换头像)
  4. Android(安卓)Jetpack之Navigation源码分析
  5. 【Android(安卓)Developers Training】 20. 创建一个Fragment
  6. 【原创】【Android(安卓)Camera】—— 关于FaceDetection
  7. Android(安卓)Framework初步认识
  8. Android的OutOfMemory解决
  9. Android(安卓)中TransitionDrawable的使用

随机推荐

  1. Android(安卓)bitmap.recycle()导致tryin
  2. Android布局优化ViewStub源码分析
  3. 关于下载最新版本Android(安卓)Studio却
  4. android 使用xutils3 https详解
  5. android相关知识简介
  6. Android(安卓)Installation error: INSTA
  7. Android摄像头采集Demo
  8. Linux/Android启动之Machine-Init函数
  9. Android(安卓)从外部网页拉起跳转到App
  10. 牛逼的Android(安卓)UI