我们在使用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的源码:
https://github.com/google/ExoPlayer/blob/release-v2/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
原生报错的地方找到了,但是接下来我们还需要解决下面几个问题:
正常的TS Packet是188字节,其层次结果如下:
名称 | 位数 | 备注 |
---|---|---|
sync_byte | 8b | 同步字节,固定为0x47 |
transport_error_indicator | 1b | 传输错误指示符,表明在ts头的adapt域后有一个无用字节,通常都为0,这个字节算在adapt域长度内 |
payload_unit_start_indicator | 1b | 负载单元起始标示符,一个完整的数据包开始时标记为1 |
transport_priority | 1b | 传输优先级,0为低优先级,1为高优先级,通常取0 |
pid | 13b | pid值 |
transport_scrambling_control | 2b | 传输加扰控制,00表示未加密 |
adaptation_field_control | 2b | 是否包含自适应区,‘00’保留;‘01’为无自适应域,仅含有效负载;‘10’仅含自适应域,无有效负载;‘11’为同时带有自适应域和有效负载。 |
continuity_counter | 4b | 递增计数器,从0-f,起始值不一定取0,但必须是连续的 |
已经规定好了每一个TS Packet大小是188字节,识别TS Packet大小的重要标志是读sync_byte位,两个sync_byte之间相距188字节,说明它是标准的TS格式。
但是,制定的标准,有的遵守标准,有的不一定遵守标准。真的发生的标准不遵守怎么办?
这次ExoPlayer发生播放这样视频失败的原因,就是因为视频源没有遵守TS Packet大小为188字节的规则,这样的错误很尴尬,它违反了标准,但是它前188字节是标准的TS数据。
我们先追踪一下ExoPlayr这段修改的原因。
先放上两个源码修改链接:
https://github.com/google/ExoPlayer/commit/0697fb3955d8a30edb935cc428d515e2fd9d48cb
https://github.com/google/ExoPlayer/issues/3149
从注释来看,google觉得每次加载不一定要等到TS_SYNC_BYTE才算加载成功,但是他们显然又怕当前不是标准的TS流,就加了一个兜底,要是当前读到的位置超过两个188字节还是没有发现TS_SYNC_BYTE,说明当前大概率不是TS流的格式。
这样的判断在标准上而言是没有什么问题的。
我们遇到这样的播放失败,只能采用两种办法了?
第一种难度可能要点高,不太现实,毕竟让服务方给你改东西,人接不太原因。那就只好播放器去适配,播放器将这个校验去掉有没有问题? 从对TS格式分析来看,这样的修改不太完美,但是从播放器的兜底处理来看,这样的处理基本没有风险。因为最坏的结果就是播放失败。已经有兜底方案了,应该没有问题。
制定了标准,总有人不去遵守。