15、软编码与硬编码对比:软编码方案(x264、fdk-aac)、软硬编码性能对比、混合编码策略
说到编码,很多同学第一反应就是「用硬编码啊,快」。嗯,这话对了一半。我在项目中踩过不少坑,今天就把软编码和硬编码的底裤扒干净,让你知道什么时候该用软的,什么时候该上硬的。
软编码方案:x264 与 fdk-aac
先说说软编码。说白了,就是用 CPU 去算编码。Android 上最主流的视频软编码器是 x264,音频则是 fdk-aac。这两个库都是开源界的扛把子。
x264:视频编码的瑞士军刀
x264 有多强?我做过一个对比测试:同样码率下,x264 的压缩效率比 MediaCodec 的硬编码高出 15%-20%。代价就是 CPU 占用高,发热大。
在 Android 上集成 x264,一般用这个配置:
// x264 参数配置示例
x264_param_t param;
x264_param_default_preset(¶m, "medium", "zerolatency");
param.i_csp = X264_CSP_I420;
param.i_width = 1280;
param.i_height = 720;
param.i_fps_num = 30;
param.i_fps_den = 1;
param.rc.i_bitrate = 2000; // 2Mbps
param.i_keyint_max = 60;
x264_param_apply_profile(¶m, "baseline");
这里有个坑:zerolatency 这个预设很关键。如果你做直播,必须用这个,否则编码器会缓存帧,导致延迟飙升。我曾经在项目里忘了加这个参数,结果延迟从 200ms 直接飙到 2 秒,被测试小姐姐追着骂了一下午。
fdk-aac:音频编码的良心之选
音频方面,fdk-aac 是 Android 上最靠谱的软编码方案。AAC 格式的压缩率比 MP3 高,音质还好。我一般这么配置:
// fdk-aac 编码器初始化
AACENC_InfoStruct info = {0};
AACENC_ERROR err;
// 设置参数
aacEncoder_SetParam(handle, AACENC_AOT, AOT_AAC_LC);
aacEncoder_SetParam(handle, AACENC_SAMPLERATE, 44100);
aacEncoder_SetParam(handle, AACENC_CHANNELMODE, MODE_2);
aacEncoder_SetParam(handle, AACENC_CHANNELORDER, CH_ORDER_MPEG);
aacEncoder_SetParam(handle, AACENC_BITRATE, 128000); // 128kbps
aacEncoder_SetParam(handle, AACENC_TRANSMUX, TT_MP4_LATM_MCP1);
注意这个 TT_MP4_LATM_MCP1,它决定了音频流的封装格式。做 RTMP 推流时,一般用 TT_MP4_RAW 或者 TT_MP4_ADTS,具体看你用的封装库支持哪种。
软硬编码性能对比
直接上数据,这是我用小米 11 实测的结果:
| 对比项 | 软编码(x264) | 硬编码(MediaCodec) |
|---|---|---|
| 编码延迟 | 30-50ms | 5-15ms |
| CPU 占用 | 40%-60% | 5%-15% |
| 压缩效率 | 高(同码率画质更好) | 中(画质略差) |
| 发热量 | 严重 | 轻微 |
| 兼容性 | 好(所有设备一致) | 差(不同芯片差异大) |
| 码率控制 | 精准(CBR/VBR 随意调) | 粗糙(部分设备不支持 VBR) |
看到这个表,你可能会想:「那硬编码不是完胜吗?」别急,听我说完。
硬编码最大的问题是什么?是 不一致。高通骁龙的硬编码表现和联发科天玑完全不一样,甚至同一颗芯片不同厂商的调校也不同。我在做一款直播 App 时,在小米手机上跑得好好的,换到 OPPO 上画面就花屏了。查了两天才发现是 MediaCodec 的 COLOR_FormatYUV420SemiPlanar 和 COLOR_FormatYUV420Planar 的差异导致的。
而软编码呢?x264 在所有设备上的行为完全一致。你调好的参数,换台手机还是那个效果。这就是为什么很多专业直播软件宁可牺牲性能也要用软编码。
混合编码策略
既然软硬编码各有优劣,那能不能结合起来?当然可以。这就是我常说的「混合编码策略」。
核心思路很简单:根据场景动态切换。
混合编码的核心原则:
- 低负载场景(如普通聊天):用硬编码,省电省发热
- 高画质场景(如游戏直播):用软编码,保证画质
- 设备发热严重时:自动切回硬编码,防止烫手
- 网络波动时:软编码可以更精细地控制码率
下面这张图是我在项目中实际使用的混合编码决策流程:
这个流程看起来复杂,其实核心就一句话:能硬则硬,该软则软。
我的实践经验:
在混合编码切换时,有个细节很容易被忽略——关键帧对齐。从软编码切到硬编码时,如果不在关键帧边界切换,接收端会出现花屏。我一般会在切换前强制编码器输出一个 IDR 帧,然后再切。
注意:不要频繁切换编码器。每次切换都会造成短暂的画面卡顿。我建议设置一个「冷却时间」,比如切换后至少 5 秒内不再切换。
最后说一个我踩过的坑。有一次做直播项目,产品经理要求「画质必须最好,延迟必须最低」。这俩要求本身就是矛盾的。我跟他解释了半天,最后定了个折中方案:启动时用硬编码保证低延迟,等用户进入直播间稳定后,再无缝切换到软编码提升画质。这个方案用户感知不到切换过程,体验反而更好。
嗯,这就是我对软硬编码的理解。说白了,没有银弹,只有最适合当前场景的方案。你想想看,是不是这个理?