音视频帧DTS、PTS的简单生成

科普:视频的I、B、P帧和PTS、DTS的关系
详细科普:雷霄骅博客


  • 需求:读取h264视频裸流文件、读取aac音频裸流文件,并发送出去
  • 现象:播放器拿到数据播放的时候。ffplay和VLC兼容性好的播放器播放画面正常,容错性稍微差一点的如小程序的live-player标签,就会出现画面回跳
  • 原因:视频中有B帧,裸流文件中不带pts,需要自己手工生成

1、视频的PTS、DTS

  • 没有B帧的时候PTS = DTS
  • 有B帧的时候:
    • 1、B帧PTS = B帧的DTS
    • 2、I帧或者P帧PTS = DTS + 依赖此帧解码并在此帧前显示的B帧的数量 + 1
    • 3、需要保证每一帧的 PTS >= DTS
  • 思路
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    1、假设P帧之间的B帧数量为3个

    2、
    编码顺序:
    I P1 B1 B2 B3 P2 ... ...
    播放顺序:
    I B1 B2 B3 P1 ...P2 ...

    3、
    实现的时候可以理解为将B帧用一个队列bframeQueue存起来,遇到下一个P帧或者I帧的时候,将bframeQueue全部出队列,并计算bframeQueue中B帧的PTS和前一个P或I帧的PTS

    PTS与DTS
    I P1 B1 B2 B3 P2 B4 B5 B6 P3//编码顺序
    0 1 2 3 4 5 6 7 8 9//DTS
    0 5 2 3 4 9 6 7 8 13 //PTS = DTS + bframeQueue.size() + 1
    //这里可以看到,当不加后面1的时候,P帧会和一个B帧PTS重复了

    4、
    假如视频fps为30,一帧占用30分之1秒,就是1/fps秒
    那么每编码出一帧的时候,DTS就是 n * 1/fps秒
    根据上面的思路,PTS就可以根据DTS算出来了

2、音频的PTS、DTS

音频PTS = DTS,比较简单。

1
2
3
4
5
6
7
F0 F1 F2 F3 ... //编码顺序
0 1 2 3 ... //DTS
0 1 2 3 ... //PTS

假如音频的采样率为 44100 Hz ,即1秒对声音采样44100次
AAC一帧数据固定包含1024个采样,那就是一帧数据占用 1024/44100 秒,即 1024/sampling_frequency 秒
那么每编码出一帧的时候,DTS就是 n * 1024/sampling_frequency 秒

AAC格式大概了解一下

3、其他

了解了一下,在直播当中,很大一部分为了保证低延时、实现简单,都不会在视频流里面传送B帧。