Vp9解码方式概述 – Parsing Process
本文是对vp9协议第9章,解析字符串函数的一个梳理,主要对几种解析类型(Type)的流程进行梳理
目录
- Vp9解码方式概述 -- Parsing Process
- 1. 如何解码视频?
- 2. f(n)
- 3. 布尔解码器Boolean decoder (read_bool( p ))
- 4. 布尔解码函数read_bool( p )
- 5. B( p )
- 6. L( n )
- 7. T
- 8. 参考资料
1. 如何解码视频?
🍟编码后的视频信息是一长串二进制的字符串,解码时将按照协议第6章的函数进行,黑体加粗(图中红圈所示)表示此时从字符串中读取数据进行解析,解析的值,赋值给该黑体加粗表示的语法元素(padding_bit);而从字符串中读取多少位信息,以及如何对获取的二进制字符串解析,则用不同的Type(图中绿圈所示)来表示。
2. f(n)
🍗f(n)表示直接从字符串中获取n bit,例如f(3),就表示从字符串中直接获取3bit,若获取的是010,那该语法元素解码值就是2;
3. 布尔解码器Boolean decoder (read_bool( p ))
🍖Vp9在解码一个tile前,都会初始化布尔解码器(init_bool(tile_size),tile_size表示解码该tile需要获取的字符串的长度),解码完一个tile后会关闭布尔解码器(exit_bool); Type中的B(n), L(n), T都代表用布尔解码器对视频字符串(码流)进行解码操作;
4. 布尔解码函数read_bool( p )
🍝布尔解码器的核心是read_bool( p )函数。B(n), L(n), T这三种类型的解码,都要调用该函数;其中在init_bool(sz)中会赋给BoolRange(255)和BoolMaxBits (8 * sz – 8), BoolValue(f(8),从码流中读取8bit,赋给BoolValue)的初始值,read_bool( p )函数如下所示:
read_bool(p){
split = 1 + (((BoolRange - 1) * p) >> 8)
if(BoolValue < split)
{
BoolRange = split;
bool = 0;
}
else
{
BoolRange -= split;
BoolValue -= split;
bool = 1;
}
if(BoolRange < 128)
{
if(BoolMaxBits > 0)
{
newBit = f(1);//从码流中获取1bit;
BoolMaxBits -= 1;
}
else{
NewBit = 0;
}
BoolRange = BoolRange *2;
BoolValue = (BoolValue << 1) + newBit;
}
return bool;
}
5. B( p )
🍛用于一些1bit语法元素的解码:B(p) = read_bool( p )
6. L( n )
🍤用于一些已知位宽(nbit)语法元素的解码
L(n){
x = 0;
for(i = 0; i < n; i++){
x = 2 * x + read_bool(128);
}
return x;
}
7. T
🍱T解码是一种依靠各种概率表和树状图的,用于一些不定长度的语法元素的解析。T表示调用多次read_bool§进行解码; 调用多少次,取决于树状表,而每次调用的参数p的值,取决与概率表;
🍣以mv_joint语法元素的解析为例:
- 🍥首先我们要看懂mv_joint对应的树状图(见协议9.3.1 Tree selection process): 前面带-符号的,表示叶子节点,其余为子节点
mv_joint_tree[ 6 ] = {
-MV_JOINT_ZERO, 2,
-MV_JOINT_HNZVZ, 4,
-MV_JOINT_HZVNZ, -MV_JOINT_HNZVNZ
}
-
🍙转换后,树状图为
-
🍘第一次调用read_bool( p ), 解码为0,解码结束,mv_joint = MV_JOINT_ZERO;
解码为1,则 node_tmp = 2(该变量是下一次调用read_bool§时,计算p用的,后面会写),继续解码; -
🍚第二次调用read_bool( p ), 解码为0,解码结束,mv_joint = MV_JOINT_HNZVZ;
解码为1,则 node_tmp = 4, 继续解码; -
🍜第三次调用read_bool( p ), 解码为0,mv_joint = MV_JOINT_HZVNZ;
解码为1,则 mv_joint =MV_JOINT_HNZVNZ , 解码结束;
🍲每次调用read_bool( p )中的参数p的大小都是变化的,p的大小由概率表mv_joint_probs[node] 决定,其中node在一个语法元素的第一次调用时,初始值为0, 之后node = node_tmp/2;
default_mv_joint_probs[ 3 ] = {
32, 64, 96
}
- 🥚第一次调用用的p值为32 (node_tmp = 0, node=0),
- 🍞若继续解码,p = 64(node_tmp = 2, node=1);
- 🍩若继续第三次解码,p=96(node_tmp = 4, node=2);
🍡各个语法元素的概率表在协议第10节(10.5 Default probability tables等) ;
🍢需要注意的是,协议里的概率表是一个初始值,在解码过程中,是会有更新的;参考文章【1】,对vp9的解码过程的框架进行过一次梳理;
8. 参考资料
【1】vp9协议笔记-CSDN博客
【2】vp9协议原文(需加速器访问)