Android 源码 QCamera2 HAL 分析

我们以 moto Nexus 6 device/moto/shamu/camera/QCamera2/ 为例进行分析。QCamera2Hal.cpp 中给 hw_module_t 结构体 camera_common 进行了赋值,然后又给 camera_module_t 结构体 HAL_MODULE_INFO_SYM 赋值,HAL_MODULE_INFO_SYM 名字是固定的,这样 hw_get_module(…) 函数才能正常工作。

device/moto/shamu/camera/QCamera2/QCamera2Hal.cpp

#include "QCamera2Factory.h"
#include "HAL3/QCamera3VendorTags.h"

static hw_module_t camera_common = {
    tag: HARDWARE_MODULE_TAG,
    module_api_version: CAMERA_MODULE_API_VERSION_2_4,
    hal_api_version: HARDWARE_HAL_API_VERSION,
    id: CAMERA_HARDWARE_MODULE_ID,
    name: "QCamera Module",
    author: "Qualcomm Innovation Center Inc",
    methods: &qcamera::QCamera2Factory::mModuleMethods,
    dso: NULL,
    reserved:  {0},
};

camera_module_t HAL_MODULE_INFO_SYM = {
    common: camera_common,
    get_number_of_cameras: qcamera::QCamera2Factory::get_number_of_cameras,
    get_camera_info: qcamera::QCamera2Factory::get_camera_info,
    set_callbacks: qcamera::QCamera2Factory::set_callbacks,
    get_vendor_tag_ops: qcamera::QCamera3VendorTags::get_vendor_tag_ops,
    open_legacy: qcamera::QCamera2Factory::open_legacy,
    set_torch_mode: qcamera::QCamera2Factory::set_torch_mode,
    init: NULL,
    reserved: {0}
};

get_number_of_cameras 函数指针具体指向了 qcamera::QCamera2Factory::get_number_of_cameras。

如果 gQCamera2Factory 为空,则先 new 一个对象出来,然后调用其 getNumberOfCameras() 方法。

device/moto/shamu/camera/QCamera2/QCamera2Factory.cpp

namespace qcamera {
......
int QCamera2Factory::get_number_of_cameras()
{
    if (!gQCamera2Factory) {
        gQCamera2Factory = new QCamera2Factory();
        if (!gQCamera2Factory) {
            ALOGE("%s: Failed to allocate Camera2Factory object", __func__);
            return 0;
        }
    }
    return gQCamera2Factory->getNumberOfCameras();
}
......
}

先来分析 new 一个对象做了哪些工作?

  1. 获取 camera 个数
  2. 分配 HAL 描述符表
  3. 获取每个 camera camera_info

device/moto/shamu/camera/QCamera2/QCamera2Factory.cpp

namespace qcamera {
......
QCamera2Factory::QCamera2Factory()
{
    camera_info info;
    int i = 0;
    mHalDescriptors = NULL;
    mCallbacks = NULL;
    // 获取 camera 个数
    mNumOfCameras = get_num_of_cameras();
    char prop[PROPERTY_VALUE_MAX];
    property_get("persist.camera.HAL3.enabled", prop, "0");
    int isHAL3Enabled = atoi(prop);

    if ((mNumOfCameras > 0) && (mNumOfCameras <= MM_CAMERA_MAX_NUM_SENSORS)) {
        // 分配 HAL 描述符表
        mHalDescriptors = new hal_desc[mNumOfCameras];
        if ( NULL != mHalDescriptors) {
            uint32_t cameraId = 0;

            for (; i < mNumOfCameras ; i++, cameraId++) {
                mHalDescriptors[i].cameraId = cameraId;
                if (isHAL3Enabled) {
                    mHalDescriptors[i].device_version = CAMERA_DEVICE_API_VERSION_3_0;
                } else {
                    mHalDescriptors[i].device_version = CAMERA_DEVICE_API_VERSION_1_0;
                }
                //在此时查询 camera,以避免在随后调用 'getCameraInfo()' 时出现任何延迟
                getCameraInfo(i, &info);
            }
        } else {
            ALOGE("%s: Not enough resources to allocate HAL descriptor table!",
                  __func__);
        }
    } else {
        ALOGE("%s: %d camera devices detected!", __func__, mNumOfCameras);
    }
}
......
}
  1. 打开设备节点 /dev/media ~ /dev/mediaN
  2. 向 camera 驱动发送命令 MEDIA_IOC_DEVICE_INFO,获取 media_device_info
  3. 向 camera 驱动发送命令 MEDIA_IOC_ENUM_ENTITIES,获取 media_entity_desc
  4. 打开 sensor_init subdev

这都需要 camera 驱动支持, camera 驱动 就不再继续分析了。

device/moto/shamu/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c

uint8_t get_num_of_cameras()
{
    int rc = 0;
    int dev_fd = 0;
    struct media_device_info mdev_info;
    int num_media_devices = 0;
    uint8_t num_cameras = 0;
    char subdev_name[32];
    int32_t sd_fd = 0;
    struct sensor_init_cfg_data cfg;
    char prop[PROPERTY_VALUE_MAX];

    property_get("persist.camera.logs", prop, "0");
    gMmCameraIntfLogLevel = atoi(prop);

    CDBG("%s : E", __func__);

    int decrypt = property_get("vold.decrypt", prop, NULL);
    if (0 < decrypt) {
        if(strncmp(prop, "trigger_restart_min_framework", decrypt) == 0) {
            return 0;
        }
    }

    /* lock the mutex */
    pthread_mutex_lock(&g_intf_lock);

    while (1) {
        int32_t num_entities = 1;
        char dev_name[32];
        // 打开设备节点 /dev/media ~ /dev/mediaN
        snprintf(dev_name, sizeof(dev_name), "/dev/media%d", num_media_devices);
        dev_fd = open(dev_name, O_RDWR | O_NONBLOCK);
        if (dev_fd < 0) {
            CDBG("Done discovering media devices\n");
            break;
        }
        num_media_devices++;
        // 向 camera 驱动发送命令 MEDIA_IOC_DEVICE_INFO,获取 media_device_info
        rc = ioctl(dev_fd, MEDIA_IOC_DEVICE_INFO, &mdev_info);
        if (rc < 0) {
            CDBG_ERROR("Error: ioctl media_dev failed: %s\n", strerror(errno));
            close(dev_fd);
            dev_fd = -1;
            break;
        }

        if (strncmp(mdev_info.model, MSM_CONFIGURATION_NAME,
          sizeof(mdev_info.model)) != 0) {
            close(dev_fd);
            dev_fd = -1;
            continue;
        }

        while (1) {
            struct media_entity_desc entity;
            memset(&entity, 0, sizeof(entity));
            entity.id = num_entities++;
            CDBG_ERROR("entity id %d", entity.id);
            // 向 camera 驱动发送命令 MEDIA_IOC_ENUM_ENTITIES,获取 media_entity_desc
            rc = ioctl(dev_fd, MEDIA_IOC_ENUM_ENTITIES, &entity);
            if (rc < 0) {
                CDBG_ERROR("Done enumerating media entities");
                rc = 0;
                break;
            }
            CDBG_ERROR("entity name %s type %d group id %d",
                entity.name, entity.type, entity.group_id);
            if (entity.type == MEDIA_ENT_T_V4L2_SUBDEV &&
                entity.group_id == MSM_CAMERA_SUBDEV_SENSOR_INIT) {
                snprintf(subdev_name, sizeof(dev_name), "/dev/%s", entity.name);
                break;
            }
        }
        close(dev_fd);
        dev_fd = -1;
    }

    /* 打开 sensor_init subdev */
    sd_fd = open(subdev_name, O_RDWR);
    if (sd_fd < 0) {
        CDBG_ERROR("Open sensor_init subdev failed");
        return FALSE;
    }

    cfg.cfgtype = CFG_SINIT_PROBE_WAIT_DONE;
    cfg.cfg.setting = NULL;
    if (ioctl(sd_fd, VIDIOC_MSM_SENSOR_INIT_CFG, &cfg) < 0) {
        CDBG_ERROR("failed");
    }
    close(sd_fd);
    dev_fd = -1;
    ......
    g_cam_ctrl.num_cam = num_cameras;

    get_sensor_info();
    /* unlock the mutex */
    pthread_mutex_unlock(&g_intf_lock);
    CDBG("%s: num_cameras=%d\n", __func__, g_cam_ctrl.num_cam);
    return g_cam_ctrl.num_cam;
}

get_sensor_info() 中获取了 camera 的 facing(前置或后置) 和 orientation。

device/moto/shamu/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c

void get_sensor_info()
{
    ......
    while (1) {
        ......
        while (1) {
            struct media_entity_desc entity;
            unsigned long temp;
            unsigned int mount_angle;
            unsigned int facing;

            memset(&entity, 0, sizeof(entity));
            entity.id = num_entities++;
            rc = ioctl(dev_fd, MEDIA_IOC_ENUM_ENTITIES, &entity);
            if (rc < 0) {
                CDBG("Done enumerating media entities\n");
                rc = 0;
                break;
            }
            if(entity.type == MEDIA_ENT_T_V4L2_SUBDEV &&
                entity.group_id == MSM_CAMERA_SUBDEV_SENSOR) {
                temp = entity.flags >> 8;
                mount_angle = (temp & 0xFF) * 90;
                facing = (temp >> 8);
                ALOGD("index = %d flag = %x mount_angle = %d facing = %d\n"
                    , num_cameras, (unsigned int)temp, (unsigned int)mount_angle,
                    (unsigned int)facing);
                g_cam_ctrl.info[num_cameras].facing = facing;
                g_cam_ctrl.info[num_cameras].orientation = mount_angle;
                num_cameras++;
                continue;
            }
        }

        CDBG("%s: dev_info[id=%d,name='%s']\n",
            __func__, num_cameras, g_cam_ctrl.video_dev_name[num_cameras]);

        close(dev_fd);
        dev_fd = -1;
    }

    CDBG("%s: num_cameras=%d\n", __func__, g_cam_ctrl.num_cam);
    return;
}

QCamera2Factory 类的 getNumberOfCameras() 方法只是简单的将 QCamera2Factory 构造器中赋值的 mNumOfCameras 成员变量返回。

int QCamera2Factory::getNumberOfCameras()
{
    return mNumOfCameras;
}
tyyj90 CSDN认证博客专家 安卓全栈开发
Android高级开发工程师,熟悉App开发,熟悉Framework定制开发,略了解Linux内核。开发使用的语言涉及Java、Kotlin、C/C++、Python和汇编NEON指令集。
©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值