VP8编码器对关键帧的判断

892 阅读3分钟

在webrtc系统中,关键帧的判断一直是一个重要的逻辑,不同的编解码器对关键帧的判断有不同的逻辑, 这里介绍一下VP8的关键帧判断逻辑.

VP8 RTP包结构

  • payload desc : 对VP8负载数据的描述

  • payload header : 非关键帧3个字节或者关键帧10个字节, 只有视频帧的第一个RTP包才会有此header

  • payload : 负载数据

payload descriptor

以上两种结构的区别在于PictureID的长度, 左侧结构中pic ID占7位, 右侧结构中pic ID占15位.

  • X : 扩展位, 如果置 ‘ 1 ’, 后面会紧跟一个字节的X项, 包括I、L、T、K、RSV

  • I : 置1 表示存在pic ID, 且其紧跟在扩展字节‘X’之后

  • pic ID域由M和Picture ID组成, M=1, picID占15位; M=0, picID占7位

  • L : 置1 表示存在TL0PICIDX, 他跟在Picture ID之后, 且T位必须置1

  • T : 置1 或(T=0 且K=1), TID/Y/KEYIDX字节存在, 否则不存在

  • K : 置1 表示TID/Y/KEYIDX字节存在; T=1且K=0, KEYIDX域被忽略; 否则TID/Y/KEYIDX字节不存在

  • TID = 0 : TL0PICIDX表示的是时间基础层帧的运行索引, 与SVC相关

  • TID > 0 : TL0PICIDX表示的是当前图像所依赖的基础层帧, 同样与SVC相关

  • TID/Y/KEYIDX域中, TID占2位, Y占1位, KEYIDX占5位

  • TID : 代表时间层, 基础层为0, 层级越高, 值越大

  • Y : 层同步位, 置1, 表示当前帧仅依赖基础层帧(TID0); 置0表示当前帧不依赖基础层帧

  • KEYIDX : key帧索引值

  • SRV : 保留位, 必须置0

  • R : 预留位, 设置成‘0’ 即可, 为以后使用,现在忽略

  • N : 是否非参考帧, 置 ‘1’ 表示是非参考帧, 这类帧在VP8中不重要, 丢弃时不影响其他将来或过去的帧

  • S : 表示这个包是否编码帧的第一个分片, 其他分片S位为0

  • PID : 表示分片的序号, 第一个分片为0, 后续分片PID可以相同, 也可以递增, 但不超过8

Payload Header

  • 可以是3个字节 也可以是10个字节, 前3个字节表达的含义都相同

  • 关键帧, 该域占10字节; 内部帧该域占3字节

  • P : 1位, 是否关键帧, 0 - key, 1 - interframe, 不同于其他结构中扩展位的含义

  • VER : 3位, 0-3定义了4种不同的解码复杂度的profile

  • H : 忽略

  • Size0/1/2 : 19位, 这个RTP包携带的视频帧第一个分片大小, 对于每一个视频帧来说只有第一个RTP包携带了payload header, 而那些没有payload header的RTP包本身所携带的就是负载数据的分片大小

  • 并不是每个RTP包中都含有payload header, 只有在上面的S位置1且PID=0时才存在header, 也就是每个视频帧的第一个RTP包才存在header

  • 3个通用字节后面的7个字节

  • 3字节起始码 : 0x9d, 0x01, 0x2a

  • 接下来的16位 : 14位表示帧的宽度, 另外2位表示水平范围

  • 最后16位 : 14位表示帧的高度, 另外2位表示垂直范围

综上,VP8判断是否关键帧的逻辑为:

  1. 查找每个RTP种描述符的S位置1 且PID=0的包
  2. 拿到header, 如果P位为0 则为关键帧, P位为1 则为非关键帧