我们以 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 一个对象做了哪些工作?
- 获取 camera 个数
- 分配 HAL 描述符表
- 获取每个 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);
}
}
......
}
- 打开设备节点 /dev/media ~ /dev/mediaN
- 向 camera 驱动发送命令 MEDIA_IOC_DEVICE_INFO,获取 media_device_info
- 向 camera 驱动发送命令 MEDIA_IOC_ENUM_ENTITIES,获取 media_entity_desc
- 打开 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;
}
转载:https://blog.csdn.net/tyyj90/article/details/108693725