在ts流中,MPEG2编码中,音视频包是交错出现的。
分析其pts可以发现,在同等交错位附近,音频的pts要比视频的靠前得多。
比如一段实际码流数据如下:
--------------------------
valid video packet count1
video packet 视频包1:
packet.pts -9223372036854775808
packet.dts 3529565163
packet.duration 3600
packet.size 37460
packet.pos -1
--------------------------
valid video packet count1
audio stream packet: 音频包1:
packet.pts 3529553320
packet.dts 3529553320
packet.duration 2160
packet.size 384
packet.pos -1
--------------------------
valid video packet count2
video packet: 视频包2:
packet.pts 3529568763
packet.dts 3529568763
packet.duration 3600
packet.size 18508
packet.pos -1
--------------------------
valid video packet count2
audio stream packet 音频包2:
packet.pts 3529555480
packet.dts 3529555480
packet.duration 2160
packet.size 384
packet.pos -1
--------------------------
valid video packet count3
video packet 视频包3
packet.pts 3529572363
packet.dts 3529572363
packet.duration 3600
packet.size 17960
packet.pos -1
--------------------------
valid video packet count3
audio stream packet 音频包3
packet.pts 3529557640
packet.dts 3529557640
packet.duration 2160
packet.size 384
packet.pos -1
--------------------------
valid video packet count3
audio stream packet 音频包4
packet.pts 3529559800
packet.dts 3529559800
packet.duration 2160
packet.size 384
packet.pos -1
--------------------------
valid video packet count4
video packet 视频包4
packet.pts -9223372036854775808
packet.dts 3529575963
packet.duration 3600
packet.size 39632
packet.pos -1
--------------------------
valid video packet count4
audio stream packet 音频包5
packet.pts 3529561960
packet.dts 3529561960
packet.duration 2160
packet.size 384
packet.pos -1
其实这样的理由是,在播放器实际播放过程中,音频是持续播放,以视频来同步音频。
这样的好处是,音频缓冲,而视频实时解码。音频占用存储量较小,而用视频来同步音频,如果解码速度实在跟不上,可以调帧。
人的肉眼对每秒比如25帧的视频跳帧是没有太大察觉度的,但如果音频出问题,很容易听出来,会影响到用户体验。
这就是为什么ts流中音频数据比视频数据优先传输的原因。
如果我们需要对音视频进行同步,关键就是找一个绝对的基准点。而之后所有的音视频数据都可以根据帧率、码率算出来偏移量。如何寻找这个绝对基准点呢?
比如从我要找到某个视频帧对应的确切PCM,可以在音频包上向前寻找附近pts与视频包较为吻合的两个音频包。
然后由于PCM和音频包大小都是固定的,就可以计算出具体的偏移量了。(根据前后pts及视频帧pts计算偏移)
这样,我从ts流任意一个地方开始播放,可能刚开始的视频帧是没有声音的。(因为刚开始的音频包对应的是之后的视频帧)
那在播放过程中,如何指定从确切的某视频帧开始播放?(一般播放器可能不能精确定位到一帧,而是附近的I帧)。
我们只需要向前索引最近的I帧,然后从I帧解出来当前帧就可以了。为了加快速度,甚至可以刚开始建力帧数据的索引信息,用于迅速定位I帧。