Test
在移动端处理视频时,传统的 FFmpeg 软解方案常遇到性能瓶颈。今天分享一个实战优化方案,结合 Android 硬件解码和 FFmpeg 滤镜链,实现高效视频处理。
为什么需要硬件解码
移动设备上视频处理面临两大挑战:
- CPU 占用高:1080P 视频软解通常占用单核 80% 以上资源
- 内存压力大:YUV 帧缓冲区的反复拷贝导致内存峰值飙升
通过测试发现,使用 MediaCodec 硬件解码可将 CPU 负载降低至 30% 左右,同时减少 50% 以上的内存拷贝操作。

技术方案选型
常见的硬件解码方案有:
- 纯 MediaCodec 方案
- 优点:直接输出到 SurfaceTexture,零拷贝
-
缺点:无法获取像素数据,不适合后续处理
-
hwdownload 方案
- 优点:支持内存访问,兼容现有处理管线
- 缺点:需要处理 stride 对齐问题
实际项目中,我们选择第二种方案,平衡了性能和灵活性。
关键实现步骤
1. MediaCodec 初始化
配置解码器时需要注意几个关键参数:
// 关键配置示例
AMediaFormat_setString(format, "mime", "video/avc");
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, 1920);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, 1080);
// 必须设置 CSD 数据
AMediaFormat_setBuffer(format, "csd-0", csd0, csd0_size);
特别提醒:Android 8.0+ 需要明确请求 GRALLOC_USAGE_SW_READ_OFTEN 权限。
2. FFmpeg 滤镜链构建

核心滤镜配置示例:
AVFilterGraph *graph = avfilter_graph_alloc();
// 输入缓冲滤镜
AVFilterContext *buffer_ctx;
avfilter_graph_create_filter(&buffer_ctx,
avfilter_get_by_name("buffer"),
"in", args, NULL, graph);
// hwdownload 滤镜
AVFilterContext *hwdownload_ctx;
avfilter_graph_create_filter(&hwdownload_ctx,
avfilter_get_by_name("hwdownload"),
"hwdl", NULL, NULL, graph);
// 格式转换滤镜(NV12 处理关键)AVFilterContext *format_ctx;
avfilter_graph_create_filter(&format_ctx,
avfilter_get_by_name("format"),
"fmt", "pix_fmts=nv12", NULL, graph);
3. 内存处理技巧
- 使用 av_hwframe_transfer_data 时注意 dst 帧的格式
- 检查 linesize[0] 是否等于 width,处理对齐问题
- 推荐使用 AV_PIX_FMT_NV12 格式平衡兼容性和性能
性能优化实测
在骁龙 865 设备上的测试数据:
| 指标 | 软解方案 | 硬件方案 |
|——|———|———|
| CPU 占用 | 82% | 38% |
| 内存峰值 | 120MB | 65MB |
| 解码延迟 | 45ms | 18ms |
常见问题处理
- API 兼容性问题:
- API 21-25 需要额外处理 color format
-
API 26+ 支持更高效的 IMAGE_READER 方案
-
内存泄漏预防:
// 解码器复位时需要显式释放 AMediaCodec_flush(codec); AMediaCodec_stop(codec); -
ANativeWindow 锁竞争:
- 建议使用双缓冲机制
- 控制 surface 的队列频率
延伸应用
这个方案可以无缝集成到 AI 预处理流水线:
- 将解码输出直接送入 TFLite 的预处理层
- 利用 GPU 加速实现归一化和色彩空间转换
- 结合 EGL 实现零拷贝的纹理共享
通过实测,在目标检测场景下,端到端延迟从 120ms 降低到 65ms,效果显著。

这个方案已经在多个商业项目中验证,特别适合需要实时视频处理的场景。建议开发者根据具体需求调整参数,欢迎交流优化经验。
正文完
评论(没有评论)