Android平台硬件加速H.264/HEVC视频解码至OpenGL FBO或纹理
嘿,很高兴看到你带着桌面开发的背景来折腾Android的视频解码+OpenGL渲染,咱们直接聊你关心的核心问题:
毫无疑问,MediaCodec是当前Android平台硬件加速视频编解码的官方标准方案。从API 16(Android 4.1)引入至今,它已经成为所有主流Android设备上实现硬件解码的核心组件——底层直接调用设备的专用视频解码芯片(比如高通的Adreno解码单元、联发科的VPU等),完全绕开CPU参与解码运算,能把性能和功耗控制到最优。
对比之前的MediaPlayer,MediaCodec提供了更低层级的控制能力,允许你直接管理解码缓冲、输出目标等,非常适合你这种需要自定义后续处理(比如对接OpenGL做滤镜)的场景。而且现在几乎所有第三方视频框架(比如ExoPlayer)的底层解码逻辑也都是基于MediaCodec实现的,足以证明它的地位。
当然可以!而且这正是实现零拷贝高性能管线的关键操作,完美契合你不想浪费CPU资源的需求。
具体来说,你可以通过SurfaceTexture这个组件把OpenGL纹理和MediaCodec的输出绑定起来:
- 首先创建一个
GL_TEXTURE_EXTERNAL_OES类型的OpenGL纹理(这个类型是专门为视频帧这类外部输入设计的,支持硬件层面的格式转换) - 用这个纹理ID初始化
SurfaceTexture,再把SurfaceTexture包装成Surface对象 - 把这个
Surface传给MediaCodec的configure()方法,指定为解码输出目标
这样一来,MediaCodec硬件解码后的视频帧会直接写入到绑定的OpenGL纹理中——整个过程完全在硬件内部流转,没有任何CPU层面的数据拷贝,效率拉满。
接下来你要做的就是:
- 当MediaCodec输出新帧时,
SurfaceTexture会收到回调,调用它的updateTexImage()方法把最新帧同步到OpenGL纹理 - 在着色器中使用
samplerExternalOES采样器(记得加上#extension GL_OES_EGL_image_external : require扩展)来访问这个纹理,直接应用滤镜或变换
结合你桌面开发的经验,这个流程有点类似桌面端用VA-API解码后直接把帧导入OpenGL纹理的零拷贝方案,但Android这边用MediaCodec+SurfaceTexture的组合是官方原生支持的,不需要依赖第三方库,兼容性更好。
- 提前用
MediaCodecList查询设备支持的硬件解码格式,尽量选择硬件原生支持的编码格式(比如H.264、H.265),避免MediaCodec fallback到软件解码(一旦用了软件解码,CPU占用会飙升) - 尽量保持OpenGL上下文和MediaCodec的解码逻辑在同一个线程,或者正确设置EGL上下文共享,避免跨线程的资源开销
- 除非有特殊需求,不要把
SurfaceTexture中的帧拷贝到普通OpenGL纹理——这会引入额外的GPU拷贝,打破零拷贝的性能优势
内容的提问来源于stack exchange,提问作者cloudraven




