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的时钟作为主时钟,或者使用共同的参考时钟源。

警告: 不要试图在CTS测试中“作弊”。有些厂商会检测CTS测试包名,然后临时切换解码策略。Google已经在Android 14中加入了反作弊检测,一旦发现,直接判定不通过。

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是个体力活。我一般会这样做:

  1. 先跑全量测试,生成一份完整的报告
  2. 筛选出FAILED的测试项,重点关注module: Media相关的
  3. 查看每个失败项的日志,定位是codec问题、同步问题还是能力声明问题
  4. 修复后,只跑失败的测试项,验证通过
  5. 最后再跑一次全量,确保没有引入新的问题
小技巧: 使用 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适配的脉络理清楚:

媒体CTS适配知识体系 CTS媒体测试项 MediaPlayer测试 MediaCodec测试 DRM & Audio测试 常见兼容性问题 编解码能力声明不一致 常见兼容性问题 音视频同步、分辨率超限 常见兼容性问题 DRM安全级别、HDCP 厂商适配四步走 梳理硬件能力 → 配置media_codecs.xml → 跑CTS分析失败项 → 处理DRM 通过CTS认证 ✓

28.5 一些掏心窝的话

做CTS适配这么多年,我最大的感受是:不要和CTS对着干。CTS的每个测试用例背后,都是Google工程师踩过的坑。你越想绕过去,后面就越容易出问题。

另外,我建议厂商在项目初期就把CTS纳入开发流程,而不是等到最后才来补课。我见过太多团队,功能开发完了,跑CTS发现几百个失败项,然后加班加点改,改完又引入新的问题。何必呢?

最后分享一个我自己的习惯:每次适配一个新平台,我都会把CTS的媒体测试日志完整保存一份。下次遇到类似问题,直接翻日志对比,能省不少时间。

核心要点回顾:
  • CTS媒体测试覆盖播放、编解码、DRM、音频等多个模块
  • 编解码器能力声明必须与硬件真实能力一致
  • 音视频同步问题要统一时钟源
  • DRM测试要确保安全链路完整
  • 适配流程:梳理能力 → 配置 → 测试 → 修复

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