H264-CAVLC(基于上下文可变长度编码)

H264-CAVLC(基于上下文可变长度编码)

在这里插入图片描述

CAVLC 是用来编码残差系数的,它充分利用了变换量化后系数的特性。

cavlc 编码语法

其中ce(v)表示使用的基于上下文的可变长度的熵编码

在这里插入图片描述

在这里插入图片描述

分析过程

  1. 所有的传输系数幅度值coeffLevel[ i ],都初始化为0,i 从0 到maxNumCoff-1
  2. 非零系数的数目TotalCoeff(coeff_token)和拖尾系数数目TrailingOnes(coeff_token)使用过分析coeff_token获得的
  3. 接下来的步骤:
    - 如果非零系数为0,直接退出,下边的操作不再进行。
    - 如果非零系数大于0,
    a. 非零系数的大小通过分析trailing_ones_sign_flag, level_prefix和level_suffix获得。
    b. 在每个非零系数前的0系数通过分析total_zeros和run_before获得。

编码非零系数和拖尾系数(coeff token)

coeff_token 编码了非零系数的数目(total-coeffs)和拖尾系数数目(T1),Total-coeffs的取值为0~16,T1的取值为0-3。如果末尾有超过3个+1/-1,则拖尾系数做多有3个,其他的当做普通系数处理。对于亮度block 共有4种表格可供选择,3个变长编码表和一个定长编码表。这些表格对(TotalCoeff, TrailingOnes) 数据对进行了编码。block左边nA和上边nB的block的非零系数的数目决定选择哪个编码表。由nA和nB计算获得nC,nC的取值决定选择哪个table。nC的映射关系如下表:

在这里插入图片描述
nC的计算:

  1. 如果左边和上边都可用,nC = (nA + nB)>> 2
  2. 如果左边可用,nC= nA
  3. 如果上边可用,nC = nB
  4. 如果都不可用,nC= 0
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

分析level 信息

处理拖尾系数的符号

逆序表示拖尾系数的符号,0表示+,1表示-
过程:
将index i初始化为0,当TrailingOnes(coeff_token)不等于0时,接下来的步骤会重复TrailingOnes(coeff_token)次来解码拖尾系数的符号:
-1bit 语法单元trailing_ones_sign_flag 如果是0 LevelVal[i] 被设置为1
- 否则LevelVal[i] 被设置0
index 加1.

编码剩余非零系数

level表示非零系数的符号和幅度,是以逆序进行编码,从高频系数向低频系数进行。
suffixLength 根据以下原则初始化:

  • 如果TotalCoeff(coeff_token)大于10并且TrailingOnes(coeff_token)小于3, suffixlength设置为1.
  • 否则TotalCoeff(coeff_token)小于等于10或者TrailingOnes等于3,suffixlength设置为0

接下来,当TotalCoeff(coeff_token) - TrailingOnes(coeff_token)不为0时,接下来的步骤重复TotalCoeff(coeff_token)-TrailingOnes(coeff_token)次来解码剩余的非零系数的level值:
1. 解码语法元素level_prefix
2. 如果level_prefix等于14并且suffixlength等于0,levelSuffixSize等于4
否则,如果level_prefix大于或者等于15,levelSuffixSzie 设置为level_prefix-3
否则,levelSuffixSize设置为suffixLength
3. 语法元素level_suffix按照如下方式解码:
a. 如果levelSuffixSize大于0,语法元素level_suffix解码为无符号整数u(v), bit长度为levelSuffixSize
b. levelSuffixSize为0,语法元素level_suffix置为0
4. levelCode 设置为(Min(15, level_prefix) << suffixLength) + level_suffix
5. 当level_prefix大于或者等于15 并且suffixlength等于0,levelCode 增加15
6. 当level_prefix 大于或者等于16,levelCode增加(1 <<(level_prefix -3)) -4096
7. 当index i 等于TrailingOnes(coeff_token)并且TrailingOnes(coeff_token)小于3时,levelcode增加2
8. 变量levelVal[i] 由下面的步骤导出:
- 如果levelCode是偶数,levelVal[i] 设置为(levelCode + 2) >> 1
- 如果levelCode是奇数,levelVal[i]设置为(-levelCode -1) >> 1
9. 当suffixLength等于0, suffixLength设置为1
10. 当levelVal[i]的绝对值大于(3<<(suffixLength-1))并且suffixLength小于6,suffixLength增加1
11. index i 增加1
下边是suffixlength的增加门限表。
在这里插入图片描述

level_prefix 的处理

level_prefix 是前缀码,从当前位置开始读取位置开始直到第一个非零bit位结束(包括此非零bit),计算前缀0的数目即为level_prefix的值。如下代码所示

leadingZeroBits =1 
for( b = 0; !b; leadingZeroBits++ ) 
	b = read_bits( 1 ) 
level_prefix = leadingZeroBits

在这里插入图片描述
在Baseline, Constrained Baseline,Main和Extended profiles中,level_prefix的值不能超过15。

处理total_zeros

total_zeros表示最后一个非零系数之前的0的数目。
变量zeroleft由下面的过程得到:

  1. 如果非零传输系数TotalCoeff(coeff_token)等于最大传输系数数目maxNumCoeff,zeroleft设置为0.
  2. 否则即有为0的系数时,解码total_zeros, zerosleft设置为total_zeros的值。
    变量tzVlcIndex设置为TotalCoeff(coeff_token)
    解码total_zeros的由下边的过程完成:
    -如果maxNumCoeff等于4,使用下表解码total_zeros
    在这里插入图片描述
    -否则,如果MaxNumCoeff等于8,使用下表解码total_zeros
    在这里插入图片描述
            -否则MaxNumCoeff不等于4并且不等于8,使用下面的解码表:
    在这里插入图片描述
    在这里插入图片描述
处理run_before

run_before表示每一个非零系数到下一个非零之间0的个数。runVal[i]使每个非零数前0的个数。接下来的步骤重复TotalCoeff(coeff_token) - 1次:

  1. 变量runVal[i]由下面进行推导:
            - 如果zeros_left大于零,run_before根据下表解码
    在这里插入图片描述
            -否则(zerosleft等于0),runVal[i] 置为0
  2. zerosleft 中减去runVal[i],它的结果赋值给zerosleft。
  3. index i 增加1

最后zerosleft的值赋值给runVal[i]

根据runval填充level
coeffNum =1
for( i = TotalCoeff( coeff_token )1; i >= 0; i− − ) {
coeffNum += runVal[ i ] + 1
coeffLevel[ startIdx + coeffNum ] = levelVal[ i ]
}

例1

[ 0 3 − 1 0 0 − 1 1 0 1 0 0 0 0 0 0 0 ] \begin{bmatrix} 0&3&-1&0\\ 0&-1&1&0\\ 1&0&0&0\\ 0&0&0&0 \end{bmatrix} 0010310011000000
zigzag排序后获得0,3,0,1,-1,-1,0,1,0,0,0,0,0,0,0,0
在这里插入图片描述
有TotalCoeffs=5,Totalzeros = 3, TrailingOnes = 3 分别是最后的(1, -1, -1)
T1 sign(N) 表示取拖尾系数的符号,N表示第N个非零系数
level(N)表示非零系数的level,N表示第N个非零系数
编码:

元素码字备注
coeff_token(5, 3)0000 100查找表格(假设nC=0)
T1 sign (4)10
T1 sign (3)-11
T1 sign (2)-11
Level (1)+1 (level prefix = 1; suffixLength = 0)1suffixlength的增加是后判定
if val > 0
levelval = val * 2 -2
else
levelval = -(val * 2 ) -1
当拖尾系数小于3,第一个非拖尾系数levelval -=2
level_prefix_temp = levelval >>suffix_length
level_suffix = levelval & (2suffix_length-1)最后根据level_prefix_temp查level_prefix表获得
Level (0)+3 (level prefix = 001, suffixLength = 1)0010根据suffixlength增加的判定,suffixlength++
得到level_prefix_temp = 2,level_suffix = 0, level_prefix_temp查表得到level_prefix码字为001
TotalZeros3111最后一个非零系数之前的0的个数为3,非零系数总数为5,查表得到编码111
run before(4)ZerosLeft = 3; run before =110查表获取编码
run before(3)ZerosLeft = 2; run before =01*
run before(2)ZerosLeft = 2; run before =01*
run before(1)ZerosLeft = 2; run before =101*
run before(0)ZerosLeft = 1; run before =01不需要编码

获得的编码为:0000100011100101111011011
解码:

码字元素输出序列备注
0000100coeff_token(5,3)
0T1 sign+1
1T1 sign--1,1
1T1 sign--1,-1,1
1level(1)11,-1,-1,1suffix_length初始化为0,level_prefix = 1,查表得到level_prefix_tmp = 0
level_val = level_prefix_temp << suffix_length + level_suffix
if (level_val %2 == 0)
level = (levelval + 2) >> 1
else
level = (-levelval-1) >> 1
0010level(0)33,1,-1,-1,1suffix_length =1, level_prefix = 001, 查表得到level_prefix_temp = 2, 最后得到level = 3
10run_before(4)03,1,-1,-1,0,1解码之前zeros_left= 3
1run_before(3)03,1,-1,-1,0,1解码之前zeros_left= 2
1run_before(2)03,1,-1,-1,0,1解码之前zeros_left= 2
01run_before(1)13,0,1,-1,-1,0,1解码之前zeros_left= 2
1run_before(0)10,3,0,1,-1,-1,0,1解码之前zeros_left= 1

最后得到的矩阵zigzag序列0,3,0,1,-1,-1,0,1

例2

[ − 2 4 0 − 1 3 0 0 0 − 3 0 0 0 0 0 0 0 ] \begin{bmatrix} -2&4&0&-1\\ 3&0&0&0\\ -3&0&0&0\\ 0&0&0&0 \end{bmatrix} 2330400000001000
zigzag排序后获得-2,4,3,-3,0,0,-1,0,0,0,0,0,0,0,0,0,0
在这里插入图片描述
有TotalCoeffs=5,Totalzeros = 2, TrailingOnes = 1 是最后的 -1
编码:

元素码字备注
coeff_token(5, 1)0000 000110查找表格(假设nC=0)
T1 sign (4)-11
level(3)-3(level prefix = 0000 0001; suffixLength = 0)0001
level (2)3(level prefix = 001; suffixLength = 1)0010
Level (1)4 (level prefix = 0001; suffixLength = 1)00010if val > 0
levelval = val * 2 -2
else
levelval = -(val * 2 ) -1
当拖尾系数小于3,第一个非拖尾系数levelval -=2
level_prefix_temp = levelval >>suffix_length
level_suffix = levelval & (2suffix_length-1)最后根据level_prefix_temp查level_prefix表获得
Level (0)-2 (level prefix = 1, suffixLength = 2)111根据suffixlength增加的判定,suffixlength++
TotalZeros20011
run before(4)ZerosLeft = 2; run before =200查表获取编码
run before(3)ZerosLeft = 0; run before =0不需要编码

获得的编码为:000000011010001001000010111001100
解码

码字元素输出序列备注
0000 000110coeff_token(5,1)
1T1 sign--1
0001level(3)-3-3,1suffix_length初始化为0,level_prefix = 0001,查表得到level_prefix_tmp = 3
level_val = level_prefix_temp << suffix_length + level_suffix
当拖尾系数数目小于3,第一个非拖尾系数level_val +=2
if (level_val %2 == 0)
level = (levelval + 2) >> 1
else
level = (-levelval-1) >> 1
0010level(2)33,-3,1suffix_length = 1 , level_prefix = 001, level_suffix=0,得到level = 3
00010level(1)44,3,-3,1suffix_length = 1,level_prefix = 0001, level_suffix = 0,得到level=4
111level(0)-2-2,4,3,-3,1suffix_length =2, level_prefix =1, level_suffix=3,得到level= -2
0011TotalZeros2-2,4,3,-3,1
00run_before(4)2-2,4,3,-3,0,0,1解码之前zeros_left= 2
run_before(3~0)-2,4,3,-3, 0,0,1解码之前zeros_left= 0

最后得到的矩阵zigzag序列-2,4,3,-3,0,0,-1

cavlc编码matlab 代码

function [bits] = enc_cavlc(data, nL, nU)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This script/function was created by 
% Abdullah Al Muhit
% contact - almuhit@gmail.com
% website - https://sites.google.com/site/almuhit/
% Please use it at your own risk. Also, Please cite the following paper:
% A A Muhit, M R Pickering, M R Frater and J F Arnold, 揤ideo Coding using Elastic Motion Model and Larger Blocks,�IEEE Trans. Circ. And Syst. for Video Technology, vol. 20, no. 5, pp. 661-672, 2010. [Impact factor �3.18] [PDF]
% A A Muhit, M R Pickering, M R Frater and J F Arnold, 揤ideo Coding using Geometry Partitioning and an Elastic Motion Model,�accepted for publication in Journal of Visual Communication and Image Representation. [Impact factor �1.33] [PDF]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% CAVLC Encoder. 
% takes in 4x4 block of residual data and produces output bits

% load table.mat;
%使用到的码表
global Table_coeff0 Table_coeff1 Table_coeff2 Table_coeff3
global Table_run Table_zeros
%返回的二进制串
bits = '';

% Convert 4x4 matrix data into a 1x16 data of zig-zag scan
%获取输入数据的维度
[row, col] = size(data);

% check the correct size of the block
if((row~=4)||(col~=4))
    disp('Residual block size mismatch - exit from CAVLC')
    return;
end
%zigzag排列的矩阵元素下标矩阵,16*2
scan = [1,1;1,2;2,1;3,1;2,2;1,3;1,4;2,3;3,2;4,1;4,2;3,3;2,4;3,4;4,3;4,4];
%按zigzag顺序排列输入矩阵到l
for i=1:16
   m=scan(i,1);
   n=scan(i,2);
   l(i)=data(m,n); % l contains the reordered data
end

i_last = 16;
% find the last non-zero co-eff in reverse order
while ((i_last>0)&(l(i_last)==0))
   i_last = i_last - 1; 
end

i_total = 0; % Total non zero coefficients
i_total_zero = 0; % Total zeros
i_trailing = 0;
sign = ''; % find sign for trailing ones
idx = 1;

%% find level, trailing ones(sign), run and total zero values
while ((i_last>0)&(abs(l(i_last))==1)&(i_trailing<3))
    level(idx)=l(i_last);
    i_total = i_total + 1;
    i_trailing = i_trailing + 1;
    
    if l(i_last)==-1
        sign = [sign '1'];
    else 
        sign = [sign '0'];
    end
    
    run(idx) = 0;    
    i_last = i_last - 1;
    while ((i_last>0)&(l(i_last)==0))
        run(idx) = run(idx) + 1;
        i_total_zero = i_total_zero + 1;
        i_last = i_last - 1; 
    end
    idx = idx + 1;
    
end

while (i_last>0)
    level(idx)=l(i_last);
    i_total = i_total + 1;
    
    
    run(idx) = 0;    
    i_last = i_last - 1;
    while ((i_last>0)&(l(i_last)==0))
        run(idx) = run(idx) + 1;
        i_total_zero = i_total_zero + 1;
        i_last = i_last - 1; 
    end
    idx = idx + 1;
    
end

%% Write coeff_token
%根据参数计算nC
% find n parameter (context adaptive)
if (nL>0)&(nU>0)
    n = (nL + nU)/2;
elseif (nL>0)|(nU>0)
    n = nL + nU;
else
    n = 0;
end

% Coeff_token mapping
% Rows are the total coefficient(0-16) and columns are the trailing ones(0-3)
% TABLE_COEFF0,1,2,3 ARE STORED IN TABLE.MAT OR CAVLC_TABLES.M FILE
% Choose proper table_coeff based on n value
if 0<=n<2
    Table_coeff = Table_coeff0;
elseif 2<=n<4
    Table_coeff = Table_coeff1;
elseif 4<=n<8
    Table_coeff = Table_coeff2;
elseif 8<=n
    Table_coeff = Table_coeff3;
end

% Assign coeff_token and append it to output bits
% Here coeff_token is cell array so needs to be coverted to char
coeff_token = Table_coeff(i_total + 1,i_trailing + 1);
bits = [bits char(coeff_token)];

% If the total coefficients == 0 exit from this function
if i_total==0
    return;
end

% Append sign of trailing ones to bits
if i_trailing>0
    bits = [bits sign];
end

%% Encode the levels of remaining non-zero coefficients

% find the suffix length
if (i_total>10)&(i_trailing<3)
   i_sufx_len = 1;
else
   i_sufx_len = 0;
end

% loop
for i=(i_trailing + 1):i_total
    
    if level(i)<0
        i_level_code = -2*level(i) - 1;
    else
        i_level_code = 2*level(i) - 2;
    end
    
    if (i == i_trailing + 1)&(i_trailing<3)
       i_level_code = i_level_code - 2; 
    end
    
    if bitshift(i_level_code,-i_sufx_len)<14
        level_prfx = bitshift(i_level_code,-i_sufx_len);
        while(level_prfx>0)
            bits = [bits '0'];
            level_prfx = level_prfx - 1;
        end
        bits = [bits '1'];
        
        if i_sufx_len>0 
            level_sufx = dec2bin(i_level_code,i_sufx_len);
            x = length(level_sufx);
            if x>i_sufx_len
                level_sufx = level_sufx(x-i_sufx_len+1:x);
            end
            bits = [bits level_sufx];
        end
    elseif (i_sufx_len==0)&(i_level_code<30)
       level_prfx = 14;
       while(level_prfx>0)
            bits = [bits '0'];
            level_prfx = level_prfx - 1;
        end
        bits = [bits '1'];
        
       level_sufx = dec2bin(i_level_code-14,4);
       x = length(level_sufx);
            if x>4
                level_sufx = level_sufx(x-4+1:x);
            end
       bits = [bits level_sufx];
    
    elseif (i_sufx_len>0)&(bitshift(i_level_code,-i_sufx_len)==14)
        level_prfx = 14;
       while(level_prfx>0)
            bits = [bits '0'];
            level_prfx = level_prfx - 1;
        end
        bits = [bits '1'];
        
        level_sufx = dec2bin(i_level_code,i_sufx_len);
        x = length(level_sufx);
            if x>i_sufx_len
                level_sufx = level_sufx(x-i_sufx_len+1:x);
            end
        bits = [bits level_sufx];
    else
        level_prfx = 15;
       while(level_prfx>0)
            bits = [bits '0'];
            level_prfx = level_prfx - 1;
        end
        bits = [bits '1'];
        
        i_level_code = i_level_code - bitshift(15,i_sufx_len);
        
        if i_sufx_len==0
           i_level_code = i_level_code - 15; 
        end
        
        if (i_level_code>=bitshift(1,12))|(i_level_code<0)
            disp('Overflow occured');
        end
        
        level_sufx = dec2bin(i_level_code,12);
        x = length(level_sufx);
            if x>12
                level_sufx = level_sufx(x-12+1:x);
            end
        bits = [bits level_sufx];
    end
    
    if i_sufx_len==0
        i_sufx_len = i_sufx_len + 1;
    end
    if ((abs(level(i)))>bitshift(3,i_sufx_len - 1))&(i_sufx_len<6)
        i_sufx_len = i_sufx_len + 1;
    end

end

%% Encode Total zeros

% Here Rows(1-16) are Total coefficient and colums(0-15) are total zeros
% Rearranged from the standard for simplicity
% Table_zeros is located in table.mat or cavlc_tables.m file
            
if i_total<16
    total_zeros = Table_zeros(i_total,i_total_zero + 1);
    bits = [bits char(total_zeros)];
end

%% Encode each run of zeros
% Rows are the run before, and columns are zeros left
% Table_run is located in table.mat or cavlc_tables.m file

i_zero_left = i_total_zero;
 if i_zero_left>=1   
    for i=1:i_total
       if (i_zero_left>0)&(i==i_total)
           break;
       end
       if i_zero_left>=1 
           i_zl = min(i_zero_left,7);
           run_before = Table_run(1 + run(i),i_zl);
           bits = [bits char(run_before)];
           i_zero_left = i_zero_left - run(i);
       end
    end
 end
 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值