4. 打开摄像头设备
任务说明
本案例实现Android Camera HAL层中打开摄像头设备的核心流程:通过Camera Module接口获取摄像头信息,调用open()方法建立与底层硬件的会话,并完成设备能力查询与初始化。最终交付一个可独立编译运行的HAL层测试程序,验证open流程的正确性。
核心代码实现
// camera_device_open_test.c
// 编译: gcc -o camera_open_test camera_device_open_test.c -I./include
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hardware/camera_common.h>
#include <hardware/camera.h>
#include <camera_metadata.h>
// 模拟底层硬件设备结构(真实HAL中对应具体sensor驱动)
typedef struct {
int32_t device_id;
int32_t facing;
int32_t orientation;
int32_t max_fps;
} mock_sensor_t;
static mock_sensor_t mock_sensors[] = {
{0, CAMERA_FACING_BACK, 90, 30},
{1, CAMERA_FACING_FRONT, 270, 30},
};
// 模拟打开硬件设备(真实场景中调用V4L2或ISP驱动)
static int mock_hw_open(int32_t id, void **hw_handle) {
if (id < 0 || id >= (int32_t)(sizeof(mock_sensors)/sizeof(mock_sensors[0]))) {
return -ENODEV;
}
*hw_handle = &mock_sensors[id];
return 0;
}
// HAL open回调:对应camera_module_t.common.methods->open
static int hal_device_open(const struct hw_module_t* module,
const char* name,
struct hw_device_t** device) {
if (module == NULL || name == NULL || device == NULL) {
return -EINVAL;
}
// 解析摄像头ID(name格式为"0"、"1"等)
char *endptr;
long id = strtol(name, &endptr, 10);
if (*endptr != '\0' || id < 0 || id >= (long)(sizeof(mock_sensors)/sizeof(mock_sensors[0]))) {
return -EINVAL;
}
// 打开底层硬件
void *hw_handle = NULL;
int ret = mock_hw_open((int32_t)id, &hw_handle);
if (ret != 0) {
return ret;
}
// 分配并初始化camera_device_t
camera_device_t *cam_dev = calloc(1, sizeof(camera_device_t));
if (cam_dev == NULL) {
return -ENOMEM;
}
cam_dev->common.tag = HARDWARE_DEVICE_TAG;
cam_dev->common.version = CAMERA_DEVICE_API_VERSION_1_0;
cam_dev->common.module = (struct hw_module_t*)module;
cam_dev->common.close = NULL; // 本案例不实现close
// 保存硬件句柄到私有数据(真实HAL中放入priv字段)
cam_dev->priv = hw_handle;
*device = (struct hw_device_t*)cam_dev;
return 0;
}
// 获取摄像头信息回调
static int hal_get_camera_info(struct camera_module_t* module,
int camera_id,
struct camera_info* info) {
if (module == NULL || info == NULL) {
return -EINVAL;
}
if (camera_id < 0 || camera_id >= (int32_t)(sizeof(mock_sensors)/sizeof(mock_sensors[0]))) {
return -ENODEV;
}
mock_sensor_t *sensor = &mock_sensors[camera_id];
info->device_id = camera_id;
info->facing = sensor->facing;
info->orientation = sensor->orientation;
info->resource_cost = 0;
info->conflicting_devices = NULL;
info->conflicting_devices_length = 0;
// 构造静态相机特征(仅包含必要字段)
info->static_camera_characteristics = NULL; // 本案例不填充完整metadata
return 0;
}
// 模块定义
static struct hw_module_methods_t hal_module_methods = {
.open = hal_device_open,
};
camera_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = CAMERA_MODULE_API_VERSION_1_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = CAMERA_HARDWARE_MODULE_ID,
.name = "Mock Camera HAL Module",
.author = "HAL Course",
.methods = &hal_module_methods,
.dso = NULL,
.reserved = {0},
},
.get_number_of_cameras = NULL, // 本案例不实现
.get_camera_info = hal_get_camera_info,
.set_callbacks = NULL,
.get_vendor_tag_ops = NULL,
.open_legacy = NULL,
.set_torch_mode = NULL,
.init = NULL,
.reserved = {0},
};
// 测试入口
int main(void) {
const hw_module_t *hw_module = &HAL_MODULE_INFO_SYM.common;
camera_module_t *cam_module = (camera_module_t*)hw_module;
printf("=== Camera HAL Open Test ===\n");
// 1. 查询摄像头数量(本案例固定为2)
int num_cameras = sizeof(mock_sensors)/sizeof(mock_sensors[0]);
printf("[1] Number of cameras: %d\n", num_cameras);
// 2. 遍历所有摄像头,执行open流程
for (int i = 0; i < num_cameras; i++) {
printf("\n--- Camera %d ---\n", i);
// 2.1 获取摄像头信息
struct camera_info info;
int ret = cam_module->get_camera_info(cam_module, i, &info);
if (ret != 0) {
printf("[FAIL] get_camera_info(%d) returned %d\n", i, ret);
return -1;
}
printf("[OK] get_camera_info: facing=%s orientation=%d\n",
info.facing == CAMERA_FACING_BACK ? "BACK" : "FRONT",
info.orientation);
// 2.2 构造设备名并调用open
char dev_name[8];
snprintf(dev_name, sizeof(dev_name), "%d", i);
struct hw_device_t *hw_dev = NULL;
ret = hw_module->methods->open(hw_module, dev_name, &hw_dev);
if (ret != 0) {
printf("[FAIL] open(%s) returned %d\n", dev_name, ret);
return -1;
}
// 2.3 验证设备句柄
camera_device_t *cam_dev = (camera_device_t*)hw_dev;
if (cam_dev->common.tag != HARDWARE_DEVICE_TAG) {
printf("[FAIL] Invalid device tag\n");
return -1;
}
// 2.4 验证底层硬件已正确关联
mock_sensor_t *sensor = (mock_sensor_t*)cam_dev->priv;
if (sensor == NULL || sensor->device_id != i) {
printf("[FAIL] Hardware handle mismatch\n");
return -1;
}
printf("[OK] open(%s) success, device_id=%d max_fps=%d\n",
dev_name, sensor->device_id, sensor->max_fps);
// 释放设备(真实HAL中调用close)
free(cam_dev);
}
printf("\n=== All camera open tests PASSED ===\n");
return 0;
}
代码说明
上述代码实现了一个最小化的Camera HAL打开设备流程:HAL_MODULE_INFO_SYM定义了标准的camera_module_t结构,其中get_camera_info回调返回模拟的摄像头朝向与旋转角信息;hal_device_open函数解析设备名字符串得到摄像头ID,调用mock_hw_open模拟底层驱动打开动作,并分配camera_device_t结构体,将硬件句柄存入priv字段。测试主函数遍历两个模拟摄像头,依次执行信息查询与设备打开,并校验返回的设备句柄与底层硬件关联是否正确。
编译与运行
# 需要Android HAL头文件路径(此处以标准路径示例)
gcc -o camera_open_test camera_device_open_test.c \
-I./include \
-L./lib -lcamera_metadata
# 运行测试
./camera_open_test
验证方法与判定标准
运行程序后,观察标准输出:
- 程序依次打印
[1] Number of cameras: 2,随后对Camera 0和Camera 1分别输出[OK] get_camera_info与[OK] open(...) success; - Camera 0应显示
facing=BACK orientation=90,Camera 1应显示facing=FRONT orientation=270; - 最终输出
=== All camera open tests PASSED ===,且进程退出码为0。
满足以上条件即可判定打开摄像头设备流程实现正确。若任一摄像头open失败或信息不匹配,程序会打印[FAIL]并提前退出,此时需检查设备ID解析或硬件模拟逻辑。