限时福利领取


作为一名安卓开发者,最近在处理H.265视频转码时踩了不少坑。今天就把我的实战经验整理成笔记,分享给同样被兼容性问题困扰的小伙伴们。

为什么需要转码?

H.265(HEVC)虽然压缩率高,但在安卓生态里简直是「兼容性地狱」:

  • 约30%的安卓设备无法硬解H.265
  • 微信等社交平台直接拒绝HEVC格式上传
  • 低端设备解码时CPU占用率轻松突破80%

H.265与H.264压缩效率对比

技术方案选型

测试了三套方案在骁龙865上的表现:

| 方案 | 1080P转码耗时 | CPU占用峰值 | 内存峰值 | |-------------------|---------------|-------------|----------| | FFmpeg纯软解 | 42s | 95% | 380MB | | MediaCodec硬解 | 15s | 30% | 210MB | | 混合方案(本文推荐)| 18s | 45% | 250MB |

推荐混合方案:用MediaCodec解码H.265,FFmpeg做后处理(如滤镜),最后MediaMuxer封装MP4。

核心代码实现

1. 解码流水线搭建

关键点在于正确配置ColorFormat,这里用YUV420Flexible保证兼容性:

MediaFormat inputFormat = MediaFormat.createVideoFormat("video/hevc", width, height);
MediaCodec decoder = MediaCodec.createDecoderByType("video/hevc");
decoder.configure(inputFormat, surface, null, 0);

// 关键:设置自适应YUV格式
inputFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
    MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);

2. 编码参数优化

比特率设置建议采用动态码率(VBR):

MediaFormat outputFormat = MediaFormat.createVideoFormat("video/avc", width, height);
outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height * 3); // 经验值
outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
outputFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
    MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);

3. 线程安全封装

用双缓冲队列避免阻塞:

// 解码线程
synchronized (frameQueue) {
    frameQueue.offer(frameData);
    frameQueue.notifyAll();
}

// 编码线程
while (frameQueue.isEmpty()) {
    frameQueue.wait();
}
ByteBuffer frame = frameQueue.poll();

转码流程示意图

性能优化实战

内存控制技巧

测试不同分辨率下的内存占用:

| 分辨率 | 纯软解内存 | 硬解内存 | |---------|------------|----------| | 720p | 180MB | 90MB | | 1080p | 380MB | 210MB | | 4K | 1.2GB | 650MB |

优化建议: 1. 大视频分片处理 2. 及时releaseOutputBuffer 3. 禁用不必要的帧重排序

首帧加速方案

通过预热编解码器,首帧延迟从800ms降到200ms:

  1. 提前初始化Codec但不传递数据
  2. 保持解码器常驻内存(注意OOM风险)
  3. 使用温启动池管理实例

避坑指南

Android 8.0以下兼容性: - 遇到COLOR_FormatYUV420Flexible不支持时,回退到COLOR_FormatYUV420Planar - 需要额外做色彩空间转换

内存泄漏预防

// 必须按顺序释放
surface.release();
decoder.stop();
decoder.release();

延伸实验

尝试调整CRF参数(18-28区间): - CRF每+6,文件体积减半 - CRF>24时明显出现块状伪影

完整代码示例已上传Gist:点击查看

推荐进一步学习: 1. Android MediaCodec官方文档 2. FFmpeg硬件加速编译指南 3. OpenGL ES视频后处理

希望这篇笔记能帮你少走弯路,如果有更好的方案欢迎交流讨论!

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐