限时福利领取


为什么需要硬件解码 H.265?

根据实测数据,使用 FFmpeg 软解 4K H.265 视频时:

  • 中端手机 CPU 占用率高达 70%~90%
  • 平均功耗达到 800mW(正常播放的 3 倍)
  • 帧率波动范围 ±15fps

功耗对比图

技术选型:FFmpeg vs MediaCodec

FFmpeg 软解方案

  • 优点:跨平台统一实现
  • 缺点:
  • 无法调用 DSP/GPU 加速
  • 内存复制次数多(平均 3 次/帧)

MediaCodec 硬解方案

  • 优点:
  • 直接使用硬件解码器
  • 支持 Zero-Copy 渲染(Surface 直通)
  • 缺点:
  • 需要处理 Android 版本碎片化
  • 配置参数较复杂

混合架构实现

sequenceDiagram
    Flutter->>+Platform: 发送视频数据
    Platform->>+MediaCodec: 输入缓冲区入队
    MediaCodec-->>-Platform: 输出帧就绪
    Platform->>+SurfaceTexture: 更新纹理
    SurfaceTexture-->>-Flutter: 渲染新帧

核心代码实现

Flutter 插件基础结构

class H265Decoder {
  final MethodChannel _channel = const MethodChannel('h265_decoder');

  Future<void> initDecoder(int width, int height) async {
    await _channel.invokeMethod('init', {
      'width': width,
      'height': height,
    });
  }
}

Android 端关键配置

MediaFormat format = MediaFormat.createVideoFormat("video/hevc", width, height);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
    MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);

MediaCodec decoder = MediaCodec.createDecoderByType("video/hevc");
decoder.configure(format, surface, null, 0);

性能优化实战

缓冲区计算

缓冲区大小 = (width × height × 3/2) × 缓冲帧数
// 例如 1080p 双缓冲:
// (1920 × 1080 × 1.5) × 2 ≈ 6MB

实测数据(骁龙865)

| 分辨率 | 解码方式 | 平均帧率 | 功耗 | |--------|----------|---------|------| | 1080p | 硬解 | 60fps | 200mW| | 4K | 硬解 | 45fps | 350mW| | 4K | 软解 | 18fps | 850mW|

生产环境陷阱

  1. Android 8.0 以下适配
  2. 需要单独处理 COLOR_FormatYUV420Flexible
  3. 某些设备要求添加 csd-0 头数据

  4. 资源泄漏防护

    @Override
    protected void finalize() throws Throwable {
        releaseDecoder();
        super.finalize();
    }
  5. 色域转换问题

  6. 必须校验 COLOR_Format 支持列表
  7. 推荐使用 GLSL 做 YUV->RGB 转换

开放性问题

如何实现动态码率适配?建议研究方向:

  1. 监听 BatteryManager.BATTERY_PROPERTY_CURRENT_NOW
  2. 根据电量状态切换解码 profile
  3. 动态调整输出 Surface 分辨率

动态适配示意图

Logo

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

更多推荐