13、CameraStream配置:Stream类型定义、分辨率与格式协商、Stream组合限制、性能优化建议
各位同学,今天我们来聊聊CameraStream配置。说实话,这块内容在Camera HAL开发中属于「天天打交道,但未必真吃透」的领域。我见过不少工程师,代码能跑,但一问到Stream类型为什么这么设计、分辨率协商的底层逻辑是什么,就有点含糊了。
嗯,咱们今天就把这块彻底掰开揉碎。
13.1 Stream类型定义:你到底要拍什么?
先问个问题:一个Camera设备,同一时刻能输出几种数据?
答案是:可以很多种。比如预览、拍照、视频录制、YUV回调、深度图输出……每一种数据流,在Android框架里就是一个Stream。
Stream的类型,由StreamType枚举定义。我直接给你列出来:
| StreamType | 含义 | 典型用途 |
|---|---|---|
CAMERA_STREAM_TYPE_PREVIEW |
预览流 | 取景器显示 |
CAMERA_STREAM_TYPE_STILL_CAPTURE |
拍照流 | JPEG/YUV拍照 |
CAMERA_STREAM_TYPE_VIDEO_RECORD |
视频录制流 | MediaCodec输入 |
CAMERA_STREAM_TYPE_VIDEO_SNAPSHOT |
视频快照流 | 录制中抓拍 |
CAMERA_STREAM_TYPE_ZSL |
零延迟快门流 | ZSL拍照输入 |
CAMERA_STREAM_TYPE_RAW |
RAW数据流 | 专业模式/DNG输出 |
CAMERA_STREAM_TYPE_DEPTH |
深度数据流 | 人像模式/AR |
这里有个细节:StreamType不是随便选的。它直接影响HAL内部的buffer管理策略和ISP pipeline配置。比如PREVIEW流,HAL通常会走低延迟、低功耗的路径;而STILL_CAPTURE流,则会走高精度、多帧合成的路径。
核心原则:每个StreamType对应一条独立的buffer生产-消费链路。不要试图用一个Stream干所有事,那是给自己挖坑。
13.2 分辨率与格式协商:一场「双向奔赴」
Stream配置里最让人头疼的,就是分辨率和格式的协商。说白了,就是App想要什么,Camera能提供什么,双方得坐下来谈。
协商过程分三步:
- App端发起请求:App通过
CameraDevice.createCaptureSession()提交一组OutputConfiguration,每个配置里包含分辨率、格式、StreamType。 - 框架层校验:CameraService会检查这些配置是否在
CameraCharacteristics声明的SCALER_AVAILABLE_STREAM_CONFIGURATIONS范围内。 - HAL层最终确认:HAL的
configureStreams()方法会收到所有Stream配置,然后返回是否支持。如果不支持,HAL可以调整分辨率或格式——但说实话,我建议HAL尽量别做调整,容易出兼容性问题。
举个例子,App想要一个3840x2160的YUV_420_888流,但你的Sensor最大只支持1920x1080的YUV输出。这时候怎么办?
嗯,框架会直接拒绝。所以App端一定要先查getOutputSizes()和getOutputFormats(),别硬来。
避坑指南:我曾经遇到一个项目,App直接硬编码了4K分辨率,结果在某个低端设备上闪退。后来我建议他们先查StreamConfigurationMap,再动态生成UI选项。从此再没出过问题。
13.3 Stream组合限制:不是你想配就能配
你以为只要每个Stream单独支持,组合起来就一定没问题?
太天真了。
实际上,Stream组合限制是HAL开发里最大的坑之一。我直接给你看一个典型的限制表:
| 组合场景 | 预览流 | 拍照流 | 视频流 | 是否常见 |
|---|---|---|---|---|
| 普通预览+拍照 | ✓ | ✓ | ✗ | 是 |
| 预览+视频录制 | ✓ | ✗ | ✓ | 是 |
| 预览+拍照+视频 | ✓ | ✓ | ✓ | 部分设备支持 |
| 双预览流 | ✓ | ✗ | ✗ | 需HAL支持 |
| RAW+YUV+JPEG | ✗ | ✓ | ✗ | 需HAL支持 |
为什么会有限制?说白了,就是硬件资源不够用。ISP的带宽、DMA通道数、内存带宽,都是有限的。你同时开三个4K流,Sensor和ISP都得冒烟。
我记得有一次调试一个三摄项目,App同时开启了主摄预览、长焦拍照、广角视频录制。结果HAL直接返回-EINVAL。查了半天,发现是ISP的MIPI接口带宽不够。最后只能降级到1080p才搞定。
注意:Stream组合限制不是固定的。不同芯片平台、不同Sensor、不同HAL实现,限制都不一样。一定要在CameraCharacteristics里查SCALER_AVAILABLE_STREAM_CONFIGURATIONS和REQUEST_AVAILABLE_CAPABILITIES。
13.4 性能优化建议:让Stream跑得更稳
好,理论说完了,咱们来点实战的。Stream配置怎么优化?我总结了四条:
13.4.1 减少不必要的Stream
每多一个Stream,就多一路buffer生产和消费。能复用就复用。比如预览和视频录制,如果分辨率一致,可以用同一个Stream,通过SurfaceView和MediaCodec共享buffer。
13.4.2 选择合适的buffer格式
YUV_420_888是通用格式,但性能不如NV21或NV12。如果App不需要做图像处理,直接用SurfaceTexture或SurfaceView,让HAL走硬件overlay路径,省掉一次memcpy。
13.4.3 控制分辨率上限
不是所有场景都需要4K。预览用1080p就够了,拍照才用全分辨率。我见过一个App,预览和拍照都用4K,结果帧率掉到15fps。后来改成预览1080p、拍照4K,体验立马好了。
13.4.4 合理设置buffer数量
HAL的configureStreams()里可以指定maxBuffers。别设太大,否则内存吃紧;也别设太小,否则容易丢帧。一般3~5个buffer是比较合理的范围。
我的个人习惯:在HAL的configureStreams()里加一段日志,打印出所有Stream的配置信息。调试时一眼就能看出问题。比如:
for (auto& stream : streams) {
ALOGI("Stream: id=%d, type=%d, format=0x%x, size=%dx%d, maxBuffers=%d",
stream->id, stream->stream_type, stream->format,
stream->width, stream->height, stream->max_buffers);
}
13.5 知识体系总览
最后,我用一张图把本章的核心逻辑串起来。你一看就明白:
这张图把Stream配置的四个核心环节串起来了。从左到右是配置流程,从上到下是优化方向。你写HAL代码时,脑子里要有这张图。
好了,关于CameraStream配置,今天就讲这么多。记住:配置不是写死,而是协商。多查CameraCharacteristics,多打日志,多验证组合。这样你的代码才能在各种设备上跑得稳。
公众号:蓝海资料掘金营,微信deep3321