用SigmaStar SSC338Q或者海思的hi3516ev300支持csi mipi 720P 120fps的摄像头,中间不需要h.264、h.265编码,经过ISP处理后把视频数据转成mipi DSI或者BT1120输出,要求csi mipi 720P 120fps input、Dsi mipi或者BT1120格式的 720P 120fps output。中间的延时尽可能的短,画面从镜头进到DSI或者BT1120输出总延时控制在30ms以内。请告诉我建议使用SigmaStar SSC338Q或者海思的hi3516ev300哪颗芯片
好的,这是一个非常专业且具体的技术需求。我会为您深入分析SigmaStar SSC338Q和海思Hi3516EV300这两颗芯片的优劣,并提供在选定芯片上的实现方案和伪代码。
结论先行:芯片选型建议
我强烈建议您使用 SigmaStar SSC338Q。
主要原因如下:
- 硬件接口匹配度:
- SigmaStar SSC338Q: 这颗芯片是为智能显示、楼宇对讲等应用设计的,原生集成了MIPI DSI输出接口。这使得您的需求(CSI输入 -> ISP -> DSI输出)形成了一个完美的硬件闭环,无需任何外部转换芯片。
- 海思 Hi3516EV300: 这颗芯片是典型的IP Camera(网络摄像头)SoC。它的强项在于视频编码(H.264/H.265)和网络传输。它没有 MIPI DSI 输出接口。其显示输出通常是并口的BT.656/BT.1120,主要用于连接一些简单的调试屏或者外挂其他处理单元。如果要在EV300上实现MIPI DSI输出,您必须外加一颗“Parallel RGB to MIPI DSI”的桥接芯片,这会显著增加硬件复杂性、成本,以及更关键的——延迟。
- 产品定位和SDK支持:
- SigmaStar: 其SDK/BSP对于“Camera to Display”的场景(官方称为
MIPI,Media Infrastructure)有非常成熟和直接的支持。通过其MI_SYS_Bind机制,可以构建出从CSI到DSI的零拷贝(Zero-Copy)、低延迟的硬件数据通路。 - 海思: 其MPP(Media Process Platform)媒体处理平台的核心是为“编码、推流、存储”服务的。虽然也能做到ISP处理后输出到显示接口,但整个框架和文档的侧重点不在此,为低延迟显示优化的案例和支持相对较少。
- SigmaStar: 其SDK/BSP对于“Camera to Display”的场景(官方称为
- 性能和延迟潜力:
- 数据通路: SSC338Q的内部总线和专用硬件通路(SCL/ISP -> DISP)就是为这种低延迟显示场景设计的。只要配置正确,可以实现极低的延迟。
- 120fps处理能力: 720P@120fps的总像素率约为
1280 * 720 * 120 ≈ 110.6 Mpixels/s。这个数据率对于这两颗芯片的ISP来说都是在能力范围之内的(通常它们能处理至少2MP@30fps,即约60 Mpixels/s,高端一些的可以到4K@30fps,约250 Mpixels/s)。关键瓶颈在于输出接口和内部数据流转效率,这正是SSC338Q的优势所在。
综上所述,Hi3516EV300在硬件上就不满足您的核心需求,后续的软件修改无从谈起。因此,以下所有实现方案都将基于SigmaStar SSC338Q展开。
基于SigmaStar SSC338Q的实现方案
您的目标是构建一个“实时预览”或“数字内窥镜”式的超低延迟视频通路。在SigmaStar的SDK中,这可以通过绑定(Bind)机制来实现,该机制可以在内核态直接将一个模块的输出数据流对接到另一个模块的输入,避免了数据在用户态的拷贝和调度延迟。
数据流路径:
Sensor (720P@120fps) -> MIPI CSI -> SCL/ISP模块 -> DISP模块 -> MIPI DSI -> 显示屏
关键实现步骤和代码修改思路
假设您已经拿到了SigmaStar提供的SSC338Q SDK。您需要做的不是修改某一份现成的代码,而是编写一个新的应用程序来初始化并绑定这些硬件模块。
1. 确认Sensor驱动和配置
- 您需要有一个支持720P@120fps输出的图像传感器(Sensor)。
- 在BSP的内核驱动中,必须有这个Sensor的驱动程序,并且该驱动要能正确配置Sensor进入720P@120fps模式。这通常通过I2C配置Sensor寄存器完成。
- 在用户态,您需要通过
MI_SNR_SetFps和MI_SNR_SetRes等API来设定Sensor的工作模式。
2. 确认DSI Panel驱动和配置
- 同样,您需要在BSP中配置好您的DSI屏幕驱动。这包括屏幕的分辨率、时序参数(HSYNC, VSYNC, PCLK等)、MIPI DSI的Lane数、速率等。
- 这些配置通常在
kernel/drivers/sstar/disp/hal/pioneer3/disp/目录下的panel配置文件中完成。 - 开机后,您需要初始化Panel:
MI_PANEL_Init(MI_PANEL_INTF_MIPI_DSI)。
3. 编写主应用程序(C代码)
核心思路是初始化各个模块,然后将它们绑定在一起,最后启动数据流。
#include "mi_sys.h"
#include "mi_vif.h" // 在某些SDK版本中,CSI输入归VIF管理
#include "mi_scl.h" // SCL是ISP和缩放等功能的核心模块
#include "mi_disp.h"
#include "mi_panel.h"
// 伪代码,展示核心逻辑和API调用流程
// 实际代码需要完整的错误处理和参数填充
int main(int argc, char **argv)
{
//================================================================
// Step 1: 系统初始化
//================================================================
MI_SYS_Init();
//================================================================
// Step 2: 初始化并配置输出端 (DSI Panel & DISP)
//================================================================
// 初始化Panel,使用DSI接口
MI_PANEL_Init(MI_PANEL_INTF_MIPI_DSI);
// 初始化DISP设备
MI_DISP_DEV DispDevId = 0;
MI_DISP_PubAttr_t stDispPubAttr;
stDispPubAttr.eIntfType = MI_DISP_INTF_MIPIDSI; // 接口类型
stDispPubAttr.eIntfSync = MI_DISP_OUTPUT_USER; // 时序由Panel驱动定义
MI_DISP_SetPubAttr(DispDevId, &stDispPubAttr);
MI_DISP_Enable(DispDevId);
// 配置并使能DISP的视频层 (Video Layer)
MI_DISP_LAYER DispLayerId = 0;
MI_DISP_VideoLayerAttr_t stLayerAttr;
// 获取Panel的时序信息来设置Layer大小
MI_PANEL_ParamConfig_t stPanelParam;
MI_PANEL_GetPanelParam(&stPanelParam);
stLayerAttr.stVidLayerSize.u16Width = stPanelParam.u16Width;
stLayerAttr.stVidLayerSize.u16Height = stPanelParam.u16Height;
// ... 其他参数设置
MI_DISP_BindVideoLayer(DispLayerId, DispDevId);
MI_DISP_SetVideoLayerAttr(DispLayerId, &stLayerAttr);
MI_DISP_EnableVideoLayer(DispLayerId);
// 配置并使能DISP的输入端口 (Input Port)
MI_DISP_INPUTPORT LayerInputPortId = 0;
MI_DISP_InputPortAttr_t stInputPortAttr;
stInputPortAttr.stDispWin.u16X = 0;
stInputPortAttr.stDispWin.u16Y = 0;
stInputPortAttr.stDispWin.u16Width = 1280; // 输入视频源的尺寸
stInputPortAttr.stDispWin.u16Height = 720;
MI_DISP_SetInputPortAttr(DispLayerId, LayerInputPortId, &stInputPortAttr);
MI_DISP_EnableInputPort(DispLayerId, LayerInputPortId);
//================================================================
// Step 3: 初始化并配置输入端 (Sensor & SCL/ISP)
//================================================================
MI_SNR_PAD_ID_e eSnrPad = E_MI_SNR_PAD_ID_0;
MI_VIF_DEV VifDevId = 0; // VIF设备通常和SNR Pad对应
MI_VIF_CHN VifChnId = 0;
MI_SCL_DEV SclDevId = 0; // SCL设备ID
MI_SCL_CHN SclChnId = 0; // SCL通道ID
MI_SCL_PORT SclOutputPortId = 0; // SCL输出端口ID
// 1. 使能Sensor
MI_SNR_SetPlaneMode(eSnrPad, FALSE);
MI_SNR_SetRes(eSnrPad, MI_SNR_QueryRes(0)); // 选择支持120fps的那个分辨率
MI_SNR_SetFps(eSnrPad, 120);
MI_SNR_Enable(eSnrPad);
// 2. 配置VIF (CSI接收)
// ... VIF的初始化和配置,使其匹配Sensor的输出 ...
MI_VIF_CreateChn(VifChnId, ...);
MI_VIF_StartChn(VifChnId);
// 3. 配置SCL (ISP处理和缩放)
MI_SCL_CreateDevice(SclDevId, ...);
MI_SCL_CreateChannel(SclDevId, SclChnId, ...);
MI_SCL_StartChannel(SclDevId, SclChnId);
// 配置SCL的输出端口
MI_SCL_PortParam_t stSclPortParam;
stSclPortParam.stPortSize.u16Width = 1280;
stSclPortParam.stPortSize.u16Height = 720;
stSclPortParam.ePixelFormat = E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_420; // DISP通常接收YUV格式
MI_SCL_SetOutputPortParam(SclDevId, SclChnId, SclOutputPortId, &stSclPortParam);
//================================================================
// Step 4: 核心步骤 - 绑定模块
//================================================================
MI_SYS_ChnInfo_t stSrcChnInfo; // 源
MI_SYS_ChnInfo_t stDstChnInfo; // 目标
// 绑定 SCL -> DISP
stSrcChnInfo.eModId = E_MI_MODULE_ID_SCL;
stSrcChnInfo.u32DevId = SclDevId;
stSrcChnInfo.u32ChnId = SclChnId;
stSrcChnInfo.u32PortId = SclOutputPortId;
stDstChnInfo.eModId = E_MI_MODULE_ID_DISP;
stDstChnInfo.u32DevId = DispDevId;
stDstChnInfo.u32ChnId = DispLayerId; // DISP的通道就是它的Layer
stDstChnInfo.u32PortId = LayerInputPortId;
// 此函数是实现低延迟的关键!它在内核层面建立了数据通路
MI_SYS_Bind(&stSrcChnInfo, &stDstChnInfo);
//================================================================
// Step 5: 主循环,程序保持运行
//================================================================
while(1) {
sleep(1);
}
//================================================================
// Step 6: 程序退出前的清理工作(解绑、销毁模块)
//================================================================
MI_SYS_UnBind(&stSrcChnInfo, &stDstChnInfo);
// ... 依次销毁DISP, SCL, VIF, SNR等模块 ...
MI_SYS_Exit();
return 0;
}
延迟控制 (< 30ms) 的关键点
30ms是一个非常严格的目标。总延迟 = Sensor延迟 + 传输延迟 + ISP处理延迟 + 缓冲延迟 + 显示延迟。
- Sensor延迟: 这是延迟的大头之一,包括曝光时间(Exposure Time)和读出时间(Readout Time)。在120fps下,每帧的时间是 1/120s ≈ 8.33ms。您的曝光时间必须远小于8.33ms。如果曝光时间是5ms,那么Sensor内部延迟就已经占了很大一部分。请务必选择支持高速读出(Global Shutter更佳)的Sensor。
-
ISP处理延迟:
- 关闭不必要的功能: 在SCL/ISP的属性设置中,关闭或简化一些重量级的算法,例如3D降噪(3DNR)、WDR(宽动态)、高级锐化等。这些算法通常需要缓存多帧或进行复杂计算,会引入显著延迟。只保留最基本的Demosaic、色彩校正、Gamma等。
- SigmaStar SDK通常允许对ISP pipeline进行精细控制,请查阅相关文档,找到关闭这些功能的API。
- 缓冲(Buffer)延迟:
MI_SYS_Bind机制本身就是为了消除用户态和内核态之间的数据拷贝,是降低缓冲延迟的核心。- 检查SCL模块和DISP模块的属性,看是否有关于内部Buffer数量的配置项(
u32BufQueueDepth或类似名称)。将其设置为最小值,比如1或2。这样可以防止数据在模块之间堆积。 MI_SYS_SetChnOutputPortDepth这个API可以用来精细控制某个模块输出端口的buffer队列深度,是延迟优化的关键。例如,将SCL输出端口的buffer深度设为1。
- DSI传输和显示延迟:
- 确保MIPI DSI的时钟速率配置正确且足够高,以保证能在8.33ms内传输完一帧720P的数据。
- 显示屏本身也有其内部处理延迟,选择高质量、响应速度快的屏幕。
总结
- 芯片选择: 必须是 SigmaStar SSC338Q,因为它原生支持MIPI DSI输出。
- 实现方式: 利用SigmaStar SDK的
MI_SYS_Bind机制,在内核态构建从SCL到DISP的硬件数据通路。 - 代码框架: 按照“初始化输出 -> 初始化输入 -> 绑定 -> 运行”的逻辑编写应用程序,无需复杂的线程和数据处理,核心工作由硬件和驱动完成。
- 延迟优化:
- 选择高速Sensor。
- 精简ISP处理流程,关闭3DNR、WDR等。
- 设置模块间的Buffer队列深度为最小值(1或2)。
- 确保DSI时钟速率足够。
结论先行:芯片选型建议
我仍然强烈建议您使用 SigmaStar SSC338Q。
即使Hi3516EV300支持BT.1120输出,SSC338Q在您的这种“低延迟、实时显示”应用场景中,依然是更优、更合适的选择。
详细对比分析
| 特性/方面 | SigmaStar SSC338Q | 海思 Hi3516EV300 | 分析与结论 |
|---|---|---|---|
| 产品定位 | 智能显示、楼宇对讲、行车记录仪 | 专业网络摄像头 (IP Camera) | SSC338Q定位更契合。 它的设计初衷就是“输入->处理->显示”,而EV300的重心是“输入->处理->编码->网络”。 |
| MIPI DSI 输出 | 原生支持,硬件集成 | 不支持,需外挂桥接芯片 | SSC338Q完胜。 如果您最终选择DSI方案,SSC338Q是唯一可行的选择,它能提供最低延迟和最低硬件成本。 |
| BT.1120 输出 | 支持 | 支持 | 在此接口上两者硬件打平。但软件和系统架构的差异会带来性能区别。 |
| SDK架构与延迟 | MI架构,为绑定而生。 MI_SYS_Bind 机制是其核心,专门用于构建零拷贝、低延迟的内核态数据通路,非常适合您的需求。 |
MPP架构,为编码而生。 虽然也有VO(Video Output)模块,但整个框架的优化重点和文档示例都倾向于编码推流,低延迟显示的优化支持相对较弱。 | SSC338Q架构优势明显。 SStar的SDK能让您更容易、更高效地实现超低延迟的Sensor-to-Display通路。 |
| 性能瓶颈 | 1. 720P@120fps 约 110.6 Mpixels/s 的数据率,对ISP和内部总线是考验。2. DSI/BT1120接口时钟能否稳定跑到所需频率。 |
1. 同样面临 110.6 Mpixels/s 的数据率压力。2. 其VO模块是否针对120fps高帧率做过优化和验证是个未知数。 |
两者硬件性能都需要实际验证,但SSC338Q的系统架构在处理这种高帧率实时流时,因其专用性而更具确定性。 |
| 开发难度 | SStar的SDK示例中有大量MIPI Preview或Sensor to LCD的例子,您可以直接参考修改。 |
您可能需要将一个为编码设计的示例,魔改成一个纯显示的应用,可能需要摸索更多底层配置。 | SSC338Q开发更直接。 |
综合定论:
* 如果您倾向于或未来可能使用MIPI DSI,那么SSC338Q是您唯一的选择。
* 如果您确定只使用BT.1120,SSC338Q凭借其更匹配的SDK架构和更低的延迟潜力,依然是更优的选择。
基于SigmaStar SSC338Q的实现方案
以下方案将涵盖MIPI DSI和BT.1120两种输出方式。核心逻辑非常相似,主要区别在于DISP(显示)模块的初始化配置。
数据流路径:
Sensor (720P@120fps) -> MIPI CSI -> SCL/ISP模块 -> DISP模块 -> (选择其一) -> MIPI DSI 或 BT.1120
关键实现步骤和代码修改
我们将编写一个统一的应用程序框架,通过宏定义或启动参数来选择最终的输出接口。
#include "mi_sys.h"
#include "mi_vif.h"
#include "mi_scl.h"
#include "mi_disp.h"
#include "mi_panel.h" // 仅DSI输出需要
// 使用宏来选择输出模式,实际项目中可改为命令行参数
#define USE_MIPI_DSI_OUTPUT 1 // 1: DSI输出, 0: BT1120输出
// 伪代码,展示核心逻辑和API调用流程
// 实际代码需要完整的错误处理和参数填充
int main(int argc, char **argv)
{
//================================================================
// Step 1: 系统初始化
//================================================================
MI_SYS_Init();
//================================================================
// Step 2: 初始化并配置输出端 (DISP设备)
//================================================================
MI_DISP_DEV DispDevId = 0;
MI_DISP_PubAttr_t stDispPubAttr;
memset(&stDispPubAttr, 0, sizeof(stDispPubAttr));
#if USE_MIPI_DSI_OUTPUT
// ----- A. DSI输出初始化 -----
// 1. 初始化Panel驱动
MI_PANEL_Init(MI_PANEL_INTF_MIPI_DSI);
// 2. 配置DISP设备以匹配DSI Panel
stDispPubAttr.eIntfType = MI_DISP_INTF_MIPIDSI;
stDispPubAttr.eIntfSync = MI_DISP_OUTPUT_USER; // 时序由Panel驱动定义
MI_DISP_SetPubAttr(DispDevId, &stDispPubAttr);
#else
// ----- B. BT.1120输出初始化 -----
// 1. 配置DISP设备为BT.1120模式
stDispPubAttr.eIntfType = MI_DISP_INTF_BT1120;
stDispPubAttr.eIntfSync = MI_DISP_OUTPUT_720P120; // 需要SDK支持该枚举值,或手动配置时序
// 您需要在此处详细配置BT.1120的时序参数 (hsync, vsync, etc.)
// stDispPubAttr.stBt1120Attr. ...
MI_DISP_SetPubAttr(DispDevId, &stDispPubAttr);
#endif
// ----- 公共的DISP初始化流程 -----
MI_DISP_Enable(DispDevId);
// 配置并使能DISP的视频层
MI_DISP_LAYER DispLayerId = 0;
MI_DISP_VideoLayerAttr_t stLayerAttr;
memset(&stLayerAttr, 0, sizeof(stLayerAttr));
stLayerAttr.stVidLayerSize.u16Width = 1280;
stLayerAttr.stVidLayerSize.u16Height = 720;
stLayerAttr.ePixFormat = E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_422; // BT.1120通常是YUV422
MI_DISP_BindVideoLayer(DispLayerId, DispDevId);
MI_DISP_SetVideoLayerAttr(DispLayerId, &stLayerAttr);
MI_DISP_EnableVideoLayer(DispLayerId);
// 配置并使能DISP的输入端口
MI_DISP_INPUTPORT LayerInputPortId = 0;
MI_DISP_InputPortAttr_t stInputPortAttr;
memset(&stInputPortAttr, 0, sizeof(stInputPortAttr));
stInputPortAttr.stDispWin.u16X = 0;
stInputPortAttr.stDispWin.u16Y = 0;
stInputPortAttr.stDispWin.u16Width = 1280;
stInputPortAttr.stDispWin.u16Height = 720;
MI_DISP_SetInputPortAttr(DispLayerId, LayerInputPortId, &stInputPortAttr);
MI_DISP_EnableInputPort(DispLayerId, LayerInputPortId);
//================================================================
// Step 3: 初始化并配置输入端 (Sensor & SCL/ISP)
// (这部分代码与之前的回复完全相同)
//================================================================
MI_SNR_PAD_ID_e eSnrPad = E_MI_SNR_PAD_ID_0;
MI_SCL_DEV SclDevId = 0;
MI_SCL_CHN SclChnId = 0;
MI_SCL_PORT SclOutputPortId = 0;
// 1. 使能Sensor,配置为720P@120fps
MI_SNR_SetPlaneMode(eSnrPad, FALSE);
MI_SNR_SetRes(eSnrPad, /*...选择720p...*/);
MI_SNR_SetFps(eSnrPad, 120);
MI_SNR_Enable(eSnrPad);
// 2. 配置VIF/SCL,此处省略详细配置代码
// ... VIF Create/Start ...
// ... SCL Create/Start ...
// 3. 配置SCL的输出端口参数,这是绑定的源头
MI_SCL_PortParam_t stSclPortParam;
memset(&stSclPortParam, 0, sizeof(stSclPortParam));
stSclPortParam.stPortSize.u16Width = 1280;
stSclPortParam.stPortSize.u16Height = 720;
stSclPortParam.ePixelFormat = E_MI_SYS_PIXEL_FRAME_YUV_SEMIPLANAR_422; // 匹配DISP层的输入格式
MI_SCL_SetOutputPortParam(SclDevId, SclChnId, SclOutputPortId, &stSclPortParam);
//================================================================
// Step 4: 核心步骤 - 绑定模块 (SCL -> DISP)
//================================================================
MI_SYS_ChnInfo_t stSrcChnInfo; // 源: SCL
MI_SYS_ChnInfo_t stDstChnInfo; // 目标: DISP
stSrcChnInfo.eModId = E_MI_MODULE_ID_SCL;
stSrcChnInfo.u32DevId = SclDevId;
stSrcChnInfo.u32ChnId = SclChnId;
stSrcChnInfo.u32PortId = SclOutputPortId;
stDstChnInfo.eModId = E_MI_MODULE_ID_DISP;
stDstChnInfo.u32DevId = DispDevId;
stDstChnInfo.u32ChnId = DispLayerId;
stDstChnInfo.u32PortId = LayerInputPortId;
// 建立数据通路,这是实现低延迟的关键!
MI_SYS_Bind(&stSrcChnInfo, &stDstChnInfo);
//================================================================
// Step 5: 主循环,程序保持运行
//================================================================
printf("Pipeline is running... Press Ctrl+C to exit.\n");
while(1) {
sleep(1);
}
//================================================================
// Step 6: 程序退出前的清理工作
//================================================================
MI_SYS_UnBind(&stSrcChnInfo, &stDstChnInfo);
// ... 依次销毁DISP, SCL, VIF, SNR等模块 ...
MI_SYS_Exit();
return 0;
}
延迟控制 (< 30ms) 的关键点 (再次强调)
要实现30ms以内的延迟,必须进行极致的优化,因为在120fps下,每帧的时间窗口只有8.33ms。
- 硬件选型是基础:
- Sensor: 必须选用高速Sensor,最好是Global Shutter(全局快门)以减少果冻效应,并确保其在120fps下的读出延迟足够低。
- SoC: 已确定SSC338Q更优。
- 软件配置是核心:
- 精简ISP: 关闭所有非必要的ISP功能,尤其是需要多帧缓存的算法,如3DNR(时域降噪)和WDR(宽动态)。这两个是延迟大户。只保留最基本的ISP流程。
- 零缓冲策略: 这是实现最低延迟的最关键一步。你需要使用
MI_SYS_SetChnOutputPortDepth接口将数据通路上所有模块的输出端口Buffer队列深度设置为最小值。// 示例:在绑定前,设置SCL输出端口的buffer深度为1 // 这意味着SCL处理完一帧后不会等待,而是立即尝试发送给DISP // 如果DISP正忙,会产生丢帧,但保证了显示出来的永远是最新的一帧,延迟最低 MI_SYS_SetChnOutputPortDepth(&stSrcChnInfo, 1, 1); - 高优先级任务: 如果您的系统上还有其他任务在运行,请确保这个实时视频处理应用的调度优先级是最高的,避免被其他进程抢占CPU时间。
总结
- 芯片选择:SigmaStar SSC338Q 是完成此项任务的理想选择,无论您最终使用MIPI DSI还是BT.1120。
- 实现方案:基于SStar SDK,通过初始化Sensor、SCL、DISP模块,并使用
MI_SYS_Bind将它们连接起来,构建一个纯硬件处理的视频通路。 - 代码修改:核心是正确配置DISP模块以匹配您选择的DSI或BT.1120接口,然后将SCL的输出绑定到DISP的输入。
- 延迟优化:成功的关键在于精简ISP和设置零缓冲(或最小缓冲)。您必须通过
MI_SYS_SetChnOutputPortDepthAPI来严格控制数据通路中的缓冲,这是从软件层面降低延迟的最有效手段。
遵循此方案,您将有很大机会在SSC338Q平台上实现720P@120fps输入到输出,且延迟控制在30ms以内的目标。