前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ExoPlayer漫谈之解码器复用

ExoPlayer漫谈之解码器复用

作者头像
马上就说
发布2021-01-21 22:59:31
2.1K0
发布2021-01-21 22:59:31
举报
文章被收录于专栏:码上就说码上就说

播放器性能的极致优化,就是要发现播放流程中一点一滴的耗时,然后分析这些耗时,并提出有效的方式解决这些耗时.了解过ExoPlayer播放器的同学们都知道ExoPlayer的解码是依赖Android系统提供的原生的解码模块,即MediaCodec来实行视频和音频解码的.

基于我们对MediaCodec使用方式和原理的熟悉,我们在使用MediaCodec的时候,首先要初始化,codec configure, codec start等流程,经过这些流程,codec分配内存来存储input buffer 和 output buffer

这块耗时对视频播放而言是无法避免的,不管是网络视频还是本地视频, codec 初始化--->configure ---> start ---> 上屏这部分的耗时都是无法避免的.

我们抓一下一个1080P的本地视频的systrace, 显示如下:

可以发现: video decoder和audio decoder创建/configure/start耗时了170ms, 直接占用了绝大部分耗时, 确实是耗时的大头.

目前ExoPlayer最新的版本是2.12.2, 而且保持着凉州一个小版本, 两个月一个大版本的更新节奏, google的工作效率还是比较高的. 针对codec 复用, 在2.10版本之前和2.10之后的版本, 使用方式和原理还是有所不同的.

ExoPlayer 2.10版本之前的codec复用

  • disabled状态, 在此状态下, 渲染器没有要播放的媒体流并且不保存解码器实例。
  • enabled状态, 在此状态下,渲染器可以播放媒体流,并在可能的情况下(例如,在读取流的格式之后)获取解码器实例。
  • started状态, 在此状态下,渲染器使用持有的解码器实例来播放视频

在2.10之前的版本中,只要视频渲染器保持在启用和启动状态,ExoPlayer就会尽可能重复使用视频解码器。特别是,这意味着从播放列表中的一种媒体过渡到另一种媒体时,视频解码器将被重用。在渲染列表过渡到禁用状态时,音频解码器不会在此类播放列表过渡中重用,视频或音频解码器也不会重用。重要的是,重新准备播放器以播放其他MediaSource会导致这种类型的状态转换,因此在这种情况下不会重复使用解码器。

一句话, 想复用codec实例,不能调用stop方法,不能将codec置为disabled状态

ExoPlayer 2.10版本之后的codec复用

2.10版本可以保证在播放新的视频源的时候复用播放器解码器资源.即使当前的渲染器持有的解码器实例已经被置为disabled状态

复用解码器实例可以减少多个视频源之间切换导致的丢帧的问题,更加可以节省时间.下面是复用解码器实例之后的systrace耗时:

解码器实例复用要求

解码器实例可以复用,肯定是有条件的,例如上一个视频播放的是VP9的视频,下一个视频播放的是H265的视频,那么解码器实例肯定不能复用. 具体是什么条件了,我们还是查看源码确认一下: MediaCodecRenderer.java有两个子类, MediaCodecVideoRenderer.java和MediaCodecAudioRenderer.java

MediaCodecVideoRenderer.java

代码语言:javascript
复制

  @Override
  protected DecoderReuseEvaluation canReuseCodec(
      MediaCodecInfo codecInfo, Format oldFormat, Format newFormat) {
    DecoderReuseEvaluation evaluation = codecInfo.canReuseCodec(oldFormat, newFormat);

    @DecoderDiscardReasons int discardReasons = evaluation.discardReasons;
    if (newFormat.width > codecMaxValues.width || newFormat.height > codecMaxValues.height) {
      discardReasons |= DISCARD_REASON_VIDEO_MAX_RESOLUTION_EXCEEDED;
    }
    if (getMaxInputSize(codecInfo, newFormat) > codecMaxValues.inputSize) {
      discardReasons |= DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED;
    }

    return new DecoderReuseEvaluation(
        codecInfo.name,
        oldFormat,
        newFormat,
        discardReasons != 0 ? REUSE_RESULT_NO : evaluation.result,
        discardReasons);
  }
  • 首先当前的视频的最大分辨率不能超过codec支持的最大解码分辨率
  • 其次视频的输入size不能超过codec的input buffer size

MediaCodecAudioRenderer.java

代码语言:javascript
复制
@Override
  protected DecoderReuseEvaluation canReuseCodec(
      MediaCodecInfo codecInfo, Format oldFormat, Format newFormat) {
    DecoderReuseEvaluation evaluation = codecInfo.canReuseCodec(oldFormat, newFormat);

    @DecoderDiscardReasons int discardReasons = evaluation.discardReasons;
    if (getCodecMaxInputSize(codecInfo, newFormat) > codecMaxInputSize) {
      discardReasons |= DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED;
    }

    return new DecoderReuseEvaluation(
        codecInfo.name,
        oldFormat,
        newFormat,
        discardReasons != 0 ? REUSE_RESULT_NO : evaluation.result,
        discardReasons);
  }
  • 音频的输入size不能超过codec的input buffer size
我们如何复用解码器

  • 保证你播放的视频的格式是相同的,例如短视频信息流都是H264/AAC编码格式
  • 如果使用ExoPlayer播放器,最好使用同一个ExoPlayer实例,因为codec实例是封装在ExoPlayer实例中的
  • 当重新prepare新的视频时,在调用prepare之前不能调用stop函数,因为stop函数会释放解码器实例
  • 如果你要调用stop函数的情况下还想保持解码器实例不被释放,你需要调用setForegroundMode(...)函数,这个函数的使用方式是比较复杂的,不能误用

https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/ExoPlayer.html#setForegroundMode-boolean-

打开了ForegroundMode模式,意味着解码器资源在调用stop的时候都不会被释放,当然这是在复用解码器资源的场景下使用的,使用的时候要小心一些,在最终的时候还是要记得释放资源的,不然会出现问题.

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 音视频平凡之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ExoPlayer 2.10版本之前的codec复用
  • ExoPlayer 2.10版本之后的codec复用
  • 解码器实例复用要求
  • 我们如何复用解码器
相关产品与服务
云点播
面向音视频、图片等媒体,提供制作上传、存储、转码、媒体处理、媒体 AI、加速分发播放、版权保护等一体化的高品质媒体服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档