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能提供什么,双方得坐下来谈。

协商过程分三步:

  1. App端发起请求:App通过CameraDevice.createCaptureSession()提交一组OutputConfiguration,每个配置里包含分辨率、格式、StreamType。
  2. 框架层校验:CameraService会检查这些配置是否在CameraCharacteristics声明的SCALER_AVAILABLE_STREAM_CONFIGURATIONS范围内。
  3. 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_CONFIGURATIONSREQUEST_AVAILABLE_CAPABILITIES

13.4 性能优化建议:让Stream跑得更稳

好,理论说完了,咱们来点实战的。Stream配置怎么优化?我总结了四条:

13.4.1 减少不必要的Stream

每多一个Stream,就多一路buffer生产和消费。能复用就复用。比如预览和视频录制,如果分辨率一致,可以用同一个Stream,通过SurfaceViewMediaCodec共享buffer。

13.4.2 选择合适的buffer格式

YUV_420_888是通用格式,但性能不如NV21或NV12。如果App不需要做图像处理,直接用SurfaceTextureSurfaceView,让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 知识体系总览

最后,我用一张图把本章的核心逻辑串起来。你一看就明白:

CameraStream配置核心逻辑 Stream类型定义 PREVIEW / STILL_CAPTURE VIDEO_RECORD / RAW / DEPTH 每个类型对应独立pipeline 分辨率与格式协商 App请求 → 框架校验 → HAL确认 查StreamConfigurationMap Stream组合限制 硬件资源有限 ISP带宽 / DMA通道 不同平台限制不同 性能优化建议 减少Stream · 选对格式 · 控制分辨率 · 合理buffer数 目标:低延迟、低功耗、高帧率 核心原则 每个Stream独立配置,组合需验证,性能靠优化

这张图把Stream配置的四个核心环节串起来了。从左到右是配置流程,从上到下是优化方向。你写HAL代码时,脑子里要有这张图。

好了,关于CameraStream配置,今天就讲这么多。记住:配置不是写死,而是协商。多查CameraCharacteristics,多打日志,多验证组合。这样你的代码才能在各种设备上跑得稳。


公众号:蓝海资料掘金营,微信deep3321