高通平台 RAW 成像链路分析与画质问题定位
在某项目中系统排查 4K 视频画质模糊问题,从 App 层逐层下钻到 CamX HAL 层,通过 MIPI RAW10 解包、节点对比分析和 Dump 配置,最终定位根因并推动修复。
在 某项目 中,发现 4K 模式录制的视频和拍摄的照片画质模糊。清晰度只有1080p的水平,怀疑相关配置出错,因此需要看raw排查问题。

-
硬件平台:Qualcomm QRB5165
-
底层架构:Qualcomm CamX
方法一:App 端抓取与分析
该项目有两种拍raw的方式:
- 使用配套的app中,将拍照格式设为raw,进行拍照,然后adb导出raw文件。


这种方式拍摄的raw,无法直接用aya打开(画面异常),且体积异常。
推测:该设备基于 Qualcomm (QRB5165) 平台,高通平台默认输出通常为 MIPI RAW10 (Packed) 格式。
-
这种格式采用"5 字节存储 4 个像素"的紧凑排布(10-bit)。
-
普通的 PC 查看工具(如 AYA、Photoshop)默认按 1 字节(8-bit)或 2 字节(16-bit)为一个单位读取。
-
如果不经过格式转换直接打开,像素的位偏移会导致画面完全花屏或无法成像。
-
由于 MIPI RAW10 无法直视,必须使用解包脚本将其转换为 Plain 16-bit 格式。
-
转换逻辑:
-
脚本读取连续的 5 个字节。
-
按照 MIPI 协议将其拆解成 4 个独立的 10-bit 数值。
-
将这些 10-bit 数值放入 16-bit 的容器中(补零对齐)。
预测解包后的文件在 AYA 中设置
16-bit、Little Endian以及Bit shift: +6后,方可呈现出正常的图像内容。Python 脚本解包后得到的是 10-bit LSB aligned(低位对齐) 保存在 16-bit 容器中的 RAW 数据。
-
在 App 中设定的拍照分辨率为 4K (3840 x 2160)。如果 4K 设置生效,按 MIPI RAW10 格式计算,文件体积理论上应为:3840×2160×1.25=10,368,000 字节 (约 9.8 MB)
[raw转换脚本.py]
由于文件名没有具体分辨率信息,推测两个可能性,1.sensor输出了8192 x 6144全尺寸的raw,原先4k setting不生效导致raw体积异常增大。2.原先4k setting生效,其他原因导致raw体积异常增大。
使用脚本转换,手动输入8192 x 6144进行转换,使用aya打开,依旧异常。

直接使用手动设定3840 x 2160,发现图像正常显示,但是重复两张。

继续尝试1920 x 1080,图像正常显示。

得出结论:app中拍摄raw使用的setting为1920*1080,不是4k,因此解析力差,和现象对齐。
重新使用脚本将原raw文件转换为1080p,得出单个文件大小为3.95mb。

原始文件是 MIPI RAW10 (Packed) 格式,每像素占 1.25 Byte
单帧 1080p 大小 = 1920×1080×1.25=2,592,000
62,914,560÷2,592,000≈24.27帧。
结论:原始文件可能是24帧的raw数据流
脚本转换后的文件是 Plain 16-bit (Unpacked) 格式,每像素占 2 Byte。
单帧 1080p 大小 = 1920×1080×2=4,147,200字节。
转换为 MiB = 4,147,200÷1024÷1024≈3.955 MB
结论:这符合 AYA 能够直接读取的标准 16bit 格式大小。
输入 (60MB):是 24 帧的"压缩"数据(RAW10)。
输出 (约 95MB):是 24 帧的"解压"数据(16bit)。
2÷1.25=1.6 倍
60MB×1.6=96MB,这正好对应 24 帧解压后的总大小。
综上结论:app中拍摄的raw,虽然设置了4k,但是拍摄出来是1080p的图片。相关配置出错了。
方法二:camx-hal3-test 底层抓取
由于 App 端的结论证实了分辨率缩减问题,因此切换到更底层的 camx-hal3-test 链路。这种方式直接调用 Qualcomm CamX HAL3 接口,绕过 App 层的处理干扰,获取真正 4K 全尺寸 RAW 来进行验证排查。
camx-hal3-test是 HAL层(硬件抽象层) 的测试工具。
如果在这里手动下发 4K 指令抓出来的 RAW 依然模糊,那就可以直接定性为问题出在 Sensor 驱动(寄存器配置不对) 或者 硬件(镜头没对焦、模组坏了) 身上,底层驱动配置或 Sensor 硬件问题,不需要再在 App 层面浪费时间。
执行命令后,在 /data/vendor/camera 目录下会生成一系列带"节点标签"的 .RAWMIPI10 文件。通过分析文件名中的 IFE(预览路径节点)和 BPS(拍照路径节点)对应的 RAW 数据,我们可以精准定位画质损失究竟发生在流水线的哪个环节。
-
IFE (Image Front End): 相当于"前哨站"。主要负责预览、实时处理。它的 RAW 比较"原始"。
-
BPS (Bayer Processing Segment): 相当于"精修站"。专门处理高画质拍照(Snapshot)的节点。
-
为什么要对比它们: 如果 IFE 清晰但 BPS 模糊,说明"精修"环节把图搞坏了;如果两个都模糊,说明"前哨站"拿到的原始数据就有问题。
在实际操作中,这一步远比 App 拍照复杂,涉及到了底层服务的停启和权限的博弈。
环境冲突与盲拍
为了腾出系统资源并避免系统相机服务占用摄像头,往往需要停掉或删除 App 服务。
-
代价: 删除系统相机服务后,热点会消失。
-
后果: 没了热点就没了 RTSP 预览,整个过程变成了"盲拍"。无法通过屏幕确认对焦是否成功、画面是否过曝,只能靠 adb 盲操作,效率极低。这就是为什么在这个项目里,抓 RAW 和正常评测存在不可调和的矛盾。
1、刷机首次执行
adb root adb remount adb disable-verity adb reboot2、开机每次执行
adb root adb remount adb shell mount -o remount,rw / systemctl stop gst-camera-app.service
核心交互指令
进入 /data/misc/camera 目录后,执行 camx-hal3-test 进入交互界面。此时必须按顺序输入:
配置流 (A指令): A:id=0,psize=1920x1080,pformat=yuv420,ssize=3840x2160,sformat=jpeg,zsl=1
告诉相机,我要开 0 号摄像头,预览设为 1080p,但拍照(ssize)我要 4K 的 JPEG 路径。
触发抓图 (S指令): S:1(拍 1 张)。
退出工具 (Q指令): Q。
初次拍摄失败。根据 log.txt 显示,在 shell 中启动 camx-hal3-test 时,程序瞬间报错:
[log.txt]
-
现象:
=========>>>catch signal 6 <<< from tid:1519====== -
定位: 堆栈信息显示崩溃发生在
CamX::HwEnvironment::Initialize。这说明工具在尝试初始化硬件环境时遭到了拒绝。在下方尝试输入的A:id=0...报错not found,是因为程序已经崩了,其实是在向普通 Linux Shell 发送指令。 -
建议 仅仅
stop服务是不够的,因为系统相机服务可能存在拉起机制或残留进程占用/dev/video*节点。"删除usr/bin/gst-camera-app" 确保没有任何 App 层的代码能干扰到 HAL 层的初始化。
删除**usr/bin/gst-camera-app**后,
使用指令拍摄,却发现 /data/misc/camera 里只有 YUV 和 JPG 。执行完指令后 /data/vendor/camera/ 目录为空,说明底层 Dump 开关未开启。必须将该文件推送到 /vendor/etc/camera/ 路径以强行覆盖系统默认行为。
- 原因:
camx-hal3-test默认只输出指令要求的格式(如sformat=jpeg)。要拿到流水线中途的原始 RAW,必须强行开启底层 Dump 开关。
为了强行接管 CamX 的行为,建议把下面camxoverridesettings文件推到/vendor/etc/camera/目录下
[camxoverridesettings.txt]
-
核心配置项:
autoImageDump=TRUE。这是开启底层 Dump 的总开关,不开启则不会产出 RAW 文件。 -
Mask 掩码逻辑: 配置文件中的
autoImageDumpMask=0x87以及IFE/IPE/BPS的各个outputPortMask被设置为高位值(如0x3FFBFFF)。 这意味着系统会无差别地导出镜像流水线中所有节点的数据。它不再依赖 App 的设置,而是由底层 CamX 直接向硬盘写入数据。
潜在风险与副作用(事后总结)
-
磁盘空间报警: 由于 Mask 掩码设置极其激进,系统会全量导出 4K 模式下的每一帧中间数据。
-
系统崩溃: 这解释了为什么实验过程中
/data分区(约 94G)会在几分钟内被打满。磁盘写满后会导致服务无法启动、热点消失,设备进入不可视的异常状态。 -
操作建议: 抓取完成后必须立即将
autoImageDump设为FALSE或删除该配置文件,并及时清理/data/vendor/camera/下的残留文件。
开启全量 Dump 后,每次触发拍照,/data/vendor/camera 目录下会瞬间生成几十个不同节点的文件。必须通过文件名的特定标签进行筛选,才能定位到真正需要的 4K RAW。
-
文件命名与筛选
一个典型的底层 RAW 文件名格式如下:
p[RealTimeFeature...]_req[1]_IFE[0]_w[3840]_h[2160]_..._b[10]_...RAWMIPI10
-
p[...]:代表该文件所属的 Pipeline 流程。
-
req[x]:请求 ID,同一拍产生的多个文件,其 ID 是一致的。
-
w[xxxx]_h[xxxx]:最核心识别指标。必须在这里看到
3840_2160(4K)或4096_3072(4:3),才能证明抓到了全分辨率。 -
RAWMIPI10:代表这是 10-bit 的 MIPI 原始数据。
在几十个文件中,重点关注以下两类:
-
IFE 标签文件:
p[RealTimeFeatureZSLPreviewRaw]..._IFE[...]...- 这是前端输入节点,反映了 Sensor 吐出来的最原始状态,主要用于排查对焦和基础清晰度。
-
BPS 标签文件:
p[ZSLSnapshotYUVHAL]..._BPS[...]...- 这是拍照路径的中间节点。如果 BPS 出来的图比 IFE 差,说明处理算法或增益分配在 BPS 环节出了问题。
- 过滤无效文件
- 忽略后缀: 忽略所有
.BLOB、.PD10、.UBWCTP10等后缀。这些是元数据、相位数据或高通内部压缩格式,常规工具无法解析。


[p[ZSLSnapshotYUVHAL]_req[1]_batch[0]_BPS[0]_port[0]_w[3840]_h[2160]_19700101_003949.RAW]
[p[RealTimeFeatureZSLPreviewRaw]_req[9]_batch[0]_IFE[0]_port[9]_w[3840]_h[2160]_19700101_003949.RAW]



两张raw解析力均正常。但是BPS文件p[ZSLSnapshotYUVHAL]_req[1]_batch[0]_BPS[0]_port[0]_w[3840]_h[2160]_19700101_003949_3840x2160_f01_u16的亮度异常,需要增加72xgain,整体亮度才和IFE文件类似。
通过对比 App 端和底层 CamX 端的 RAW 数据,得出以下差异:
- App 抓取路径(基于某通信协议):
-
现象:设置 4K 但产出 1080p 连帧 RAW(约 24 帧)。
-
推断:该路径受 App 通信协议消息集控制。虽然控制端下发了 4K 拍照指令,但最终 dump 的是预览路径(Preview Path)的 Buffer,而非真正的单帧快照流(Snapshot Path)。
- 底层抓取路径(camx-hal3-test 直连):
-
现象:手动下发
ssize=3840x2160指令后,成功在 BPS 节点获取 4K 全分辨率单帧 RAW。 -
推断:此结果证明了传感器模组、底层驱动及 HAL 层的 4K Snapshot 链路是打通的。
- 节点数据特征差异(IFE vs BPS):
-
IFE 节点(前端):RAW 画面解析力正常,亮度正常。数据带有基础的 Preview Gain,反映了 Sensor 吐出的原始预览状态。
-
BPS 节点(后端):RAW 画面解析力正常,但亮度极暗(需 72x Gain 还原)。这符合高通 BPS 节点截获线性原始数据(Linear RAW)的特征,证明该节点抓取的是未经 ISP 数字增益处理的、真正的快照原始底图。
在完成 4K (16:9) RAW 抓取后,尝试抓取 4096 x 3072 分辨率的 RAW 数据以进行全像素分析。在执行过程中,经历了三次指令调整:
第一次尝试:内存溢出
-
指令:
A:id=0,psize=640*480,pformat=yuv420,ssize=4096*3072,sformat=jpeg,zsl=1 -
现象:程序报错
Cannot allocate memory并显示Killed。 -
原因分析:
-
该错误由
msmgbm_bo_create触发,说明系统在尝试为 4096 x 3072 分辨率分配图形缓冲区(GBM)时失败。 -
ZSL 模式占用:由于开启了
zsl=1,CamX 会在后台预留多帧高分辨率缓冲区。推测4:3 全分辨率(约 12MP)的数据量极大,超出了当前系统分配给camx-hal3-test的可用内存上限,导致 OOM(内存溢出)被系统强杀。
-
第二次尝试:无文件输出
-
指令:
A:id=0,psize=1920x1080,pformat=yuv420,ssize=2160x1536,sformat=jpeg,zsl=1 -
现象:指令运行看似成功(显示
Exiting application!),但/data/vendor/camera目录下没有生成任何 RAW 文件。 -
原因分析:
- 虽然程序未崩溃,但推测该特定分辨率(2160x1536)可能不在系统预设的静态流配置表中,导致 Pipeline 虽然初始化,但未能成功触发 Dump 逻辑
第三次尝试:成功
-
指令:
A:id=0,psize=1920x1080,pformat=yuv420,ssize=2048*1536,sformat=jpeg,zsl=1 -
结果:成功产出文件。经核对,生成的 RAW 文件名中
w[4096]_h[3072],即达到了 4:3 全尺寸要求。 -
关键推断:
-
ssize 触发机制:在
camx-hal3-test中,ssize参数并不直接决定 RAW 的大小,而是决定了系统调用哪种 Sensor Mode。 -
逻辑链路:输入
2048*1536成功触发了 Sensor 的 Full Size 模式(不进行 Binning 或裁切)。由于底层 Dump(autoImageDump)是在数据流经缩放器(Resizer)之前截获的,因此即便指令要求的是 2048x1536,我们拿到的仍然是该模式下最原始的 4096 x 3072 图像数据。
-
结论
抓取底层 RAW 时,指令中的 ssize 需参考提供的"触发分辨率"。只要 Sensor 进入了对应的全尺寸工作模式,底层 Dump 出来的 RAW 就会保持该模式下的最高物理分辨率,不受后续缩放指令影响。


4:3下,BPS和IFE均正常。
后续:反馈解析力不足可能是由于4k60fps那边的数据应该没有用上,看日志是用到了2k60fps的数据。
提供新的配置文件后,4k60p的解析力正常。
