光学基本概念
- 焦距:镜头中心到成像平面的距离,在驱动中通过VCM(音圈马达)控制
- 光圈:光圈值 = 焦距 / 通光孔径直径,F值越小,光圈越大,进光量越多
- 景深:图像中清晰的范围
- 感光度(ISO):传感器对光的敏感程度,在驱动中通过模拟/数字增益实现 // 低ISO → 低噪声,但需要更多光线 // 高ISO → 高噪声,但可在暗光下拍摄
- 白平衡:在不同光源下保持白色物体显示为白色
- 曝光值:EV = log₂(光圈² / 快门时间) + log₂(ISO/100)
图像传感器
工作原理:光子 → 微透镜 → 彩色滤光片 → 光电二极管 → 电子 → 电压 → 数字信号
关键参数
1、量子效率
量子效率:指入射光子转换为电子的效率百分比。它是衡量传感器光电转换能力的核心指标。 QE = (产生的电子数 / 入射光子数) × 100% 波长相关性:QE随波长变化,不同颜色的光转换效率不同
满阱容量 (Full Well Capacity, FWC) 满阱容量指单个像素能够存储的最大电子数量,决定了像素的饱和极限。 理论FWC ≈ (像素面积 × 电容密度 × 工作电压) / 电子电荷
2、噪声特性 (Noise Characteristics)
2.1 散粒噪声 (Shot Noise)
来源:光子到达的随机性和光电转换的统计波动 特性:与信号强度的平方根成正比 √N 不可消除性:这是光的量子本性决定的物理极限
2.2 读取噪声 (Read Noise)
来源:读出电路引入的噪声 组成部分:复位噪声(KTC噪声)、源极跟随器噪声、ADC量化噪声 重要性:决定传感器的低光性能极限
2.3 暗电流噪声 (Dark Current Noise)
来源:热激发产生的电子,与光照无关 温度依赖性:温度每升高6-8°C,暗电流翻倍 表现形式: 固定图案噪声(FPN)、热像素(Hot Pixels)
3、动态范围 (Dynamic Range, DR)
定义:动态范围是传感器同时捕获最亮和最暗细节的能力 线性动态范围(dB) = 20 × log₁₀(最大信号 / 噪声基底) 比特动态范围 = log₂(最大信号 / 噪声基底)
3.1 扩展动态范围技术
3.1.1 双转换增益(DCG)
高增益:优化低光噪声 低增益:扩展高光范围
3.1.2 交错曝光(HDR)
短曝光:捕获高光细节 长曝光:捕获暗部细节
3.1.3 空间多曝光
不同像素采用不同曝光时间
4、像素尺寸 (Pixel Size)
定义:像素尺寸指单个感光单元的物理尺寸,直接影响感光能力和分辨率。
参数间的相互影响
关键权衡关系 像素尺寸 vs 分辨率 传感器尺寸固定时,小像素提高分辨率但降低感光度
满阱容量 vs 转换增益 高转换增益降低噪声但减少满阱容量
读取速度 vs 噪声 高速读取通常伴随更高的读取噪声
动态范围 vs 信噪比 扩展动态范围可能牺牲特定亮度区间的信噪比
音圈马达
电流 → 线圈 → 磁场 → 电磁力 → 镜头移动 ↓ ↓ ↓ ↓ 控制信号 永磁体 洛伦兹力 对焦位置
Camera2 API
public class CameraActivity extends AppCompatActivity { private CameraManager cameraManager; // 相机管理器 private CameraDevice cameraDevice; // 相机设备 private CameraCaptureSession captureSession; // 捕获会话 private CaptureRequest.Builder requestBuilder;// 捕获请求 private ImageReader imageReader; // 图像读取器 }
应用层
应用层相机初始化流程:获取CameraManager->获取相机ID列表->打开相机设备->创建预览会话->创建捕获请求->开始预览
camera服务层
// CameraService 是相机系统的核心服务
class CameraService : public BinderService<CameraService>,
public virtual IBinder::DeathRecipient {
private:
// 相机设备管理
std::map<String8, sp<CameraDeviceClient>> mActiveClients;
// 相机特性管理
CameraMetadata mCameraCharacteristics;
// 权限控制
CameraPermissions mCameraPermissions;
public:
// 主要服务接口
virtual status_t connect(const sp<ICameraClient>& client,
int cameraId,
const String16& clientPackageName,
int clientUid,
int clientPid,
sp<ICamera>* device);
virtual status_t disconnect(int cameraId);
};
常见名词解释
HIDL:HIDL(HAL Interface Definition Language)是Android 8.0引入的硬件接口定义语言。 AIDL:AIDL(Android Interface Definition Language)是Android中的接口定义语言,主要用于应用进程间通信(IPC)。
HAL组成部分
CameraModule.cpp:Camera HAL的核心文件,负责处理相机硬件的初始化、预览、拍照等功能。 CameraDevice.cpp:负责与相机硬件交互,包括打开、关闭相机设备,设置相机参数等。 CameraMetadata.cpp:负责解析和设置相机参数,如ISO、曝光时间、白平衡等。
HAL历程
| 出现版本 | Android 8.0前 | Android 8.0+ | Android 10+ |
| 接口定义 | C/C++头文件 | .hal文件 | .aidl文件 |
| 实现语言 | C/C++ | C++/Java | Java/Kotlin |
| 进程模型 | 进程内调用 | Binder跨进程 | Binder跨进程 |
| 版本兼容性 | 无 | 强(前后向兼容) | 中(需手动适配) |
| 性能 | 最高 | 高 | 较高 |
| 适用场景 | 底层硬件驱动 | 复杂硬件(如GPU) | 纯软件HAL/传感器 |
| 优点 | 简单直接,性能损耗极低(接近原生C调用) | 大幅降低适配成本,进程隔离提升稳定性 | 接口定义极简,开发效率高,完全兼容Android框架生态,易于调试 |
1.1 HAL3 设计理念
HAL3 引入了基于请求的模型,取代了 HAL1 的自动模式控制。核心思想是将相机控制权从 HAL 转移到框架和应用层。
2.1 主要接口组件
ICameraProvider (camera.provider@2.4) ↓ ICameraDevice (camera.device@3.2/3.3/3.4/3.5) ↓ ICameraDeviceSession (camera.device@3.x) ↓ 相机硬件操作
4. ICameraDevice 接口
4.1 设备管理接口
// 硬件/接口/camera/provider/2.4/ICameraProvider.hal
interface ICameraProvider {
// 获取相机ID列表
getCameraIdList(getCameraIdList_cb _hidl_cb) generates (Status status, vec<string> cameraIds);
// 检查是否支持并行相机会话
isSetTorchModeSupported() generates (bool supported);
// 获取相机特性
getCameraCharacteristics(string cameraId) generates (Status status, CameraMetadata characteristics);
// 打开相机设备
openSession(string cameraId, openSession_cb _hidl_cb) generates (Status status, ICameraDeviceSession session);
// 设置回调
setCallback(ICameraProviderCallback callback) generates (Status status);
// 获取供应商标签
getVendorTags() generates (Status status, VendorTagSection[] vendorTags);
};
5. ICameraDeviceSession 接口
5.1 会话操作接口(核心)
interface ICameraDeviceSession {
// 配置数据流
configureStreams(StreamConfiguration requestedConfiguration)
generates (Status status, HalStreamConfiguration halConfiguration);
// 处理捕获请求(核心方法)
processCaptureRequest(vec<CaptureRequest> requests, uint32_t numRequestProcessed)
generates (Status status, uint32_t frameNumber);
// 处理批量捕获请求
processCaptureRequestBatch(vec<CaptureRequest> requests)
generates (Status status, vec<uint32_t> frameNumbers);
// 刷新所有待处理请求
flush() generates (Status status);
// 关闭会话
close() generates (Status status);
// 构建默认请求模板
constructDefaultRequestSettings(RequestTemplate type)
generates (Status status, CameraMetadata requestTemplate);
// 获取捕获结果元数据队列
getCaptureResultMetadataQueue() generates (MQDescriptor<uint8_t, SynchronizedReadWrite> descriptor);
};
6. 核心数据结构
6.1 流配置 (Stream Configuration)
// 流配置结构
struct StreamConfiguration {
vec<Stream> streams; // 流列表
uint32_t operationMode; // 操作模式
CameraMetadata sessionParameters; // 会话参数
bool multiResolutionInput; // 多分辨率输入(HAL3.5)
};
// 单个流定义
struct Stream {
int32_t id; // 流ID
StreamType streamType; // 流类型
uint32_t width; // 宽度
uint32_t height; // 高度
PixelFormat format; // 像素格式
uint64_t usage; // 使用标志
uint64_t dataSpace; // 数据空间
StreamRotation rotation; // 旋转
int32_t physicalCameraId; // 物理相机ID(多相机)
};
6.2 捕获请求 (Capture Request)
// 捕获请求结构
struct CaptureRequest {
uint32_t frameNumber; // 帧号
int32_t fmqSettingsSize; // 设置数据大小
CameraMetadata settings; // 捕获设置
BufferStatus bufferStatus; // 缓冲区状态
vec<StreamBuffer> inputBuffers; // 输入缓冲区
vec<StreamBuffer> outputBuffers; // 输出缓冲区
vec<string> physicalCameraSettings; // 物理相机设置(多相机)
};
### 6.3 流缓冲区 (Stream Buffer)
```cpp
// 流缓冲区结构
struct StreamBuffer {
int32_t streamId; // 流ID
Buffer buffer; // 缓冲区句柄
BufferStatus status; // 缓冲区状态
uint64_t bufferId; // 缓冲区ID
Fence releaseFence; // 释放栅栏
};
7. 回调接口
7.1 设备回调接口
// 相机设备回调
interface ICameraDeviceCallback {
// 处理捕获结果
processCaptureResult(CaptureResult result);
// 处理通知消息
notify(NotifyMsg msg);
};
7.2 通知消息类型
// 通知消息联合体
union NotifyMsg {
ErrorMsg error; // 错误消息
ShutterMsg shutter; // 快门消息
BufferMsg buffers; // 缓冲区消息
};
// 错误消息
struct ErrorMsg {
ErrorCode errorCode; // 错误代码
int32_t frameNumber; // 帧号
int32_t errorStreamId; // 错误流ID
};
8. 关键操作模式
8.1 操作模式常量
// 相机操作模式
enum OperationMode : uint32_t {
NORMAL_MODE = 0, // 普通模式
CONSTRAINED_HIGH_SPEED_MODE = 1, // 约束高速模式
VENDOR_MODE = 0x8000, // 供应商模式
};
8.2 请求模板类型
// 请求模板
enum RequestTemplate : int32_t {
PREVIEW = 1, // 预览
STILL_CAPTURE = 2, // 静态拍照
VIDEO_RECORD = 3, // 视频录制
VIDEO_SNAPSHOT = 4, // 视频快照
ZERO_SHUTTER_LAG = 5, // 零快门延迟
MANUAL = 6, // 手动模式
};
9. 完整 HAL3 实现示例
9.1 相机会话实现
// 相机设备会话实现
class CameraSession : public ICameraDeviceSession {
private:
camera3_device_t *mDevice; // 传统HAL3设备
sp<ICameraDeviceCallback> mCallback; // 回调接口
RequestQueue mRequestQueue; // 请求队列
bool mFlushing; // 刷新状态
public:
// 配置流
Return<void> configureStreams(const StreamConfiguration& requestedConfiguration,
configureStreams_cb _hidl_cb) override {
HalStreamConfiguration halConfig;
status_t status = OK;
// 转换HIDL流配置到HAL流配置
camera3_stream_configuration_t halStreamConfig;
convertToHalStreamConfig(requestedConfiguration, &halStreamConfig);
// 调用HAL配置流
int result = mDevice->ops->configure_streams(mDevice, &halStreamConfig);
if (result != 0) {
status = STATUS_ERROR;
} else {
// 转换HAL流配置回HIDL格式
convertFromHalStreamConfig(&halStreamConfig, &halConfig);
}
_hidl_cb(static_cast<Status>(status), halConfig);
return Void();
}
// 处理捕获请求
Return<Status> processCaptureRequest(const hidl_vec<CaptureRequest>& requests,
uint32_t numRequestProcessed) override {
if (mFlushing) {
return Status::ILLEGAL_ARGUMENT;
}
for (const auto& request : requests) {
// 转换HIDL请求到HAL请求
camera3_capture_request_t halRequest;
convertToHalRequest(request, &halRequest);
// 提交到HAL处理
int result = mDevice->ops->process_capture_request(mDevice, &halRequest);
if (result != 0) {
return Status::INTERNAL_ERROR;
}
}
return Status::OK;
}
// 刷新请求
Return<Status> flush() override {
mFlushing = true;
if (mDevice->ops->flush) {
int result = mDevice->ops->flush(mDevice);
if (result != 0) {
return Status::INTERNAL_ERROR;
}
}
mFlushing = false;
return Status::OK;
}
private:
// 转换HIDL流配置到HAL格式
void convertToHalStreamConfig(const StreamConfiguration& hidlConfig,
camera3_stream_configuration_t* halConfig) {
halConfig->num_streams = hidlConfig.streams.size();
halConfig->operation_mode = hidlConfig.operationMode;
// 分配流数组
std::vector<camera3_stream_t*> streams(hidlConfig.streams.size());
for (size_t i = 0; i < hidlConfig.streams.size(); i++) {
convertToHalStream(hidlConfig.streams[i], &streams[i]);
}
halConfig->streams = streams.data();
}
};
9.2 捕获结果处理
// 捕获结果回调处理
class CaptureResultProcessor {
public:
// 处理HAL返回的捕获结果
void processCaptureResult(const camera3_capture_result_t* halResult) {
CaptureResult hidlResult;
// 转换帧号
hidlResult.frameNumber = halResult->frame_number;
// 转换结果元数据
if (halResult->result) {
hidlResult.result.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(halResult->result)),
get_camera_metadata_size(halResult->result));
}
// 转换输出缓冲区
hidlResult.outputBuffers.resize(halResult->num_output_buffers);
for (uint32_t i = 0; i < halResult->num_output_buffers; i++) {
convertToHidlStreamBuffer(&halResult->output_buffers[i], &hidlResult.outputBuffers[i]);
}
// 设置部分结果
hidlResult.partialResult = halResult->partial_result;
// 通知框架
mCallback->processCaptureResult(hidlResult);
}
// 处理HAL通知
void processNotify(const camera3_notify_msg_t* halMsg) {
NotifyMsg hidlMsg;
switch (halMsg->type) {
case CAMERA3_MSG_SHUTTER:
hidlMsg.shutter({halMsg->message.shutter.frame_number,
halMsg->message.shutter.timestamp});
break;
case CAMERA3_MSG_ERROR:
hidlMsg.error({convertErrorCode(halMsg->message.error.error_code),
halMsg->message.error.frame_number,
halMsg->message.error.error_stream_id});
break;
}
mCallback->notify(hidlMsg);
}
};
10. 数据流管理
10.1 缓冲区管理
// 缓冲区队列管理
class BufferQueueManager {
private:
struct StreamInfo {
int32_t streamId;
uint32_t width;
uint32_t height;
PixelFormat format;
std::queue<StreamBuffer> freeBuffers;
};
std::map<int32_t, StreamInfo> mStreams;
public:
// 注册流
status_t registerStream(const Stream& stream) {
StreamInfo info = {
.streamId = stream.id,
.width = stream.width,
.height = stream.height,
.format = stream.format
};
mStreams[stream.id] = info;
return OK;
}
// 分配缓冲区
StreamBuffer allocateBuffer(int32_t streamId) {
auto& streamInfo = mStreams[streamId];
if (streamInfo.freeBuffers.empty()) {
// 分配新缓冲区
StreamBuffer buffer = createNewBuffer(streamInfo);
return buffer;
} else {
StreamBuffer buffer = streamInfo.freeBuffers.front();
streamInfo.freeBuffers.pop();
return buffer;
}
}
// 返回缓冲区
void returnBuffer(const StreamBuffer& buffer) {
auto& streamInfo = mStreams[buffer.streamId];
streamInfo.freeBuffers.push(buffer);
}
};
11. 错误处理
11.1 错误代码定义
// 错误代码枚举
enum ErrorCode : int32_t {
ERROR_DEVICE = 0, // 设备错误
ERROR_REQUEST = 1, // 请求错误
ERROR_RESULT = 2, // 结果错误
ERROR_BUFFER = 3, // 缓冲区错误
};
11.2 错误处理实现
// 错误处理管理器
class ErrorHandler {
public:
void handleError(ErrorCode errorCode, int32_t frameNumber, int32_t streamId) {
switch (errorCode) {
case ErrorCode::ERROR_DEVICE:
ALOGE("Device error at frame %d", frameNumber);
// 可能需要重启设备
break;
case ErrorCode::ERROR_REQUEST:
ALOGE("Request error at frame %d, stream %d", frameNumber, streamId);
// 丢弃问题请求
break;
case ErrorCode::ERROR_BUFFER:
ALOGE("Buffer error at frame %d, stream %d", frameNumber, streamId);
// 回收问题缓冲区
break;
}
// 通知框架
NotifyMsg msg;
msg.error({errorCode, frameNumber, streamId});
mCallback->notify(msg);
}
};
12. 性能优化
12.1 请求流水线优化
// 高性能请求处理器
class RequestPipeline {
private:
static constexpr size_t MAX_IN_FLIGHT_REQUESTS = 8;
std::vector<CaptureRequest> mInFlightRequests;
std::queue<CaptureRequest> mPendingRequests;
public:
// 提交请求(带节流控制)
Status submitRequest(const CaptureRequest& request) {
if (mInFlightRequests.size() >= MAX_IN_FLIGHT_REQUESTS) {
mPendingRequests.push(request);
return Status::OK; // 请求已排队
}
Status status = processRequestImmediately(request);
if (status == Status::OK) {
mInFlightRequests.push_back(request);
}
return status;
}
// 请求完成回调
void onRequestComplete(uint32_t frameNumber) {
// 移除已完成请求
auto it = std::find_if(mInFlightRequests.begin(), mInFlightRequests.end(),
[frameNumber](const CaptureRequest& req) {
return req.frameNumber == frameNumber;
});
if (it != mInFlightRequests.end()) {
mInFlightRequests.erase(it);
}
// 处理排队请求
if (!mPendingRequests.empty() &&
mInFlightRequests.size() < MAX_IN_FLIGHT_REQUESTS) {
CaptureRequest nextReq = mPendingRequests.front();
mPendingRequests.pop();
submitRequest(nextReq);
}
}
};
13. HAL3 工作流程总结
13.1 典型调用序列
1. getCameraIdList() // 获取相机列表
2. getCameraCharacteristics() // 获取相机特性
3. openSession() // 打开会话
4. configureStreams() // 配置数据流
5. constructDefaultRequestSettings() // 构建默认请求
6. processCaptureRequest() // 处理捕获请求(循环)
7. flush() // 刷新请求(可选)
8. close() // 关闭会话
13.2 关键设计模式
请求-响应模型:框架发送请求,HAL异步返回结果
流式配置:预先配置数据流管道
元数据驱动:每个请求和结果都包含完整的控制参数
缓冲区管理:框架负责缓冲区分配,HAL负责填充数据
HAL3 接口提供了强大而灵活的方式来控制相机硬件,支持复杂的多流场景和精确的参数控制,是现代 Android 相机系统的核心基础。
主流平台 Camera HAL 流程详解
1. 高通(Qualcomm)平台
1.1 高通 Camera 架构
应用层 → 框架层 → 相机服务 → CamX HAL → CHI → 内核驱动
↓
CamX: Camera Extensions
CHI: Camera Hardware Interface
1.2 CamX-CHI 架构详解
// 高通 CamX 核心组件
class CamXHAL {
private:
// CamX 核心引擎
class CamXCore {
public:
// 节点处理管道
struct Pipeline {
Node* sourceNode; // 源节点(传感器)
Node* ispNode; // ISP节点
Node* jpegNode; // JPEG编码节点
Node* fdNode; // 人脸检测节点
};
// 会话管理
class SessionManager {
vector<Session*> activeSessions; // 活跃会话
Session* createSession(); // 创建会话
};
};
// CHI 覆盖层
class CHIOverride {
public:
// 供应商自定义组件
VendorComponent* vendorComponents; // 供应商组件
AlgorithmPlugin* algorithmPlugins; // 算法插件
// 扩展点
virtual void overridePipeline(Pipeline* pipeline);
virtual void overrideNode(Node* node);
};
};
1.3 高通 HAL 流程
// 高通 CamX HAL 实现流程
class QCameraHAL {
public:
// 1. 初始化流程
status_t initialize() {
// 加载CamX核心库
mCamXCore = loadCamXLibrary();
// 初始化CHI覆盖
mCHIOverride = createCHIOverride();
// 注册供应商组件
registerVendorComponents();
// 创建节点工厂
mNodeFactory = createNodeFactory();
return OK;
}
// 2. 打开相机流程
status_t openCamera(const string& cameraId) {
// 创建相机会话
mSession = mCamXCore->createSession();
// 构建处理管道
Pipeline* pipeline = buildPipeline(cameraId);
// 配置管道
mSession->addPipeline(pipeline);
// 提交管道配置
mSession->commitConfiguration();
return OK;
}
// 3. 配置流流程
status_t configureStreams(const StreamConfiguration& config) {
// 为每个输出流创建Chi流
for (auto& stream : config.streams) {
ChiStream* chiStream = createChiStream(stream);
mChiStreams.push_back(chiStream);
}
// 配置管道输出
mPipeline->setOutputStreams(mChiStreams);
// 触发管道重新配置
mSession->reconfigure();
return OK;
}
// 4. 处理捕获请求流程
status_t processCaptureRequest(const CaptureRequest& request) {
// 创建Chi捕获请求
ChiCaptureRequest* chiRequest = createChiRequest(request);
// 设置请求回调
chiRequest->setCallback(mRequestCallback);
// 提交到CamX管道
mPipeline->processRequest(chiRequest);
return OK;
}
private:
// 构建处理管道
Pipeline* buildPipeline(const string& cameraId) {
Pipeline* pipeline = new Pipeline();
// 添加传感器节点
Node* sensorNode = mNodeFactory->createNode("Sensor");
pipeline->addNode(sensorNode);
// 添加IFE节点(图像前端)
Node* ifeNode = mNodeFactory->createNode("IFE");
pipeline->addNode(ifeNode);
// 添加IPE节点(图像后端)
Node* ipeNode = mNodeFactory->createNode("IPE");
pipeline->addNode(ipeNode);
// 添加BPS节点(Bayer处理段)
Node* bpsNode = mNodeFactory->createNode("BPS");
pipeline->addNode(bpsNode);
// 连接节点
pipeline->connectNodes(sensorNode, ifeNode);
pipeline->connectNodes(ifeNode, ipeNode);
pipeline->connectNodes(ifeNode, bpsNode);
return pipeline;
}
};
2. 联发科(MTK)平台
2.1 MTK Camera 架构
应用层 → 框架层 → 相机服务 → MTK HAL → Pipeline模型 → 内核驱动
↓
mtkcam3 (HAL3实现)
2.2 MTK Pipeline 模型
// MTK 管道模型核心组件
class MTKCameraHAL {
private:
// 管道控制器
class PipelineController {
public:
// 管道上下文
struct PipelineContext {
sp<AppStreamMgr> appStreamMgr; // 应用流管理
sp<HalStreamMgr> halStreamMgr; // HAL流管理
sp<PipelineContext> p2Context; // P2管道上下文
sp<MetadataProvider> metadataProvider; // 元数据提供
};
// 构建管道
status_t buildPipeline(const StreamConfiguration& config);
};
// 节点映射器
class NodeMapper {
public:
// 映射流到节点
status_t mapStreamToNode(const Stream& stream);
// 获取P1节点(传感器)
sp<P1Node> getP1Node();
// 获取P2节点(处理)
sp<P2Node> getP2Node();
};
// 会话管理
class SessionManager {
vector< sp<ISession> > mSessions; // 会话列表
};
};
2.3 MTK HAL 流程
// MTK HAL 实现流程
class MTKCamHAL : public ICameraDeviceSession {
public:
// 1. 配置流流程
Return<void> configureStreams(const StreamConfiguration& requestedConfiguration,
configureStreams_cb _hidl_cb) override {
HalStreamConfiguration halConfig;
// 创建管道上下文
mPipelineContext = new PipelineContext();
// 配置应用流管理器
mAppStreamMgr = new AppStreamMgr();
mAppStreamMgr->configureStreams(requestedConfiguration.streams);
// 配置HAL流管理器
mHalStreamMgr = new HalStreamMgr();
mHalStreamMgr->configureStreams(requestedConfiguration.streams);
// 构建管道
status_t status = mPipelineController->buildPipeline(requestedConfiguration);
if (status != OK) {
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
// 准备管道
status = mPipelineController->preparePipeline();
if (status != OK) {
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
_hidl_cb(Status::OK, halConfig);
return Void();
}
// 2. 处理捕获请求流程
Return<Status> processCaptureRequest(const hidl_vec<CaptureRequest>& requests,
uint32_t numRequestProcessed) override {
for (const auto& request : requests) {
// 创建MTK内部请求结构
sp<CaptureRequest> mtkRequest = new CaptureRequest();
// 转换HIDL请求到MTK格式
convertToMtkRequest(request, mtkRequest);
// 设置请求回调
mtkRequest->setListener(mRequestListener);
// 提交到管道处理
status_t status = mPipelineController->processRequest(mtkRequest);
if (status != OK) {
return Status::INTERNAL_ERROR;
}
}
return Status::OK;
}
private:
// 转换到MTK请求格式
void convertToMtkRequest(const CaptureRequest& hidlRequest,
sp<CaptureRequest> mtkRequest) {
// 设置帧号
mtkRequest->setFrameNo(hidlRequest.frameNumber);
// 设置元数据
if (!hidlRequest.settings.empty()) {
IMetadata settings;
// 转换HIDL元数据到MTK元数据格式
convertToMtkMetadata(hidlRequest.settings, &settings);
mtkRequest->setSettings(settings);
}
// 设置输出缓冲区
for (const auto& buffer : hidlRequest.outputBuffers) {
sp<StreamBuffer> mtkBuffer = new StreamBuffer();
convertToMtkStreamBuffer(buffer, mtkBuffer);
mtkRequest->addOutputStreamBuffer(mtkBuffer);
}
}
};
3. 海思(Hisilicon)平台
3.1 海思 Camera 架构
应用层 → 框架层 → 相机服务 → HiSilicon HAL → ISP管道 → 内核驱动
↓
HiAI引擎集成
3.2 海思 HAL 流程
// 海思 Camera HAL 实现
class HiSiliconCameraHAL {
private:
// ISP管道管理
class ISPPipeline {
public:
// ISP配置
struct ISPConfig {
int ispDev; // ISP设备号
int viDev; // VI设备号
int voDev; // VO设备号
ISP_MODULE_E modules; // ISP模块使能
};
// 构建ISP管道
status_t buildPipeline(const StreamConfiguration& config);
};
// 传感器控制
class SensorController {
public:
// 传感器配置
status_t configureSensor(int sensorId, const SensorConfig& config);
// 设置曝光
status_t setExposure(int exposureTime, int analogGain);
// 设置帧率
status_t setFrameRate(int fps);
};
// VI/VPSS管理
class VIVPSSManager {
public:
// VI配置
status_t configureVI(int viDev, const VIConfig& config);
// VPSS配置
status_t configureVPSS(int vpssGrp, const VPSSConfig& config);
};
};
// 海思 HAL 主要流程实现
class HiSiliconHALImpl : public ICameraDeviceSession {
public:
// 1. 初始化流程
Return<Status> initialize() {
// 初始化ISP
HI_S32 ret = HI_MPI_ISP_Init();
if (ret != HI_SUCCESS) {
ALOGE("ISP init failed: 0x%x", ret);
return Status::INTERNAL_ERROR;
}
// 初始化VI
ret = HI_MPI_VI_Init();
if (ret != HI_SUCCESS) {
ALOGE("VI init failed: 0x%x", ret);
return Status::INTERNAL_ERROR;
}
// 初始化VPSS
ret = HI_MPI_VPSS_Init();
if (ret != HI_SUCCESS) {
ALOGE("VPSS init failed: 0x%x", ret);
return Status::INTERNAL_ERROR;
}
return Status::OK;
}
// 2. 配置流流程
Return<void> configureStreams(const StreamConfiguration& requestedConfiguration,
configureStreams_cb _hidl_cb) override {
HalStreamConfiguration halConfig;
// 配置传感器
status_t status = configureSensor(requestedConfiguration);
if (status != OK) {
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
// 配置VI设备
status = configureVIDevice(requestedConfiguration);
if (status != OK) {
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
// 配置VPSS组
status = configureVPSSGroup(requestedConfiguration);
if (status != OK) {
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
// 启动数据流
status = startStreaming();
if (status != OK) {
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
_hidl_cb(Status::OK, halConfig);
return Void();
}
private:
// 配置传感器
status_t configureSensor(const StreamConfiguration& config) {
// 设置传感器模式
HI_MPI_ISP_SetPubAttr(mIspDev, &mIspPubAttr);
HI_MPI_ISP_Init(mIspDev);
// 配置MIPI RX
HI_MPI_ISP_SetMipiRxAttr(mIspDev, &mMipiRxAttr);
// 使能传感器时钟
HI_MPI_ISP_EnableSensor(mIspDev);
return OK;
}
// 配置VI设备
status_t configureVIDevice(const StreamConfiguration& config) {
// 设置VI设备属性
HI_MPI_VI_SetDevAttr(mViDev, &mViDevAttr);
// 设置VI通道属性
HI_MPI_VI_SetChnAttr(mViDev, mViChn, &mViChnAttr);
// 启用VI设备
HI_MPI_VI_EnableDev(mViDev);
HI_MPI_VI_EnableChn(mViDev, mViChn);
return OK;
}
// 配置VPSS组
status_t configureVPSSGroup(const StreamConfiguration& config) {
// 设置VPSS组属性
HI_MPI_VPSS_SetGrpAttr(mVpssGrp, &mVpssGrpAttr);
// 设置VPSS通道属性
for (int i = 0; i < config.streams.size(); i++) {
HI_MPI_VPSS_SetChnAttr(mVpssGrp, i, &mVpssChnAttr[i]);
HI_MPI_VPSS_EnableChn(mVpssGrp, i);
}
// 启用VPSS组
HI_MPI_VPSS_StartGrp(mVpssGrp);
return OK;
}
};
4. 展锐(Unisoc)平台
4.1 展锐 Camera 架构
应用层 → 框架层 → 相机服务 → Sprd HAL → DCAM/ISP → 内核驱动
↓
sprd_camera HAL
4.2 展锐 HAL 流程
// 展锐 Camera HAL 实现
class SprdCameraHAL {
private:
// 相机硬件接口
class SprdCameraHW {
public:
// 相机上下文
struct CameraContext {
cmr_handle cameraHandle; // 相机句柄
cmr_handle ispHandle; // ISP句柄
cmr_handle scaleHandle; // 缩放句柄
SURFACE_TYPE previewSurface; // 预览Surface
};
// 初始化相机
status_t cameraInit(int cameraId);
// 启动预览
status_t startPreview();
// 拍照
status_t takePicture();
};
// ISP控制
class ISPController {
public:
// ISP配置
status_t configureISP(const ISPSettings& settings);
// 3A控制
status_t set3AParams(const AECParams& aec, const AFParams& af, const AWBParams& awb);
};
// 缩放处理器
class ScaleProcessor {
public:
// 缩放配置
status_t configureScale(const ScaleConfig& config);
// 处理图像
status_t processImage(const ImageBuffer& input, ImageBuffer& output);
};
};
// 展锐 HAL3 实现
class SprdCamera3HAL : public ICameraDeviceSession {
public:
// 1. 配置流流程
Return<void> configureStreams(const StreamConfiguration& requestedConfiguration,
configureStreams_cb _hidl_cb) override {
HalStreamConfiguration halConfig;
// 初始化相机硬件
int ret = mCameraHW->cameraInit(mCameraId);
if (ret != 0) {
ALOGE("Camera init failed: %d", ret);
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
// 设置相机模式
ret = mCameraHW->setCameraMode(requestedConfiguration.operationMode);
if (ret != 0) {
ALOGE("Set camera mode failed: %d", ret);
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
// 配置预览
for (const auto& stream : requestedConfiguration.streams) {
if (stream.streamType == CAMERA3_STREAM_OUTPUT) {
ret = configurePreviewStream(stream);
if (ret != 0) {
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
}
}
// 启动通道
ret = mCameraHW->startChannel();
if (ret != 0) {
ALOGE("Start channel failed: %d", ret);
_hidl_cb(Status::INTERNAL_ERROR, halConfig);
return Void();
}
_hidl_cb(Status::OK, halConfig);
return Void();
}
// 2. 处理捕获请求流程
Return<Status> processCaptureRequest(const hidl_vec<CaptureRequest>& requests,
uint32_t numRequestProcessed) override {
for (const auto& request : requests) {
// 转换到展锐内部格式
camera3_capture_request_t sprdRequest;
convertToSprdRequest(request, &sprdRequest);
// 处理捕获请求
int ret = mCameraHW->processCaptureRequest(&sprdRequest);
if (ret != 0) {
ALOGE("Process capture request failed: %d", ret);
return Status::INTERNAL_ERROR;
}
}
return Status::OK;
}
private:
// 配置预览流
status_t configurePreviewStream(const Stream& stream) {
// 设置预览格式
int ret = mCameraHW->setPreviewFormat(stream.format);
if (ret != 0) {
ALOGE("Set preview format failed: %d", ret);
return UNKNOWN_ERROR;
}
// 设置预览尺寸
ret = mCameraHW->setPreviewSize(stream.width, stream.height);
if (ret != 0) {
ALOGE("Set preview size failed: %d", ret);
return UNKNOWN_ERROR;
}
// 分配预览缓冲区
ret = mCameraHW->allocatePreviewBuffers(stream.width, stream.height);
if (ret != 0) {
ALOGE("Allocate preview buffers failed: %d", ret);
return UNKNOWN_ERROR;
}
return OK;
}
// 转换到展锐请求格式
void convertToSprdRequest(const CaptureRequest& hidlRequest,
camera3_capture_request_t* sprdRequest) {
sprdRequest->frame_number = hidlRequest.frameNumber;
// 转换设置
if (!hidlRequest.settings.empty()) {
const camera_metadata_t* metadata =
reinterpret_cast<const camera_metadata_t*>(hidlRequest.settings.data());
sprdRequest->settings = metadata;
}
// 转换输出缓冲区
sprdRequest->num_output_buffers = hidlRequest.outputBuffers.size();
for (size_t i = 0; i < hidlRequest.outputBuffers.size(); i++) {
convertToSprdStreamBuffer(hidlRequest.outputBuffers[i],
&sprdRequest->output_buffers[i]);
}
}
};
5. 各平台流程对比
5.1 架构设计对比
| 高通 | CamX+CHI分层架构 | 灵活可扩展,算法丰富 | 高端旗舰机 |
| 联发科 | Pipeline管道模型 | 流程清晰,易于调试 | 中高端手机 |
| 海思 | ISP集成架构 | 性能优化好,功耗低 | 安防、专业设备 |
| 展锐 | 传统HAL架构 | 代码简洁,资源占用少 | 入门级手机 |
5.2 开发调试建议
高通平台调试
# 启用CamX调试日志
adb shell setprop persist.vendor.camera.logger 7
adb shell setprop persist.vendor.camera.CAMX_DEBUG 1
# 查看CamX管道状态
adb shell dumpsys media.camera -m
联发科平台调试
bash
# 启用MTK相机调试
adb shell setprop debug.camera.log 1
adb shell setprop persist.vendor.mtk.camera.log_level 4
# 查看管道状态
adb shell dumpsys media.camera | grep -i pipeline
通用调试命令
bash
# 检查相机服务状态
adb shell dumpsys media.camera
# 查看相机HAL版本
adb shell getprop | grep camera
# 检查相机权限
adb shell pm list permissions | grep camera
6. 总结
各主流平台的 Camera HAL 都遵循 Android HAL3 标准,但在实现架构和优化策略上有所不同: 高通:采用先进的 CamX-CHI 架构,适合高性能和复杂功能需求 联发科:使用 Pipeline 模型,平衡性能和开发复杂度 海思:专注于 ISP 集成和低功耗优化,适合专业设备 展锐:采用传统实现,资源占用少,适合入门级设备 理解各平台的架构特点和流程差异,有助于在不同场景下选择合适的平台和优化策略。
展锐平台架构组成
展锐平台的 Camera 系统主要包含以下几个核心模块:
- CAMSYS(Camera System Controller):硬件抽象调度模块,管理 Sensor 接入、通道调度、帧率控制等;
- ISP Pipeline(图像信号处理链):完成 RAW 图像数据的黑电平、去噪、DPC、伽马校正等处理;
- V4L2 驱动层:基于 Linux 的 Video4Linux 接口提供统一设备抽象和图像流控制;
- Camera HAL 层(Vendor HAL):对接 Android CameraService,暴露 camera_device_ops 接口;
- 图像共享 Buffer 管理层:通过 ION/DMA-BUF 提供物理地址共享机制,支持 Zero-copy 通路;
- AI 子模块(可选):如双摄融合、对焦控制、虚化建模,在部分平台中集成独立协处理器。
工作流程概览
展锐平台在实际运行时的流程如下: Android 应用请求相机服务(通过 Camera2 API); HAL 层通过 CameraModule 接口调起 CAMERA_DEVICE; 驱动层初始化 CAMSYS 并完成 Sensor 配置; ISP Pipeline 被配置为 YUV 或 RGB 输出; 图像流通过 DMA 写入共享内存,供 Preview、Capture、Video 等路径消费。
HAL 3A问题分析
好的,这是一个在摄影和相机领域非常常见的术语,我用一个通俗易懂的方式为您解释。
一、通俗理解:什么是“拉风箱”?
在现代数码相机和手机相机中,“拉风箱”指的是一种自动对焦(AF)故障现象:当您半按快门尝试对焦时,相机镜头(或手机内部的对焦马达)发出“咻-咻-咻”的声音,反复地、缓慢地在前后的对焦点之间来回移动,但就是无法迅速、准确地对上焦点,画面在模糊与清晰之间来回摇摆。
二、专业解释:为什么会发生“拉风箱”?
要理解原因,我们需要知道自动对焦是如何工作的。主要有两种方式:
对比度检测对焦
- 原理:相机传感器分析画面中物体边缘的明暗对比度。对比度最高时,画面最清晰,即对焦成功。
- 过程:相机需要让镜头马达一点点移动,反复试探,寻找那个“对比度最高”的点。它不知道目标是在前还是在后,只能像走迷宫一样来回找。
相位检测对焦
- 原理:像人眼的双眼定位,通过计算光线到达不同传感器的相位差,直接判断出目标物体是偏前还是偏后,以及偏差多少。
- 过程:理论上可以直接“命令”镜头马达一步到位,对焦速度极快。
“拉风箱”的根本原因在于:
- 在低光照、低对比度的环境下(比如对着纯色的墙壁、在昏暗的房间里、拍摄雾中的景物),对比度检测对焦会失效,因为系统找不到清晰的边缘来判断对比度是否达到最高。
- 即使是有相位检测对焦的系统,在光线极差时,信号太弱,也无法准确计算相位差。
- 此时,相机的对焦系统就会陷入迷茫,不断地向前搜索,找不到焦点,再向后搜索,还是找不到,如此反复,就形成了“拉风箱”。
三、在相机驱动和HAL开发中的视角
对于相机驱动和HAL(硬件抽象层)开发者来说,“拉风箱”是一个需要重点分析和优化的3A(AF/AE/AWB)问题,特别是AF(自动对焦)问题。
从代码和算法层面看,原因可能包括:
AF算法参数不佳:
- 对焦搜索的步长(Step Size)设置不合理。步长太大可能越过焦点,步长太小会导致搜索过慢。
- 对焦超时(Timeout)设置过长,导致系统在一直找不到焦点的情况下仍在无效搜索。
场景评估错误:
- 场景分析(Scene Detection)算法未能正确识别出当前是“低对比度”或“低光照”场景,从而错误地启动了全范围的对比度搜索,而不是切换到更优的策略(如辅助对焦)。
硬件限制或驱动问题:
- 音圈马达(VCM)的精度或响应速度不够。
- 传感器或ISP(图像信号处理器)提供的对焦数据(如相位信息)噪声太大,不可靠。
- 驱动层与HAL层之间的指令传递或状态同步有延迟或错误。
缺乏有效的辅助对焦机制:
- 没有有效触发激光对焦或闪光灯辅助对焦(在暗光下打出一束图案来创造对比度)等备用方案。
四、如何避免和解决“拉风箱”?
对于相机HAL开发者:
- 优化AF搜索算法:实现自适应的搜索步长和智能的搜索策略。
- 增强场景识别:准确识别低光、低对比度场景,并触发相应的辅助对焦流程。
- 传感器融合:结合激光、陀螺仪等传感器数据来辅助光学对焦。
- 调试与调优:
- 使用 adb logcat 过滤AF相关的日志(如 AF_ALGO),观察对焦值(Focus Value)的曲线变化,分析搜索过程。
- 调整VCM的驱动参数和响应曲线。
- 进行大量的场景测试,尤其是在弱光和低对比度环境下的测试。
启用3A调试日志
adb shell setprop vendor.camera.af.debug 1 adb shell setprop vendor.camera.ae.debug 1 adb shell setprop vendor.camera.awb.debug 1
查看3A算法内部状态
adb logcat | grep -E “(AF_ALGO|AE_ALGO|AWB_ALGO)”
平台特定调试命令
# 高通
adb shell setprop persist.vendor.camera.af.logs 1
# MTK
adb shell setprop debug.camera.log 1
# 海思
adb shell setprop hw.camera.debug 1
掌握Camera HAL开发与问题分析的完整学习路径
1. 学习路径规划
1.1 基础阶段(1-3个月)
第一阶段:理论基础
├── Android Camera架构
├── HAL3接口规范
├── 图像传感器原理
├── 光学基础知识
└── 3A算法基础
第二阶段:代码实践
├── AOSP Camera源码阅读
├── 平台HAL代码分析
├── 简单HAL模块开发
└── 基础调试技能
1.2 进阶阶段(3-6个月)
第三阶段:深入理解
├── 3A算法实现原理
├── 性能优化技巧
├── 稳定性问题分析
└── XTS测试框架
第四阶段:实战经验
├── 实际问题调试
├── 平台特性掌握
├── 问题定位方法论
└── 解决方案设计
2. HAL层开发学习
2.1 源码学习路线
# 1. 从AOSP基础开始
frameworks/av/services/camera/libcameraservice/
hardware/interfaces/camera/
# 2. 学习平台参考实现
# 高通:vendor/qcom/opensource/camera/
# MTK:vendor/mediatek/proprietary/hardware/mtkcam/
# 海思:vendor/hisi/
# 3. 重点文件
– ICameraProvider.hal
– ICameraDevice.hal
– ICameraDeviceSession.hal
– types.hal
2.2 实践开发环境搭建
# 搭建调试环境
# 1. 获取AOSP源码
repo init -u https://android.googlesource.com/platform/manifest -b android-13.0.0_r1
repo sync
# 2. 编译相机模块
source build/envsetup.sh
lunch aosp_x86_64-eng # 根据实际情况选择
mmm frameworks/av/services/camera/libcameraservice/
mmm hardware/interfaces/camera/
# 3. 启用调试日志
adb shell setprop persist.camera.hal.debug 1
adb shell setprop persist.camera.logger 1
2.3 HAL开发练习项目
// 实现一个简单的虚拟相机HAL
class VirtualCameraHAL : public ICameraProvider {
public:
// 1. 实现相机枚举
Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override {
std::vector<std::string> cameraIds = {"0"};
_hidl_cb(Status::OK, cameraIds);
return Void();
}
// 2. 实现相机特性查询
Return<void> getCameraCharacteristics(const hidl_string& cameraId,
getCameraCharacteristics_cb _hidl_cb) override {
CameraMetadata characteristics;
// 填充基础相机特性
setupBasicCameraCharacteristics(&characteristics);
_hidl_cb(Status::OK, characteristics);
return Void();
}
// 3. 实现会话创建
Return<void> openSession(const hidl_string& cameraId,
const sp<ICameraDeviceCallback>& callback,
openSession_cb _hidl_cb) override {
sp<VirtualCameraSession> session = new VirtualCameraSession(callback);
_hidl_cb(Status::OK, session);
return Void();
}
};
3. 3A问题分析与处理
3.1 3A算法基础理解
3.1.1 AE(自动曝光)核心原理
// AE算法状态机
class AEStateMachine {
public:
enum AEState {
AE_INACTIVE, // 非活跃状态
AE_SEARCHING, // 搜索最佳曝光
AE_CONVERGED, // 曝光收敛
AE_LOCKED, // 曝光锁定
AE_FLASH_REQUIRED // 需要闪光灯
};
// AE评估函数
float calculateBrightness(const ImageStatistics& stats) {
// 计算图像亮度(加权平均或直方图分析)
float brightness = 0;
for (int i = 0; i < stats.regionCount; i++) {
brightness += stats.regions[i].weight * stats.regions[i].averageLuma;
}
return brightness;
}
// AE控制逻辑
void updateExposure(const AEInput& input, AEOutput* output) {
float currentBrightness = calculateBrightness(input.stats);
float error = mTargetBrightness – currentBrightness;
if (abs(error) > mConvergenceThreshold) {
// 需要调整曝光
adjustExposureParameters(error, input, output);
mState = AE_SEARCHING;
} else {
mState = AE_CONVERGED;
}
// 应用防闪烁
applyFlickerAvoidance(input, output);
}
};
3.1.2 AF(自动对焦)问题分析
// AF问题诊断工具
class AFDiagnostic {
public:
struct AFProblem {
enum Type {
FOCUS_HUNTING, // 反复拉风箱
CANNOT_FOCUS, // 无法对焦
WRONG_FOCUS_POSITION, // 对焦位置错误
SLOW_FOCUS // 对焦速度慢
};
Type type;
std::string description;
std::vector<float> focusValues;
};
// 分析AF问题
AFProblem analyzeAFIssue(const std::vector<AFFrameData>& frameHistory) {
AFProblem problem;
// 检查是否反复拉风箱
if (isFocusHunting(frameHistory)) {
problem.type = AFProblem::FOCUS_HUNTING;
problem.description = "AF system repeatedly searching without convergence";
return problem;
}
// 检查对比度曲线
if (hasPoorContrastCurve(frameHistory)) {
problem.type = AFProblem::CANNOT_FOCUS;
problem.description = "Insufficient contrast for reliable AF";
return problem;
}
return problem;
}
private:
bool isFocusHunting(const std::vector<AFFrameData>& history) {
if (history.size() < 10) return false;
// 检查镜头位置是否在来回移动
int directionChanges = 0;
for (size_t i = 1; i < history.size() – 1; i++) {
int prevDir = sign(history[i].lensPosition – history[i–1].lensPosition);
int currDir = sign(history[i+1].lensPosition – history[i].lensPosition);
if (prevDir != 0 && currDir != 0 && prevDir != currDir) {
directionChanges++;
}
}
return directionChanges > history.size() / 3;
}
};
3.2 3A问题调试方法
3.2.1 实时3A状态监控
# 启用3A调试日志
adb shell setprop vendor.camera.af.debug 1
adb shell setprop vendor.camera.ae.debug 1
adb shell setprop vendor.camera.awb.debug 1
# 查看3A算法内部状态
adb logcat | grep -E "(AF_ALGO|AE_ALGO|AWB_ALGO)"
# 平台特定调试命令
# 高通
adb shell setprop persist.vendor.camera.af.logs 1
# MTK
adb shell setprop debug.camera.log 1
# 海思
adb shell setprop hw.camera.debug 1
3.2.2 3A参数调优实践
// AE参数调优示例
class AETuning {
public:
struct TuningParams {
float targetLuma; // 目标亮度
float tolerance; // 容差范围
float compensationSpeed; // 补偿速度
int minExposureTime; // 最小曝光时间
int maxExposureTime; // 最大曝光时间
float minAnalogGain; // 最小模拟增益
float maxAnalogGain; // 最大模拟增益
};
// 基于场景的AE参数调整
TuningParams getSceneSpecificParams(AESceneType scene) {
TuningParams params;
switch (scene) {
case SCENE_BACKLIGHT:
params.targetLuma = 0.6f; // 提高目标亮度补偿背光
params.compensationSpeed = 0.8f; // 较慢的补偿速度避免闪烁
break;
case SCENE_LOW_LIGHT:
params.targetLuma = 0.4f; // 降低目标亮度保持氛围
params.compensationSpeed = 0.5f; // 慢速补偿减少噪声
break;
case SCENE_SPORTS:
params.targetLuma = 0.7f;
params.compensationSpeed = 1.2f; // 快速响应运动场景
params.minExposureTime = 1000; // 限制曝光时间避免运动模糊
break;
default:
params.targetLuma = 0.5f;
params.compensationSpeed = 1.0f;
}
return params;
}
};
4. 稳定性问题分析
4.1 常见稳定性问题分类
// 稳定性问题类型定义
enum StabilityIssue {
CAMERA_CRASH, // 相机崩溃
PREVIEW_FREEZE, // 预览冻结
MEMORY_LEAK, // 内存泄漏
PERFORMANCE_DEGRADATION, // 性能下降
THERMAL_THROTTLING, // 热节流
RESOURCE_CONTENTION // 资源竞争
};
4.2 稳定性问题分析方法论
4.2.1 系统化问题定位
# 1. 收集崩溃日志
adb logcat -b crash
adb bugreport
# 2. 分析内存使用
adb shell dumpsys meminfo camera
adb shell cat /proc/meminfo
# 3. 检查CPU使用率
adb shell top -n 1 | grep camera
# 4. 监控温度
adb shell cat /sys/class/thermal/thermal_zone*/temp
4.2.2 稳定性测试框架
#!/usr/bin/env python3
# 相机稳定性测试脚本
import subprocess
import time
import logging
class CameraStabilityTest:
def __init__(self):
self.test_count = 0
self.failure_count = 0
self.logger = self.setup_logger()
def run_stress_test(self, duration_hours=24):
"""运行长时间压力测试"""
start_time = time.time()
test_cases = [
self.test_preview_stability,
self.test_capture_stability,
self.test_switch_camera,
self.test_video_recording
]
while time.time() – start_time < duration_hours * 3600:
for test_case in test_cases:
try:
test_case()
self.test_count += 1
except Exception as e:
self.failure_count += 1
self.logger.error(f"Test failed: {e}")
# 每小时输出状态报告
if self.test_count % 60 == 0:
self.report_status()
def test_preview_stability(self):
"""预览稳定性测试"""
# 启动相机预览
subprocess.run(["adb", "shell", "am", "start", "-n",
"com.android.camera2/com.android.camera.CameraActivity"])
time.sleep(2)
# 检查预览是否正常
result = subprocess.run(["adb", "shell", "dumpsys", "media.camera"],
capture_output=True, text=True)
if "PREVIEW_STREAMING" not in result.stdout:
raise Exception("Preview not streaming")
def report_status(self):
"""报告测试状态"""
success_rate = (self.test_count – self.failure_count) / self.test_count * 100
self.logger.info(f"Tests: {self.test_count}, Failures: {self.failure_count}, "
f"Success Rate: {success_rate:.2f}%")
4.3 内存问题分析技巧
// 内存泄漏检测工具
class MemoryLeakDetector {
public:
static void trackAllocation(void* ptr, size_t size, const char* tag) {
std::lock_guard<std::mutex> lock(sMutex);
sAllocations[ptr] = {size, tag, std::chrono::steady_clock::now()};
sTotalAllocated += size;
}
static void trackDeallocation(void* ptr) {
std::lock_guard<std::mutex> lock(sMutex);
auto it = sAllocations.find(ptr);
if (it != sAllocations.end()) {
sTotalAllocated -= it->second.size;
sAllocations.erase(it);
}
}
static void dumpLeaks() {
std::lock_guard<std::mutex> lock(sMutex);
ALOGI("=== Memory Leak Report ===");
ALOGI("Total allocated: %zu bytes", sTotalAllocated);
ALOGI("Leaked allocations: %zu", sAllocations.size());
for (const auto& [ptr, info] : sAllocations) {
ALOGI("Leak: %p, size: %zu, tag: %s", ptr, info.size, info.tag);
}
}
private:
static std::mutex sMutex;
static std::unordered_map<void*, AllocationInfo> sAllocations;
static size_t sTotalAllocated;
};
5. XTS问题分析能力
5.1 XTS测试框架理解
5.1.1 CTS测试结构
# CTS测试目录结构
cts/tests/camera/src/
├── android/hardware/camera2/cts/
│ ├── CameraTest.java
│ ├── CaptureResultTest.java
│ └── ImageReaderTest.java
├── testng/ # 测试配置
└── resources/ # 测试资源
5.1.2 VTS测试重点
# VTS测试示例 – camera HAL测试
class CameraHidlTest(unittest.TestCase):
def setUp(self):
# 初始化相机Provider
self.camera_provider = self.getCameraProvider()
def testCameraOpenClose(self):
"""测试相机打开关闭稳定性"""
for camera_id in self.camera_provider.getCameraIdList():
with self.subTest(camera_id=camera_id):
# 重复打开关闭测试
for i in range(100):
device = self.camera_provider.openCamera(camera_id)
self.assertIsNotNone(device)
device.close()
def testMandatoryStreamConfigs(self):
"""测试必需的流配置"""
for camera_id in self.camera_provider.getCameraIdList():
with self.subTest(camera_id=camera_id):
characteristics = self.camera_provider.getCameraCharacteristics(camera_id)
# 验证必需的输出格式
self.assertIn(android.hardware.PixelFormat.YCBCR_420_888,
characteristics[SCALER_AVAILABLE_FORMATS])
self.assertIn(android.hardware.PixelFormat.BLOB,
characteristics[SCALER_AVAILABLE_FORMATS])
5.2 XTS问题分析方法
5.2.1 测试失败诊断流程
// XTS失败分析工具类
class XTSFailureAnalyzer {
public:
struct TestFailure {
std::string testName;
std::string failureType;
std::string logSnippet;
std::vector<std::string> possibleCauses;
std::vector<std::string> suggestedFixes;
};
TestFailure analyzeFailure(const std::string& logFile, const std::string& testName) {
TestFailure failure;
failure.testName = testName;
// 解析日志文件
std::ifstream log(logFile);
std::string line;
std::vector<std::string> errorLines;
while (std::getline(log, line)) {
if (line.find("FAIL") != std::string::npos ||
line.find("ERROR") != std::string::npos) {
errorLines.push_back(line);
}
}
// 根据错误模式分类
if (contains(errorLines, "TimeoutException")) {
failure.failureType = "TIMEOUT";
failure.possibleCauses = {
"HAL响应过慢",
"资源竞争导致死锁",
"内存压力导致性能下降"
};
failure.suggestedFixes = {
"检查HAL处理请求的耗时",
"分析是否有资源竞争",
"优化内存使用"
};
} else if (contains(errorLines, "AssertionError")) {
failure.failureType = "ASSERTION_FAILED";
// 进一步分析具体的断言失败
analyzeAssertionFailure(errorLines, &failure);
}
return failure;
}
};
5.2.2 常见XTS问题及解决方案
# 1. CTS测试失败:testMandatoryConcurrentStreams
# 问题:不支持并发流
# 解决方案:在HAL中正确实现多流支持
# 2. VTS测试失败:testInvalidPhysicalCameraId
# 问题:物理相机ID处理错误
# 解决方案:正确实现逻辑相机到物理相机的映射
# 3. CTS测试失败:testJpegExifData
# 问题:EXIF数据不完整或错误
# 解决方案:确保在JPEG中写入正确的EXIF元数据
5.3 自定义测试开发
#!/usr/bin/env python3
# 自定义相机功能测试
import unittest
import subprocess
import time
class CustomCameraTests(unittest.TestCase):
def test_3a_convergence_speed(self):
"""测试3A收敛速度"""
start_time = time.time()
# 触发AF
self.trigger_auto_focus()
# 等待AF收敛
convergence_time = self.wait_for_af_convergence()
# 验证收敛时间在合理范围内
self.assertLess(convergence_time, 1.0,
f"AF convergence too slow: {convergence_time}s")
def test_preview_smoothness(self):
"""测试预览流畅度"""
frame_times = []
# 收集100帧的时间间隔
for i in range(100):
frame_start = time.time()
self.capture_preview_frame()
frame_end = time.time()
frame_times.append(frame_end – frame_start)
# 计算帧率稳定性
avg_frame_time = sum(frame_times) / len(frame_times)
frame_rate = 1.0 / avg_frame_time
self.assertGreater(frame_rate, 25,
f"Preview frame rate too low: {frame_rate}fps")
def test_memory_usage_stability(self):
"""测试内存使用稳定性"""
initial_memory = self.get_camera_memory_usage()
# 执行一系列相机操作
for i in range(50):
self.test_preview_capture_cycle()
final_memory = self.get_camera_memory_usage()
memory_increase = final_memory – initial_memory
# 验证内存增长在合理范围内
self.assertLess(memory_increase, 50 * 1024 * 1024, # 50MB
f"Excessive memory growth: {memory_increase} bytes")
6. 实战问题解决流程
6.1 系统化问题解决框架
// 问题解决模板
class ProblemSolver {
public:
struct ProblemSolution {
std::string problemDescription;
std::string rootCause;
std::vector<std::string> investigationSteps;
std::string solution;
std::string preventionMeasures;
};
ProblemSolution solveCameraIssue(const std::string& issueDescription) {
ProblemSolution solution;
solution.problemDescription = issueDescription;
// 步骤1:问题重现和日志收集
solution.investigationSteps.push_back("重现问题并收集完整日志");
// 步骤2:日志分析
solution.investigationSteps.push_back("分析日志中的错误模式和时间线");
// 步骤3:根本原因分析
solution.rootCause = analyzeRootCause(issueDescription);
// 步骤4:解决方案实施
solution.solution = developSolution(solution.rootCause);
// 步骤5:预防措施
solution.preventionMeasures = developPreventionMeasures();
return solution;
}
private:
std::string analyzeRootCause(const std::string& issue) {
if (issue.find("preview freeze") != std::string::npos) {
return "缓冲区管理问题或管道阻塞";
} else if (issue.find("cannot focus") != std::string::npos) {
return "AF算法参数不当或硬件限制";
} else if (issue.find("out of memory") != std::string::npos) {
return "内存泄漏或缓冲区未及时释放";
}
return "需要进一步分析";
}
};
6.2 建立个人知识库
# 相机问题知识库
## 常见问题分类
### 3A问题
– [AF拉风箱问题分析和解决]
– [AE在背光场景下过曝问题]
– [AWB在室内偏色问题]
### 性能问题
– [预览延迟优化方案]
– [拍照速度提升方法]
– [内存使用优化]
### 稳定性问题
– [相机服务崩溃分析]
– [预览冻结问题定位]
– [热相关问题解决]
## 调试技巧
### 日志分析
– 关键日志标签和含义
– 性能问题日志模式
– 崩溃堆栈解析方法
### 工具使用
– systrace使用指南
– perfetto性能分析
– 内存分析工具
7. 持续学习资源
7.1 官方文档
- Android Camera架构文档
- HIDL接口规范
- CTS/VTS测试指南
7.2 社区资源
- AOSP Issue Tracker
- Stack Overflow Camera标签
- 各平台开发者论坛
7.3 实践项目
通过系统化的学习和持续的实践,结合实际问题解决经验的积累,你将逐步掌握Camera HAL开发的各项技能,并能够有效分析和解决各种复杂问题。
报错日志排查
1. 日志分析 – 首要步骤
启用详细日志
// 在 HAL 代码中添加详细日志
#include <log/log.h>
// 使用不同级别的日志
ALOGV("Verbose: Entering function %s", __FUNCTION__); // 详细日志
ALOGD("Debug: Sensor configured with exposure %d", exposure); // 调试日志
ALOGI("Info: Camera HAL initialized successfully"); // 信息日志
ALOGW("Warning: Unexpected sensor response"); // 警告日志
ALOGE("Error: Failed to open device: %s", strerror(errno)); // 错误日志
// 条件日志
if (error_condition) {
ALOGE("Error in %s at line %d: condition failed", __FILE__, __LINE__);
}
配置日志级别
# 查看 Camera 相关日志
adb logcat | grep -iE "(camera|CAMERA|CameraHal)"
# 查看特定 tag 的日志
adb logcat -s CameraHal:V CameraService:V *:S
# 查看所有相机相关服务的日志
adb logcat | grep -E "(camera|CAMERA|CameraProvider|CameraService|CameraDevice)"
# 查看内核日志中的相机相关消息
adb shell dmesg | grep -i camera
# 查看相机服务崩溃重启
adb logcat | grep -i "cameraserver"
2. 常见错误分类及排查方法
2.1 初始化阶段错误
症状:相机无法打开,返回 STATUS_ENUMERATING 或设备未找到错误。
# 检查相机设备枚举
adb shell dumpsys media.camera
# 检查相机服务状态
adb shell dumpsys media.camera -v
# 检查相机 Provider
adb shell lshal | grep -i camera
排查步骤:
2.2 流配置错误
症状:configure_streams() 失败,无法设置分辨率或格式。
// 在 configure_streams 中添加详细日志
static int configure_streams(const camera3_device* device,
camera3_stream_configuration_t* stream_list) {
ALOGI("Configuring %d streams", stream_list->num_streams);
for (uint32_t i = 0; i < stream_list->num_streams; i++) {
camera3_stream_t* stream = stream_list->streams[i];
ALOGI("Stream[%d]: format: %d, width: %d, height: %d, usage: %llu, max_buffers: %d",
i, stream->format, stream->width, stream->height,
stream->usage, stream->max_buffers);
}
// 验证流配置是否支持
if (!is_stream_configuration_supported(stream_list)) {
ALOGE("Stream configuration not supported");
return –EINVAL;
}
return 0;
}
2.3 捕获请求处理错误
症状:拍照或预览失败,process_capture_request() 返回错误。
// 在 process_capture_request 中添加调试信息
static int process_capture_request(const camera3_device* device,
camera3_capture_request_t* request) {
ALOGD("Processing request frame_number: %d, num_output_buffers: %d",
request->frame_number, request->num_output_buffers);
// 检查设置是否有效
if (request->settings) {
dump_camera_metadata(request->settings, "Request Settings");
}
// 检查输出缓冲区
for (uint32_t i = 0; i < request->num_output_buffers; i++) {
const camera3_stream_buffer_t* buffer = &request->output_buffers[i];
ALOGD("Buffer[%d]: stream: %p, status: %d",
i, buffer->stream, buffer->status);
}
return process_request_implementation(device, request);
}
3. 硬件层排查
3.1 I2C 通信排查
# 检查 I2C 设备是否存在
adb shell ls -la /dev/i2c-*
# 扫描 I2C 总线上的设备
adb shell i2cdetect -y 1 # 对于 i2c-1 总线
# 读取传感器 ID 验证通信
adb shell i2cget -y 1 0x3c 0x3000 w # 示例命令
# 检查 I2C 通信错误
adb shell dmesg | grep -i i2c
3.2 V4L2 设备排查
# 检查 V4L2 设备
adb shell ls -la /dev/video*
# 查询 V4L2 设备能力
adb shell v4l2-ctl -d /dev/video0 –info
# 查看支持的格式
adb shell v4l2-ctl -d /dev/video0 –list-formats-ext
# 测试设备打开
adb shell v4l2-ctl -d /dev/video0 –all
3.3 电源和时钟排查
# 检查相机相关的电源和时钟
adb shell cat /sys/kernel/debug/camera/clock/stats
adb shell cat /sys/kernel/debug/camera/power/stats
# 检查 GPIO 状态
adb shell cat /sys/kernel/debug/gpio
# 检查 regulator 状态
adb shell cat /sys/kernel/debug/regulator/regulator_summary
4. 系统级工具排查
4.1 使用 strace 跟踪系统调用
# 跟踪相机服务系统调用
adb shell strace -p $(pidof cameraserver) -f -o /data/local/tmp/camera_trace.txt
# 跟踪特定进程
adb shell strace -p $(pidof com.android.camera2) -f
4.2 使用 GDB 调试
// 在代码中添加调试点
#include <csignal>
void debug_breakpoint() {
ALOGI("Reached debug breakpoint in %s", __FUNCTION__);
// 可以在这里触发信号用于 GDB 附加
// raise(SIGSTOP);
}
# 使用 GDB 附加到相机服务
adb shell gdbserver :5039 –attach $(pidof cameraserver)
adb forward tcp:5039 tcp:5039
4.3 内存和性能分析
# 检查内存泄漏
adb shell dumpsys meminfo cameraserver
# 检查 CPU 使用率
adb shell top -p $(pidof cameraserver)
# 性能分析
adb shell perfetto -t 10s -o /data/misc/perfetto-traces/trace.pftrace
5. Camera HAL 专用调试工具
5.1 创建调试工具类
class CameraDebugger {
private:
bool mDebugEnabled;
std::ofstream mDebugLog;
public:
CameraDebugger() : mDebugEnabled(false) {
// 检查调试开关
char value[PROPERTY_VALUE_MAX];
property_get("camera.hal.debug", value, "0");
mDebugEnabled = (strcmp(value, "1") == 0);
if (mDebugEnabled) {
mDebugLog.open("/data/vendor/camera/hal_debug.log",
std::ios::out | std::ios::app);
mDebugLog << "=== Camera HAL Debug Session Started ===" << std::endl;
}
}
~CameraDebugger() {
if (mDebugLog.is_open()) {
mDebugLog.close();
}
}
void log(const char* format, ...) {
if (!mDebugEnabled) return;
va_list args;
va_start(args, format);
char buffer[1024];
vsnprintf(buffer, sizeof(buffer), format, args);
mDebugLog << get_current_timestamp() << " – " << buffer << std::endl;
va_end(args);
}
void dump_metadata(const camera_metadata_t* metadata, const char* tag) {
if (!mDebugEnabled || !metadata) return;
mDebugLog << "=== " << tag << " ===" << std::endl;
// 实现 metadata 转储逻辑
// …
}
static CameraDebugger& getInstance() {
static CameraDebugger instance;
return instance;
}
};
// 在代码中使用
#define CAMERA_DEBUG(fmt, ...) \\
CameraDebugger::getInstance().log(fmt, ##__VA_ARGS__)
5.2 错误码映射和解释
const char* camera_error_to_string(int error_code) {
switch (error_code) {
case –ENODEV: return "Camera device not found";
case –EINVAL: return "Invalid parameters";
case –ENOSYS: return "Operation not supported";
case –EBUSY: return "Device or resource busy";
case –EIO: return "I/O error";
case –ENOMEM: return "Out of memory";
case –ETIMEDOUT: return "Operation timed out";
case –EACCES: return "Permission denied";
default: return "Unknown error";
}
}
// 在错误处理中使用
if (result < 0) {
ALOGE("Operation failed with error %d: %s",
result, camera_error_to_string(result));
}
6. 系统属性调试
6.1 使用属性控制调试行为
# 启用详细日志
adb shell setprop camera.hal.log.level 2
# 启用调试模式
adb shell setprop camera.hal.debug 1
# 启用性能分析
adb shell setprop camera.hal.profile 1
# 强制特定分辨率
adb shell setprop camera.hal.force.resolution 1920×1080
6.2 在代码中读取属性
bool is_debug_enabled() {
char value[PROPERTY_VALUE_MAX];
property_get("camera.hal.debug", value, "0");
return (strcmp(value, "1") == 0);
}
int get_log_level() {
char value[PROPERTY_VALUE_MAX];
property_get("camera.hal.log.level", value, "1");
return atoi(value);
}
7. 常见错误模式及解决方案
7.1 权限问题
# 检查 SELinux 权限
adb shell dmesg | grep avc
# 检查文件权限
adb shell ls -la /dev/video*
adb shell ls -la /dev/i2c-*
7.2 资源竞争
// 添加资源锁调试
class DebugMutex {
private:
std::mutex mMutex;
const char* mName;
public:
DebugMutex(const char* name) : mName(name) {}
void lock() {
ALOGD("Waiting for lock: %s", mName);
mMutex.lock();
ALOGD("Acquired lock: %s", mName);
}
void unlock() {
mMutex.unlock();
ALOGD("Released lock: %s", mName);
}
};
7.3 时序问题
// 添加时序调试
class TimingDebug {
private:
std::chrono::steady_clock::time_point mStartTime;
const char* mOperation;
public:
TimingDebug(const char* operation) : mOperation(operation) {
mStartTime = std::chrono::steady_clock::now();
}
~TimingDebug() {
auto endTime = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
endTime – mStartTime);
ALOGD("Operation %s took %lld ms", mOperation, duration.count());
}
};
// 使用
void some_operation() {
TimingDebug timer("some_operation");
// … 操作代码
}
8. 自动化测试和验证
8.1 创建测试套件
class CameraHalTestSuite {
public:
static bool test_device_discovery() {
// 测试设备发现
// 返回 true 如果测试通过
}
static bool test_stream_configuration() {
// 测试流配置
}
static bool test_capture_requests() {
// 测试捕获请求
}
static void run_all_tests() {
ALOGI("Running Camera HAL tests…");
if (!test_device_discovery()) {
ALOGE("Device discovery test failed");
}
if (!test_stream_configuration()) {
ALOGE("Stream configuration test failed");
}
if (!test_capture_requests()) {
ALOGE("Capture requests test failed");
}
ALOGI("Camera HAL tests completed");
}
};
总结
Camera HAL 错误排查的系统化方法:
关键排查命令总结:
# 基础排查
adb logcat | grep -i camera
adb shell dumpsys media.camera
adb shell dmesg | grep -i camera
# 硬件排查
adb shell i2cdetect -y 1
adb shell v4l2-ctl –all
# 权限排查
adb shell dmesg | grep avc
通过系统性的排查方法,可以快速定位和解决 Camera HAL 中的各种问题。
在 Android Camera HAL(特别是 Camera HAL v3)和 Camera2 API 的上下文中,fmt 字段表示 图像像素格式(Pixel Format),其数值对应于 android.hardware.ImageFormat 或底层 HAL 定义的格式常量。
这些格式决定了图像数据在内存中的排列方式(如 YUV、RGB、JPEG 等),直接影响图像处理、编码和显示。
✅ 常见 fmt 值及其含义(按使用频率排序)
| 35 | 0x23 | HAL_PIXEL_FORMAT_YCbCr_420_888 | 通用 YUV 格式,支持硬件加速,Camera2 默认推荐格式 | ✅ 极常用 |
| 33 | 0x21 | ImageFormat.YUV_420_888 | 与 35 相同(部分厂商映射为 33) | ✅ 常见(尤其日志中) |
| 256 | 0x100 | ImageFormat.JPEG | 压缩 JPEG 图像,用于拍照输出 | ✅ 常用 |
| 17 | 0x11 | ImageFormat.NV21 | YUV 4:2:0,Android 默认摄像头预览格式(旧 API) | ⚠️ 旧版常用 |
| 842094169 | 0x32315659 | HAL_PIXEL_FORMAT_YV12 | YV12(YUV 4:2:0 planar) | ❌ 已废弃 |
| 1 | 0x1 | HAL_PIXEL_FORMAT_RGBA_8888 | 32-bit RGBA,用于 GPU 渲染 | ✅ UI/合成常用 |
| 2 | 0x2 | HAL_PIXEL_FORMAT_RGBX_8888 | RGB + padding | 较少 |
| 3 | 0x3 | HAL_PIXEL_FORMAT_RGB_888 | 24-bit RGB | 少见 |
| 4 | 0x4 | HAL_PIXEL_FORMAT_RGB_565 | 16-bit RGB,节省内存 | 嵌入式设备 |
| 0x102 | 258 | ImageFormat.DEPTH16 | 16-bit 深度图(ToF/结构光) | 📷 特定传感器 |
| 0x103 | 259 | ImageFormat.DEPTH_POINT_CLOUD | 点云深度数据 | 📷 AR/3D |
| 0x104 | 260 | ImageFormat.RAW_SENSOR | 原始 Bayer 数据(.dng) | 📷 专业摄影 |
| 0x105 | 261 | ImageFormat.RAW_PRIVATE | 私有 RAW 格式 | 📷 OEM 专用 |
| 0x106 | 262 | ImageFormat.YUV_422_888 | YUV 4:2:2,高质量视频 | 视频采集 |
| 0x107 | 263 | ImageFormat.YUV_444_888 | YUV 4:4:4,无压缩高保真 | 专业视频 |
🔍 注意:
- fmt=33 和 fmt=35 在实际中常混用,因为不同厂商 HAL 实现可能将 YUV_420_888 映射到不同值。
- Camera2 API 中,应用通过 ImageFormat.XXX 请求格式,但 HAL 日志可能打印底层 HAL 值。
📚 详细说明几个关键格式
1. YUV_420_888(fmt=33/35)
- 特点:
- 不是具体内存布局,而是一个“灵活”格式(flexible format)
- 实际可能是 NV21、NV12、YV12 中的一种,由 Image.getPlanes() 返回各分量指针
- 用途:Camera2 预览、录像、处理流的首选格式
- 优势:兼容所有设备,支持硬件加速(如 MediaCodec)
// Java 层获取 YUV 数据
Image image = reader.acquireLatestImage();
Plane[] planes = image.getPlanes(); // Y, U, V 分量
2. JPEG(fmt=256)
- 特点:
- 压缩图像,单平面
- 通常用于 CAPTURE 请求的输出
- 注意:不能用于预览或实时处理(需解码)
3. NV21(fmt=17)
- 内存布局:YYYY…VUVU…(V 在前)
- 历史:Android 早期 Camera1 API 的默认预览格式
- 现状:Camera2 仍支持,但推荐用 YUV_420_888
4. RAW_SENSOR(fmt=260)
- 内容:Bayer mosaic 原始数据(RGGB / BGGR 等)
- 用途:专业摄影、自定义 ISP 处理
- 要求:设备必须支持 REQUEST_AVAILABLE_CAPABILITIES_RAW
5. DEPTH16(fmt=258)
- 内容:每个像素 16-bit 深度值(单位:毫米)
- 来源:ToF 传感器、双摄视差、结构光
- 用途:人像模式、AR 测距
🔧 如何查看设备支持的格式?
方法 1:通过 Camera2 API(Java/Kotlin)
CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = chars.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
int[] formats = map.getOutputFormats(); // 返回支持的 fmt 列表
方法 2:通过 dumpsys media.camera
adb shell dumpsys media.camera
搜索 availableStreamConfigurations,会列出所有 (format, width, height, input?) 组合。
示例输出:
[35, 1920, 1080, 0] → YUV_420_888, 1920×1080, output
[256, 4032, 3024, 0] → JPEG, 4032×3024, output
⚠️ 注意事项
并非所有格式都可用于所有用途
- JPEG 只能用于 CAPTURE,不能用于 PREVIEW
- RAW_SENSOR 需要特定硬件支持
厂商可能自定义私有格式
- 如 0x1000~0xFFFF 范围常被 Qualcomm、MTK 用于私有 YUV 或压缩格式
- 这些格式通常只在 HAL 内部使用,应用层不可见
fmt 值在不同 Android 版本可能变化
- 建议以 ImageFormat.java 和 graphics.h 为准
📄 附:关键头文件定义位置
-
AOSP 源码路径:
- frameworks/base/core/java/android/hardware/ImageFormat.java
- system/core/include/system/graphics.h
- hardware/interfaces/graphics/common/1.0/types.hal
-
常用宏定义(graphics.h):
#define HAL_PIXEL_FORMAT_RGBA_8888 1
#define HAL_PIXEL_FORMAT_RGBX_8888 2
#define HAL_PIXEL_FORMAT_RGB_888 3
#define HAL_PIXEL_FORMAT_RGB_565 4
#define HAL_PIXEL_FORMAT_BGRA_8888 5
#define HAL_PIXEL_FORMAT_YV12 0x32315659 // FOURCC
#define HAL_PIXEL_FORMAT_YCbCr_420_888 0x23
✅ 总结
| 预览/录像/处理 | YUV_420_888 | 33 或 35 |
| 拍照输出 | JPEG | 256 |
| 深度感知 | DEPTH16 | 258 |
| 专业摄影 | RAW_SENSOR | 260 |
| GPU 渲染 | RGBA_8888 | 1 |
如果你有具体的 fmt 值(比如日志中看到 fmt=260),我可以帮你精确解读!






