28. 兼容性与CTS测试:媒体CTS测试项、兼容性问题、厂商适配指南
做Android多媒体框架这么多年,我有个很深的体会:代码写得再漂亮,过不了CTS都是白搭。CTS,全称Compatibility Test Suite,是Google用来检验设备是否“够格”成为Android设备的一套测试集。说白了,它就是一道门槛——你的设备要想预装Google服务,媒体相关的CTS测试项必须全部通过。
今天我们就来聊聊媒体CTS测试的那些事儿。我会结合自己踩过的坑,讲讲常见的兼容性问题,以及厂商该怎么去适配。
28.1 媒体CTS测试项概览
媒体CTS测试,主要分布在以下几个模块里。我习惯把它们分成三类:
| 测试模块 | 测试内容 | 典型测试类 |
|---|---|---|
| MediaPlayer | 音视频播放、Seek、循环、多实例 | MediaPlayerTest, MediaPlayerSeekTest |
| MediaCodec | 编解码器能力、格式支持、异步模式 | MediaCodecTest, DecoderTest, EncoderTest |
| Camera | 预览、拍照、录像、参数合规 | CameraTest, VideoCaptureTest |
| Audio | 音频录制、播放、延迟、路由 | AudioRecordTest, AudioTrackTest |
| DRM | 数字版权管理、安全解码 | MediaDrmTest, ClearKeyTest |
每个测试项背后,都对应着CDD(Compatibility Definition Document)里的硬性要求。比如,Android 12以上要求设备必须支持VP9硬件解码,这个在CTS里就有对应的测试用例。
28.2 常见的媒体兼容性问题
我在项目中遇到过不少兼容性问题,有些问题反复出现。这里挑几个典型的说说。
28.2.1 编解码器能力声明不一致
这个问题最常见。厂商在MediaCodecList里声明了支持某种格式,但实际硬件解码器却处理不了。CTS的做法是:先查你的codec列表,然后挨个送测试流去解码。
举个例子:
// 厂商声明支持AVC Baseline Profile Level 4.0
// 但实际硬件解码器只支持到Level 3.1
// CTS会构造一个Level 4.0的流去测试,结果解码失败
// 正确的做法:在MediaCodecList中如实声明能力
MediaCodecList codecList = MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (info in codecList.codecInfos) {
if (info.isEncoder) continue
val capabilities = info.getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_AVC)
// 检查profile和level
val profileLevels = capabilities.profileLevels
// 确保只声明硬件真正支持的级别
}
嗯,这里要注意:不要为了通过CTS而虚报能力。我曾经见过某厂商把profile level报得很高,结果CTS测试时解码器直接崩溃。最后不得不降级声明,重新跑一轮测试。
28.2.2 音视频同步问题
这个坑我踩过好几次。CTS里有个测试叫MediaPlayerSyncTest,它会播放一段音视频,然后检查音画是否同步。很多厂商在硬件加速解码时,音频和视频的时钟源不一致,导致音画不同步。
你想想看,视频用硬件时钟,音频用ALSA的时钟,两个时钟漂移不一样,时间一长肯定对不上。解决办法是:统一使用AudioTrack的时钟作为主时钟,或者使用共同的参考时钟源。
28.2.3 分辨率与帧率超限
CTS会测试各种分辨率组合,包括极限情况。比如,你的设备屏幕是1080p,但CTS可能会测试4K视频播放——如果你的硬件不支持,就必须在codec列表里明确排除。
我建议的做法是:
- 在
media_codecs.xml中明确声明每个codec支持的最大分辨率和帧率 - 对于不支持的格式,使用
Limits标签进行限制 - 不要依赖解码器内部的“自适应降级”,CTS不认这个
28.3 厂商适配指南
说了这么多问题,那厂商到底该怎么适配?我总结了一套流程,你可以参考一下。
28.3.1 第一步:梳理硬件能力
拿到一个新的SoC平台,第一件事不是写代码,而是搞清楚硬件能做什么、不能做什么。我习惯列一个表格:
| 媒体能力 | 硬件支持情况 | 备注 |
|---|---|---|
| H.264 解码 | 支持到4K@60fps | Level 5.2 |
| H.265 解码 | 支持到4K@30fps | Main Profile |
| VP9 解码 | 不支持 | 需软件解码或升级固件 |
| AV1 解码 | 不支持 | Android 14要求可选 |
这个表格直接决定了你的media_codecs.xml怎么写。千万别偷懒,硬件能力梳理越细,后面CTS踩坑越少。
28.3.2 第二步:配置media_codecs.xml
这个文件是Stagefright的灵魂。每个codec的声明都要精确匹配硬件能力。我分享一个我常用的模板:
<MediaCodecs>
<Decoders>
<MediaCodec name="OMX.google.h264.decoder" type="video/avc" >
<Limit name="size" min="176x144" max="1920x1080" />
<Limit name="frame-rate" range="1-30" />
<Limit name="bitrate" range="1-20000000" />
<Feature name="adaptive-playback" />
</MediaCodec>
</Decoders>
</MediaCodecs>
这里有个细节:adaptive-playback这个feature,如果你的硬件支持动态分辨率切换,一定要加上。CTS里有个测试专门检查这个。
28.3.3 第三步:跑CTS并分析失败项
跑CTS是个体力活。我一般会这样做:
- 先跑全量测试,生成一份完整的报告
- 筛选出
FAILED的测试项,重点关注module: Media相关的 - 查看每个失败项的日志,定位是codec问题、同步问题还是能力声明问题
- 修复后,只跑失败的测试项,验证通过
- 最后再跑一次全量,确保没有引入新的问题
cts-tradefed run cts --module CtsMediaTestCases --test <test_name> 可以单独跑某个测试用例,节省时间。
28.3.4 第四步:处理DRM相关测试
DRM测试是很多厂商的噩梦。CTS里的MediaDrmTest会测试多种安全级别:L1、L2、L3。如果你的设备支持L1(安全解码路径到显示屏),那必须确保整个链路都是安全的。
我曾经遇到一个问题:设备声明支持L1,但实际HDMI输出时,内容保护没有生效。CTS会检测HDMI输出是否启用了HDCP,如果没有,测试直接失败。
解决办法是:确保HDMI输出时,HDCP自动启用。这个需要在HAL层做适配。
28.4 知识体系总览
说了这么多,我画了一张图,帮你把整个媒体CTS适配的脉络理清楚:
28.5 一些掏心窝的话
做CTS适配这么多年,我最大的感受是:不要和CTS对着干。CTS的每个测试用例背后,都是Google工程师踩过的坑。你越想绕过去,后面就越容易出问题。
另外,我建议厂商在项目初期就把CTS纳入开发流程,而不是等到最后才来补课。我见过太多团队,功能开发完了,跑CTS发现几百个失败项,然后加班加点改,改完又引入新的问题。何必呢?
最后分享一个我自己的习惯:每次适配一个新平台,我都会把CTS的媒体测试日志完整保存一份。下次遇到类似问题,直接翻日志对比,能省不少时间。
- CTS媒体测试覆盖播放、编解码、DRM、音频等多个模块
- 编解码器能力声明必须与硬件真实能力一致
- 音视频同步问题要统一时钟源
- DRM测试要确保安全链路完整
- 适配流程:梳理能力 → 配置 → 测试 → 修复
公众号:蓝海资料掘金营,微信deep3321