基本信息
- 支持图片格式:YUV420
- 帧种类:I帧, P帧
- 四种参考帧:当前帧(帧内预测),上一帧,golden帧, altref帧。
- 宏块大小:16*16
疑问:golden和altref分别是什么,有什么区别
基本编码流程
- 划分宏块
- 对每个宏块,确定预测方式(用哪个参考帧,预测方式)
- 对每个宏块,根据预测结果,计算残差。对残差进行DCT/WHT变换。
- 对前面的预测信息,残差变换后的信息,进行熵编码
码流格式
三个部分
VP8的码流包含3个或者更多个部分(partition按byte对齐)。
- 未加密数据块:I帧 10byte, P帧 3byte.
- 2个或者更多加密数据块(partitions).
-
第一个partition包括两个部分:
- 适用于整个帧的头信息
- 每个宏块是如何从已重建的数据进行预测的。(解码器要用)
- 后面的partition包括:DCT/WHT的系数。约占整体数据的70%。VP8支持将宏块行中压缩的DCT / WHT系数的数据打包到单独的分区中。如果这种partion个数大于1,除了最后一个以外的size会放在第一个partition之后,每个size3字节。
疑问:如果第二种partition个数大于1,如何确定有多少个?
未加密数据块
-
通用的3byte
- 1bit,帧类型(0:I帧,1:P帧)
- 3bit,version,目前定义了0-3,代表4种不同型,解码复杂度不同。
- 1bit,show_frame(0,不显示,1显示)
- 19bit,第一个partition的大小(bytes)。
version定义:
+---------+-------------------------+-------------+
| Version | Reconstruction Filter | LoopFilter |
+---------+-------------------------+------------+
| 0 | Bicubic | Normal |
| | | |
| 1 | Bilinear | Simple |
| | | |
| 2 | Bilinear | None |
| | | |
| 3 | None | None |
| | | |
| Other | Reserved for future use | |
+---------+-------------------------+-------------+
- I帧的7byte
Start code byte 0 0x9d
Start code byte 1 0x01
Start code byte 2 0x2a
16 bits : (2 bits Horizontal Scale << 14) | Width (14 bits)
16 bits : (2 bits Vertical Scale << 14) | Height (14 bits)
scaleType:VP8的编码,在内部可能缩放图片。
+-------+--------------------------------------+
| Value | Scaling |
+-------+--------------------------------------+
| 0 | No upscaling (the most common case). |
| | |
| 1 | Upscale by 5/4. |
| | |
| 2 | Upscale by 5/3. |
| | |
| 3 | Upscale by 2. |
+-------+--------------------------------------+
RTP封装VP8格式
整体结构
如图是每一帧的第一个包的格式,如果是帧的后续包,没有payload Header
.Marker bit(M)
:每帧的最后一个包设置为1,表示这一帧结束了,可以开始解码。不然就得等下一帧来了,才知道上一帧结束了。Payload type(PT)
:负载类型。Timestamp
:该帧的采样时间。不是真实时间(貌似单位是1/90000s)。
疑问:负载类型有统一定义吗,还是自定义?
疑问:timestamp的单位是啥
Payload Descriptor
结构如下(左右两图结构一样,只有PictureID长度不同)
必选
X
:扩展控制位。如果为1,结构如图。如果为0,途中optional的行都没有。R
:保留位,必须设置为0.N
:不被参考的帧。1表示丢了这帧,不影响其他帧的解码。如果不清楚,设置0.S
:标识一个VP8 partition的开始。如果payload的第一个字节是一个新的VP8 partition的开始,则设为1.每帧的第一个包必须设置为1.PID
: Partition index.每帧的第一个partition必须是0.每个partition增加1,或者全保持为0.PID不超过7.如果多个包包含同一个PID,则除了第一个,其他的S位设置为0.
可选
X
为1时,有以下部分:
I: PictureID 控制。如果设置为1,有图中I行。
L: TL0PICIDX 控制。如果设置为1,有图中L行。并且T必须设置为1.
T: TID 控制。如果设置为1,有T/K行。
K: KeyIDX 控制。如果设置为1,有T/K行。
RSV: 保留位。
M
:1,PictureID长度15位(上右图),0,PictureID长度7位(上左图)。PictureID
:标识帧,随机值开始,每帧增加1。到达最大值后,回到0.(不要假设PictureID的长度保持不变)TL0PICIDX
:(没看懂)TID
:(没看懂)2bit,Temporal-layer index.如果T为0,必须被忽略。Y
:(没看懂)1layer sync bit.KeyIDX
:5bit,temporal key frame index.如果K为0,必须被忽略。开始于随机值,最大值31,达到最大值后变为0.关键帧如果改变了对后续解码很关键的参数信息,则+1,未改变参数的关键帧和非关键帧保持和前面的关键帧相同。如果收到一个P帧,而相同KeyIDX的关键帧没有收到,则不应该解码。如果不确定是否改变了关键信息,可以把关键帧都+1.或者把K设置为0。
疑问:base layer是啥,TID是啥?可能需要阅读更多的RFC6386.
VP8 payload Header
是VP8压缩数据的未压缩数据部分。前3个字节是I帧P帧通用的。I帧后7个字节被认为是payload的其他部分。
payload header只存在于S位为1,且PID为0的包。
疑问:第一字节的顺序和vp8编解码里介绍的是反的,为啥?
VP8 payload
VP8编码数据
封包说明
- RTP封包的时候,可以考虑VP8的partition边界,也可以不考虑。
- 如果不考虑,则所有一个包可以包含多个partition,PID全为0.
- 如果考虑,则一个包只能包含一个parition的片段,每个partition的包PID递增。
Optional RTP padding
RTP头的P为1才有这部分。
第一次完整阅读RFC文档,读后感
要在视频通话中使用VP8,需要阅读的RFC文档有两个。
一个是VP8的数据格式及编解码说明文档,另一个是如何在RTP中存放VP8格式码流的文档。编解码说明文档比较难,也比较多,只是使用的话,不用全部看(300页全英文呢)。RTP封装就简单一些,也少多了,应该全看。
文档很详细,有例子,甚至代码,对理解非常有帮助。
不过我并没有全部理解,能记下来的也不多,也许也不需要全部记,以后应该还需要再看。
感觉还是很有成就感的。^_^,再接再厉。
- 参考资料:
RFC6386:VP8 Data Format and Decoding Guide
RFC7741:RTP Payload Format for VP8 Video
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。