3. UsecaseId 枚举
定义在 chi-cdk/core/chiusecase/chxdefs.h:
enumclassUsecaseId : uint32_t {
Default =0, // → AdvancedCameraUsecase(大部分单摄场景)
PreviewZSL =1, // ZSL 预览
VideoLiveShot =2, // 录像时拍照
SAT =3, // Smooth Zoom / MultiCamera
RTB =4, // Realtime Bokeh
QCFA =5, // Quad CFA (48M/64M binning 模式)
HighSpeed =6, // 高帧率录像 (120fps+)
VideoEIS =7, // 电子防抖
SuperSlowMoFRC =8, // 超级慢动作 FRC
};4. UsecaseSelector 决策逻辑
文件 chi-cdk/core/chiusecase/chxusecaseutils.cpp → GetMatchingUsecase():
// 输入来自 HAL3 的 configure_streams()
// - operation_mode: NORMAL / CONSTRAINED_HIGH_SPEED / SAT ...
// - stream_count: framework 请求的 stream 数量
// - physical_camera_count: 物理 camera 数量
UsecaseIdGetMatchingUsecase(
OperationModeop_mode,
uint32_t stream_count,
uint32_t physical_camera_count)
{
// 多摄 + 多 stream → 切 MultiCamera (SAT)
if (physical_camera_count>1&&stream_count>1) {
returnUsecaseId::SAT;
}
// HFR 高帧率模式
if (op_mode==OperationMode::CONSTRAINED_HIGH_SPEED) {
returnUsecaseId::HighSpeed;
}
// 检测 EIS 是否使能
if (IsEISEnabled()) {
returnUsecaseId::VideoEIS;
}
// 默认 → AdvancedCameraUsecase(覆盖预览/录像/ZSL拍照等)
returnUsecaseId::Default;
}注意: 这一步只确定 UsecaseId,不涉及 XML 节点匹配。大多数单摄场景走
UsecaseId::Default,实际 Usecase 名将在 AdvancedCameraUsecase 内部通过 XML 匹配确定。
5. UsecaseFactory 分发
文件 chi-cdk/core/chiusecase/chxusecasefactory.cpp → Create():
Usecase*UsecaseFactory::Create(UsecaseIdid) {
switch (id) {
caseUsecaseId::Default:
returnnewAdvancedCameraUsecase(); // ~80% 场景
caseUsecaseId::SAT:
returnnewUsecaseMultiCamera(); // 双摄/多摄变焦
caseUsecaseId::HighSpeed:
returnnewUsecaseHighSpeed(); // HFR 高帧率
caseUsecaseId::VideoEIS:
returnnewUsecaseVideoEIS();
caseUsecaseId::QCFA:
returnnewUsecaseQCFA(); // Quad CFA 模式
...
}
}| UsecaseId | 创建的类 | 典型场景 |
|---|---|---|
Default / PreviewZSL / VideoLiveShot | AdvancedCameraUsecase | 单摄预览、录像、ZSL 拍照 |
SAT / MultiCamera | UsecaseMultiCamera | 双摄变焦(Wide+Tele) |
HighSpeed | UsecaseHighSpeed | 高帧率录像(120/240fps) |
VideoEIS | UsecaseVideoEIS | 电子防抖录像 |
6. AdvancedCameraUsecase::Create() 内部三步
文件 chi-cdk/core/chiusecase/advancedcamerausecase.cpp
6-a. SelectUsecaseConfig() — XML Usecase 匹配
// 匹配算法:遍历编译进来的所有 XML Usecase,寻找匹配配置
voidSelectUsecaseConfig(constStreamConfig&config) {
for (auto&xmlUsecase : GetXMLUsecaseList()) {
// 条件①:StreamConfigMode 必须一致
if (xmlUsecase.streamConfigMode!=config.op_mode)
continue;
// 条件②:framework 的每个 stream 都必须在 XML Targets 里有匹配
boolmatch=true;
for (auto&stream : config.GetStreams()) {
boolfound=false;
for (auto&target : xmlUsecase.GetTargets()) {
// 匹配三要素:Format 类型 + Direction + Resolution 范围
if (stream.GetFormat() ==target.GetFormat() &&
stream.GetDirection() ==target.GetDirection() &&
stream.GetWidth() <=target.GetMaxW() &&
stream.GetHeight() <=target.GetMaxH()) {
found=true;
break;
}
}
if (!found) { match=false; break; }
}
if (match) {
m_pXmlUsecase=&xmlUsecase; // 采用匹配到的 Usecase
return;
}
}
// 无完全匹配 → fallback 到默认 Usecase
m_pXmlUsecase=GetDefaultXMLUsecase();
}6-b. FeatureSetup() — Feature 确定
voidFeatureSetup() {
for (auto&stream : m_frameworkStreams) {
if (stream.GetType() ==StreamType::Snapshot)
AddFeature(FeatureType::MFNR); // 多帧降噪
if (IsHDRRequested())
AddFeature(FeatureType::HDR);
if (IsVideoSnapshotEnabled())
AddFeature(FeatureType::LiveShot); // 录像时拍照
}
}6-c. BuildUsecase() — 插入 Feature Pipelines
voidBuildUsecase() {
// 1. 克隆 XML 定义的 base topology
m_pClonedUsecase=CloneXMLUsecase(m_pXmlUsecase);
// 2. 根据 Feature 插入额外的 pipeline / 修改属性
for (auto&ft : m_features) {
switch (ft) {
caseFeatureType::MFNR:
m_pClonedUsecase->AddPipeline("ReprocessJpeg");
break;
caseFeatureType::LiveShot:
m_pClonedUsecase->AddPipeline("ReprocessYuv2Streams");
break;
caseFeatureType::HDR:
// HDR 一般不改 pipeline 拓扑,通过 IFE 属性控制
m_pClonedUsecase->SetNodeProperty("IFE", "HDRMerge", 1);
break;
}
}
}| Feature | 插入的 Pipeline | 用途 |
|---|---|---|
| MFNR | ReprocessJpeg | 多帧降噪 / 夜景 / HDR+ |
| HDR | 不改拓扑,设 IFE 属性 | HDR 合并模式 |
| LiveShot | ReprocessYuv2Streams | 录像时拍照 |
7. Pipeline & Session 创建
文件 chi-cdk/core/chiusecase/camerausecasebase.cpp → Initialize():
CamxResultCameraUsecaseBase::Initialize() {
// 遍历 BuildUsecase 后确定的 pipeline 列表
for (uint32_ti=0; i<m_pClonedUsecase->GetPipelineCount(); i++) {
constauto&pipeDef=m_pClonedUsecase->GetPipelineDef(i);
// Pipeline::Create() — 解析 XML 拓扑,创建节点和 DRQ 链路
Pipeline*pPipeline=Pipeline::Create(
pipeDef.GetName(),
pipeDef.GetNodeList(),
pipeDef.GetPortLinkages(),
pipeDef.GetAllocProperties());
// Session::Create() — 绑定硬件资源
Session*pSession=Session::Create(pPipeline, m_hCameraHandle);
pSession->RegisterResultCb(ProcessResultCb);
m_pPipelines.push_back(pPipeline);
m_pSessions.push_back(pSession);
}
returnCamxResult::Success;
}camx/src/core/camxpipeline.cpp → Pipeline::Create() 核心逻辑:
// camxpipeline.cpp — 核心解析逻辑
Pipeline*Pipeline::Create(
constchar* name,
constNodeList& nodeList,
constLinkList& linkList,
...)
{
Pipeline*pPipeline=newPipeline(name);
// ① 创建所有 node(Sensor / IFE / IPE / BPS / JPEG ...)
for (auto&nodeDef : nodeList) {
Node*pNode=HwFactory::CreateNode(
nodeDef.GetNodeId(),
nodeDef.GetInstanceId(),
nodeDef.GetProperties());
pPipeline->GetNodeMap()[nodeDef.GetKey()] =pNode;
}
// ② 建�� DRQ 链路(= 拓扑图中的边)
for (auto&linkDef : linkList) {
DRQ*pDrq=DRQ::Create(
pPipeline->FindNode(linkDef.GetSrcKey()),
linkDef.GetSrcPort(),
pPipeline->FindNode(linkDef.GetDstKey()),
linkDef.GetDstPort(),
linkDef.GetBufferProperties());
pPipeline->GetDrqLinks().push_back(pDrq);
}
// ③ 分配硬件资源(IFE/IPE/BPS 时间片、时钟、总线带宽)
pPipeline->AllocateHWResources();
returnpPipeline;
}关键理解: Pipeline 是一个有向无环图(DAG)。Node = 顶点,DRQ Link = 边,数据从 Sensor 节点流向 SinkBuffer 节点。
8. 完整示例:双摄 Preview + Video + Snapshot
以 kona 平台的 UsecaseDualCamera 为例:
// config: op_mode=NORMAL, streams=3 (Preview+Video+Snapshot), 2 cameras (Wide+Tele)
// Step 1: UsecaseSelector
physical_camera_count=2, stream_count=3 → UsecaseId::SAT
// Step 2: UsecaseFactory
→newUsecaseMultiCamera()
// Step 3: UsecaseMultiCamera::Create()
// ③-a XML 匹配
→kona_usecase.xml→<UsecaseName>UsecaseDualCamera</UsecaseName>
Target匹配:
Preview(1080p, NV12) →TARGET_BUFFER_PREVIEW0 (max5488×4112) ✅
Video(4K, NV12) →TARGET_BUFFER_VIDEO0 (max5488×4112) ✅
Snapshot(12M, JPEG) →TARGET_BUFFER_SNAPSHOT0 (format=JPEG) ✅
// ③-b FeatureSetup: 有 Snapshot → MFNR
// ③-c BuildUsecase: 插入 MFNR 的 ReprocessJpeg pipeline
// Step 4: Initialize()
// 最终 pipelines:
Pipeline[0] ="Realtime0" // Wide: Sensor0 → IFE → IPE → Sink
Pipeline[1] ="Realtime1" // Tele: Sensor1 → IFE → IPE → Sink
Pipeline[2] ="ReprocessJpeg" // MFNR: IPE → JPEG → Aggregator → Sink
Session[0] =Session::Create(Pipeline[0])
Session[1] =Session::Create(Pipeline[1])
Session[2] =Session::Create(Pipeline[2])
→3Pipelines, 3Sessions→Ready⚠️ 注意: 如果
UsecaseDualCamera的 Targets 不包含 Video stream,传了 Video stream 下来匹配不上 → fallback 到默认 Usecase。这就是为什么有的双摄平台录像时会被降级到单摄。
9. 匹配规则总结
| 维度 | 匹配规则 | 说明 |
|---|---|---|
| StreamConfigMode | 精确相等 | NORMAL / CONSTRAINED_HIGH_SPEED / SAT 必须一致 |
| Format | 相等(OR 关系) | 一个 Target 可能支持多个 Format(如 NV12 + UBWC) |
| Direction | 相等 | TargetOutput(对应 framework 的 output stream) |
| Resolution | ≤ MaxW/MaxH | 只要 ≤ 上限就算匹配,不等精度匹配 |
| Feature | BuildUsecase 时插入 | 不改 Usecase 匹配结果,只影响 pipeline 数量 |
《更多交流,欢迎加入知识星球》
评论 (0)