欢迎光临
我们一直在努力

camera开发入门

光学基本概念

  • 焦距:镜头中心到成像平面的距离,在驱动中通过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历程

特性传统HALHIDL HALAIDL 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[i1].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 实践项目

  • 自定义HAL实现:基于虚拟相机开发完整的HAL实现
  • 算法优化:实现自定义的3A算法或图像处理管线
  • 性能分析工具:开发相机专用的性能监控工具
  • 自动化测试:构建完整的相机自动化测试框架
  • 通过系统化的学习和持续的实践,结合实际问题解决经验的积累,你将逐步掌握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

    排查步骤:

  • 检查 HAL 模块是否被正确加载
  • 验证 get_number_of_cameras() 和 get_camera_info() 实现
  • 检查设备树配置是否正确
  • 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 值及其含义(按使用频率排序)

    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


    ✅ 总结

    场景推荐格式fmt 值
    预览/录像/处理 YUV_420_888 33 或 35
    拍照输出 JPEG 256
    深度感知 DEPTH16 258
    专业摄影 RAW_SENSOR 260
    GPU 渲染 RGBA_8888 1

    如果你有具体的 fmt 值(比如日志中看到 fmt=260),我可以帮你精确解读!

    赞(0)
    未经允许不得转载:171主机测评 » camera开发入门
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址