7、Camera HAL层实现:从open到process_capture_request的完整解析
各位同学,今天我们来啃一块硬骨头——Camera HAL层的核心流程。说实话,HAL层是Android Camera框架里最"接地气"的一层,它直接跟硬件打交道。我当年刚接触这块时,也被那一堆回调函数和buffer流转搞得头大。但别怕,咱们一步步拆解。
7.1 open/initialize/configure_streams流程详解
这三个接口,说白了就是Camera HAL的"三段式"启动流程。每个阶段都有它存在的意义,咱们一个一个看。
7.1.1 open()——打开相机设备
open()是HAL层被调用的第一个接口。它的任务很简单:创建一个camera3_device_t实例,并绑定好ops函数表。
// 典型的open实现
int camera_device_open(const struct hw_module_t* module,
const char* id,
struct hw_device_t** device) {
// 1. 分配设备结构体
camera3_device_t* cam_dev = (camera3_device_t*)malloc(sizeof(camera3_device_t));
if (!cam_dev) return -ENOMEM;
// 2. 初始化ops函数表
cam_dev->ops = &camera3_device_ops;
cam_dev->priv = new CameraDevice(atoi(id));
// 3. 填充公共字段
cam_dev->common.tag = HARDWARE_DEVICE_TAG;
cam_dev->common.version = CAMERA_DEVICE_API_VERSION_3_4;
cam_dev->common.close = camera_device_close;
*device = (hw_device_t*)cam_dev;
return 0;
}
7.1.2 initialize()——真正的初始化
initialize()会传入一个camera3_callback_ops_t指针,这是HAL跟framework通信的"电话线"。你得把它保存好,后面所有的事件上报、数据回调都靠它。
int CameraDevice::initialize(const camera3_callback_ops_t* callback_ops) {
// 保存回调接口
mCallbackOps = callback_ops;
// 初始化ISP硬件
mIspDriver->init();
// 创建请求队列
mRequestQueue = new MessageQueue();
// 启动预览线程
mPreviewThread = new std::thread(&CameraDevice::previewLoop, this);
return 0;
}
initialize()完成后,framework会认为相机设备已经就绪,可以开始配置数据流了。
7.1.3 configure_streams()——配置数据流
这个接口是HAL层最复杂的部分之一。它接收一个camera3_stream_configuration_t结构体,里面包含了所有需要配置的stream信息。
| Stream类型 | 用途 | 典型分辨率 |
|---|---|---|
| CAMERA3_STREAM_OUTPUT | 预览/拍照输出 | 1920x1080 |
| CAMERA3_STREAM_INPUT | 输入流(如YUV reprocessing) | 取决于输入源 |
| CAMERA3_STREAM_BIDIRECTIONAL | 双向流(少见) | — |
int CameraDevice::configure_streams(
camera3_stream_configuration_t* stream_config) {
// 1. 验证配置
if (stream_config->num_streams > MAX_STREAMS) {
return -EINVAL;
}
// 2. 遍历所有stream,配置硬件
for (size_t i = 0; i < stream_config->num_streams; i++) {
camera3_stream_t* stream = stream_config->streams[i];
stream->usage = GRALLOC_USAGE_SW_READ_OFTEN;
stream->max_buffers = 4;
// 根据格式配置ISP管线
switch (stream->format) {
case HAL_PIXEL_FORMAT_YCbCr_420_888:
mIspDriver->configYuvPipe(stream->width, stream->height);
break;
case HAL_PIXEL_FORMAT_BLOB:
mIspDriver->configJpegPipe(stream->width, stream->height);
break;
}
}
// 3. 计算并返回stall duration
return 0;
}
7.2 process_capture_request实现
这是HAL层的核心接口,每次拍照或预览帧都会走到这里。它接收一个camera3_capture_request_t,里面包含了metadata、buffer等信息。
7.2.1 Request解析
一个capture request包含三部分:settings(3A参数)、input_buffer(如果有)、output_buffers(目标buffer列表)。
int CameraDevice::process_capture_request(
const camera3_capture_request_t* request) {
// 1. 解析settings
camera_metadata_ro_entry_t entry;
if (find_camera_metadata_ro_entry(
request->settings,
ANDROID_SENSOR_EXPOSURE_TIME,
&entry)) {
mExposureTime = entry.data.i64[0];
}
// 2. 解析output buffers
for (size_t i = 0; i < request->num_output_buffers; i++) {
const camera3_stream_buffer_t* buf = &request->output_buffers[i];
// 处理每个output buffer
mPendingBuffers.push_back(buf);
}
// 3. 提交到硬件队列
mRequestQueue->push(request);
return 0;
}
7.2.2 ISP参数下发
ISP参数下发是HAL层最"硬核"的部分。你需要把Android的metadata转换成ISP寄存器能理解的值。
void CameraDevice::applyIspSettings(
const camera_metadata_t* settings) {
// 转换曝光时间
int64_t exposure = getMetadataValue(
settings, ANDROID_SENSOR_EXPOSURE_TIME);
mIspDriver->setExposureTime(exposure / 1000); // ns -> us
// 转换增益
int32_t gain = getMetadataValue(
settings, ANDROID_SENSOR_SENSITIVITY);
mIspDriver->setAnalogGain(gain / 100.0f);
// 转换白平衡
camera_metadata_rational_t wb = getMetadataRational(
settings, ANDROID_COLOR_CORRECTION_GAINS);
mIspDriver->setWhiteBalance(wb.numerator / (float)wb.denominator);
}
7.2.3 Buffer处理
Buffer处理是HAL层性能的关键。你需要管理好buffer的生命周期,确保不丢帧、不重复使用正在处理的buffer。
void CameraDevice::handleBuffer(
camera3_stream_buffer_t* buffer,
const void* data, size_t data_size) {
// 1. 获取buffer的handle
buffer_handle_t* buf_handle = buffer->buffer;
// 2. 锁定buffer,获取CPU访问地址
void* cpu_addr;
mGrallocModule->lock(*buf_handle,
GRALLOC_USAGE_SW_WRITE_OFTEN,
0, 0, width, height,
&cpu_addr);
// 3. 拷贝ISP输出数据到buffer
memcpy(cpu_addr, data, data_size);
// 4. 解锁buffer
mGrallocModule->unlock(*buf_handle);
// 5. 通知framework buffer已就绪
buffer->status = CAMERA3_BUFFER_STATUS_OK;
buffer->release_fence = -1;
mCallbackOps->process_capture_result(mCallbackOps, &result);
}
7.3 flush/flush_ongoing机制
flush机制是Android Camera HAL里一个容易被忽视但非常重要的部分。当framework需要快速关闭相机时(比如切换到其他应用),会调用flush来清空所有pending的request。
int CameraDevice::flush() {
// 1. 停止接收新request
mRequestQueue->stop();
// 2. 清空硬件队列
mIspDriver->flushQueue();
// 3. 返回所有pending buffer
for (auto& buf : mPendingBuffers) {
camera3_capture_result_t result = {};
result.num_output_buffers = 1;
result.output_buffers = &buf;
result.frame_number = buf.frame_number;
result.result = NULL;
result.partial_result = 0;
buf.status = CAMERA3_BUFFER_STATUS_ERROR;
mCallbackOps->process_capture_result(mCallbackOps, &result);
}
mPendingBuffers.clear();
return 0;
}
7.4 Error Handling与Callback机制
Camera HAL的错误处理机制,说白了就是"出事了怎么告诉framework"。Android定义了几种错误类型:
- CAMERA3_MSG_ERROR_DEVICE:设备级错误,比如ISP挂了
- CAMERA3_MSG_ERROR_REQUEST:单个request处理失败
- CAMERA3_MSG_ERROR_RESULT:metadata生成失败
- CAMERA3_MSG_ERROR_BUFFER:buffer处理失败
void CameraDevice::notifyError(
uint32_t frame_number,
camera3_error_msg_code_t error_code) {
camera3_notify_msg_t msg = {};
msg.type = CAMERA3_MSG_ERROR;
msg.message.error.frame_number = frame_number;
msg.message.error.error_code = error_code;
mCallbackOps->notify(mCallbackOps, &msg);
}
Callback机制则是HAL层主动上报的通道。除了错误通知,还有快门事件、3A状态变化等。
7.5 实战:基于Rockchip平台实现一个最小HAL
好了,理论说完了,咱们来点实际的。下面是一个基于Rockchip RK3588平台的最小HAL实现骨架。
// rk_camera_hal.cpp
class RkCameraDevice : public CameraDevice {
public:
RkCameraDevice(int id) : mCameraId(id) {
// Rockchip ISP驱动初始化
mIspDrv = new RkIspDriver("/dev/video" + std::to_string(id));
}
int initialize(const camera3_callback_ops_t* callback_ops) override {
mCallbackOps = callback_ops;
mIspDrv->init();
mIspDrv->loadTuningFile("/etc/camera/ov5640_tuning.xml");
return 0;
}
int configure_streams(
camera3_stream_configuration_t* stream_config) override {
// Rockchip平台支持的最大stream数
if (stream_config->num_streams > 3) {
return -EINVAL;
}
for (size_t i = 0; i < stream_config->num_streams; i++) {
auto* stream = stream_config->streams[i];
// Rockchip ISP支持NV12和JPEG
if (stream->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
mIspDrv->configChannel(0, stream->width, stream->height);
} else if (stream->format == HAL_PIXEL_FORMAT_BLOB) {
mIspDrv->configJpegChannel(stream->width, stream->height);
}
}
return 0;
}
int process_capture_request(
const camera3_capture_request_t* request) override {
// 解析Rockchip特有的ISP参数
RkIspParams params;
parseRkIspParams(request->settings, ¶ms);
mIspDrv->setParams(params);
// 提交到硬件
mIspDrv->enqueueRequest(request);
return 0;
}
private:
int mCameraId;
RkIspDriver* mIspDrv;
};
这个最小HAL虽然简单,但已经包含了所有核心流程。你可以在此基础上扩展,比如添加3A算法、多帧合成、HDR等功能。
嗯,HAL层的实现就讲到这里。记住,HAL层是连接Android框架和硬件驱动的桥梁,它的设计质量直接影响相机性能和稳定性。写HAL代码时,多想想边界情况,多想想异常处理,这样你的代码才能经得起考验。