一个ExoPlayer原生播放问题引起的思考

3,160 阅读3分钟

问题背景

我们在使用ExoPlayer播放视频的视频发现一种特殊的M3U8视频,播放总是失败。 而且报如下的错误:

ExoPlayerImplInternal: Source error. 
com.google.android.exoplayer2.ParserException: Cannot find sync byte. Most likely not a Transport Stream. 
at com.google.android.exoplayer2.extractor.ts.TsExtractor.read(TsExtractor.java:260) 
at com.google.android.exoplayer2.source.hls.e.f(HlsMediaChunk.java:284) 
at com.google.android.exoplayer2.source.hls.e.load(HlsMediaChunk.java:209) 
at com.google.android.exoplayer2.upstream.Loader$a.run(Loader.java:330) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:919) 

这样的报错似乎是ExoPlayer的原生问题,我们赶紧找到ExoPlayer的源码:

WechatIMG69.png github.com/google/ExoP… 原生报错的地方找到了,但是接下来我们还需要解决下面几个问题:

  • TS格式是怎么样的?
  • ExoPlayer为什么要这样修改?
  • 正确的修改方式是什么样的?

TS格式解析

0.png 正常的TS Packet是188字节,其层次结果如下:

名称位数备注
sync_byte8b同步字节,固定为0x47
transport_error_indicator1b传输错误指示符,表明在ts头的adapt域后由一个无用字节,通常都为0,这个字节算在adapt域长度内
payload_unit_start_indicator1b负载单元起始标示符,一个完整的数据包开始时标记为1
transport_priority1b传输优先级,0为低优先级,1为高优先级,通常取0
pid13bpid值
transport_scrambling_control2b传输加扰控制,00表示未加密
adaptation_field_control2b是否包含自适应区,‘00’保留;‘01’为无自适应域,仅含有效负载;‘10’为仅含自适应域,无有效负载;‘11’为同时带有自适应域和有效负载。
continuity_counter4b递增计数器,从0-f,起始值不一定取0,但必须是连续的

已经规定好了每一个TS Packet大小是188字节,识别TS Packet大小的重要标志是读sync_byte位,两个sync_byte之间相距188字节,说明它是标准的TS格式。 但是,制定的标准,有的遵守标准,有的不一定遵守标准。真的发生的标准不遵守怎么办? 这次ExoPlayer发生播放这样视频失败的原因,就是因为视频源没有遵守TS Packet大小为188字节的规则,这样的错误很尴尬,它违反了标准,但是它前188字节是标准的TS数据。 我们先追踪一下ExoPlayr这段修改的原因。

ExoPlayer这样修改的原因

先放上两个源码修改链接: github.com/google/ExoP… github.com/google/ExoP…

WechatIMG70.png

WechatIMG71.png 从注释来看,google觉得每次加载不一定要等到TS_SYNC_BYTE才算加载成功,但是他们显然又怕当前不是标准的TS流,就加了一个兜底,要是当前读到的位置超过两个188字节还是没有发现TS_SYNC_BYTE,说明当前大概率不是TS流的格式。 这样的判断在标准上而言是没有什么问题的。

我们应该怎么改

我们遇到这样的播放失败,只能采用两种办法了?

  • 向M3U8的提供方提意见,最好修改一下TS内部格式,让其符合标准。
  • 定制化修改ExoPlayer源码,适配这种异常的类型。 第一种难度可能要点高,不太现实,毕竟让服务方给你改东西,人接不太原因。那就只好播放器去适配,播放器将这个校验去掉有没有问题? 从对TS格式分析来看,这样的修改不太完美,但是从播放器的兜底处理来看,这样的处理基本没有风险。因为最坏的结果就是播放失败。已经有兜底方案了,应该没有问题。 制定了标准,总有人不去遵守。