八、H.264中的Slice数据和宏块结构
- Slice Data结构
-
Slice Data:
-
H.264码流中Slice结构的主体部分;
-
Slice Body在Slice中紧跟Slice Header之后;
-
主要结构由连续或间隔的多个宏块结构组成(根据编码器的配置,有些宏块可能采用的是跳过模式,这样的话,某一个或某几个宏块在码流中就没有它的任何数据,完全采用其他宏块的信息就可以将此宏块重建出来,所以不再需要传递这个宏块的数据,选择跳过,可以达到节省码流的目的)
-
slice header占整个slice的结构比较小,更多的是slice body
![](https://img.haomeiwen.com/i4193251/53dc2fe51d0acde4.png)
2.Slice Data结构定义
![](https://img.haomeiwen.com/i4193251/a186b6f9effc28d6.png)
![](https://img.haomeiwen.com/i4193251/725a066c69e84a46.png)
从以上表格得出Slice Data游离出来的语法元素非常少,除了cabac_alignment_one_bit、mb_skip_run、mb_skip_flag、mb_field_decoding_flag、end_of_slice_flag,除此之外Slice Data中的绝大部分数据都保存在宏块结构层macroblock_layer( )中,上面除了按字节对齐的cabac_alignment_one_bit比特位之外,其他的宏块mb_skip_run、mb_skip_flag跳过,场编码标志位mb_field_decoding_flag等都是为宏块结构层macroblock_layer()来服务的。Slice Data结构的主要数据由macroblock宏块来组成的。
-
cabac_alignment_one_bit:
- CABAC(基于上下文自适应的二进制算术编码)设置下,按字节对齐的填充位;(Slice起始位置使用字节对齐,如果没有字节对齐,使用若干个bit将其补充到按字节对齐)
-
mb_skip_run和mb_skip_flag:
- 宏块跳过信息;前者表示CAVLC(基于上下文的可变长度编码)设置下跳过宏块的个数,后者表示CABAC设置下当前宏块跳过的标识位;
-
mb_field_decoding_flag:
- 表示指定宏块使用场编码模式;(整部视频不会出现场编码的内容,现在的情况下不常用,麻烦,一般在老的模拟广播电视节目的时候才会用到场编码的内容,现在的互联网视频,流媒体,安防基本不会出现场编码的情况)
-
end_of_slice_flag
- 帧结尾标识位;(为真slice走到了结尾,采用算术编码来实现ae(v),码流中采用CAVLC时,此语法元素不存在,和mb_skip_flag类似)
以上是Slice Data中除了宏块结构macroblock_layer()之外的主要内容
- H.264的宏块Macroblock
-
宏块(Macroblock):
-
编码视频信息的基本单元;
-
在编码过程中提供了较强的灵活性;(同一帧不同的宏块,预测模式,宏块类型等等,可以采用不同的设置,更灵活的方式取得更高的编码效率)
-
-
一帧(I420)图像划分为多个宏块,每个宏块包含:
-
1个16×16像素的亮度像素块
-
两个8×8像素的色度像素块;
-
![](https://img.haomeiwen.com/i4193251/501f9554ced705ee.png)
上图横排16个亮度像素块,竖排9个亮度像素块
宏块的构成(YUV420,luma是亮度,chroma是色度)
![](https://img.haomeiwen.com/i4193251/48af7f16953d7e7c.png)
4.宏块的类别
-
常用宏块类型:
-
I宏块:采用帧内预测宏块,可能位于I/B/P帧;(B/P帧也可进行帧内预测)
-
P宏块:采用单向帧间预测,只存在于P帧;
-
B宏块:采用双向帧间预测,只存在于B帧;
-
-
根据宏块类型的不同,宏块在码流中采用不同结构的语法元素表示
- 宏块结构的语法元素定义
![](https://img.haomeiwen.com/i4193251/0ad6ca0551f86ab0.png)
![](https://img.haomeiwen.com/i4193251/5ead714d836bfb26.png)
mb_type,表示宏块类型,
当mb_type为I_PCM类型时,以差分的方式传递宏块内部的像素值,传递的是256个亮度pcm_sample_luma[ i ]的采样值,以及根据采样率和分辨率传递的色度pcm_sample_chroma[ i ]的采样值
![](https://img.haomeiwen.com/i4193251/07ae50f402c13547.png)
当mb_type不是I_NxN类型时,分隔模式不是Intra16x16,也就是说不是帧内编码,分割的个数为4的时候,采用的是下面的sub_mb_pred(mb_type)
当为其他情况,对于帧内编码I帧的Slice来说
mb_pred(mb_type)保存宏块的预测信息和预测模式等等
![](https://img.haomeiwen.com/i4193251/2044401e95c04e91.png)
此外宏块结构中还有一个很重要的residual(0,15)残差数据,这一个章节中暂时不会解析残差数据,原因在后面会讲到
在宏块结构中,也只有少部分的游离语法元素
mb_type表示宏块类型,在不同的Slice中代表不同的含义,如果当前帧为I Slice,取值范围为0-25这26个值
![](https://img.haomeiwen.com/i4193251/c79cd5d8a41a1c17.png)
![](https://img.haomeiwen.com/i4193251/963ccd963407d027.png)
mb_type为0时,表示I_NxN模式,其他表示16x16模式,判断mb_type是不是I_PCM时,只需要判断值是否等于25,等于25,表示I_PCM模式主要有三个语法元素
pcm_alignment_zero_bit:按照字节对齐的填充位,根据当前字节对齐情况,没有或不存在或填充若干个0
pcm_sample_luma[ i ]和pcm_sample_chroma[ i ]以差分的方式来传递像素的值
以上主要在帧间编码模式下使用,研究帧间编码时仔细考虑这部分内容
transform_size_8x8_flag:标志位,表示当前宏块是采用8x8大小的变化,还是不采用8x8而采用4x4大小的变换,采用哪种大小的快变换,由此标志位决定,此标志位在下面还会出现一次
![](https://img.haomeiwen.com/i4193251/ffb23611a60b414a.png)
coded_block_pattern:表示当前宏块的编码方式,元素俗称叫做cbp,非常重要的一个语法元素,当前宏块的亮度和色度分量的各个最小块的残差编码方案都由此元素决定,根据这个原色值得不同,有一下几种情况
I.对所有残差都编码
II.只对残差的直流(DC)系数进行编码
III.对残差的直流(DC)和交流(AC)都不进行编码
cbp可以分离出亮度cbp CodedBlockPatternLuma和色度cbp CodedBlockPatternChroma
CodedBlockPatternLuma = coded_block_pattern % 16
CodedBlockPatternChroma = coded_block_pattern / 16
cbp只在模式不是16x16的时候才会存在
因为如果是16x16模式,cbp实际上已经包含在mb_type里面了,根据mb_type的不同,内部隐含了cbp的值
![](https://img.haomeiwen.com/i4193251/dc14f4a7f309a49f.png)
mb_qp_delta:表示当前宏块的量化参数的偏移量,取值范围为-26~25。qp量化参数值得获取,前面pps中,可以获取到整个序列每帧图像的初始量化参数pic_init_qp,pic_init_qp_minus26 + 26可以获取到pic_init_qp表示整个序列每帧图像的初始量化参数
![](https://img.haomeiwen.com/i4193251/1107a471658a35c5.png)
此外在每一帧的Slice Header中,可以找到每帧的slice_qp_delta,只对当前的Slice生效,相当于pps中的pic_init_qp,用pic_init_qp+slice_qp_delta+mb_qp_delta=最终编码宏块实际的量化参数,通过这三个值得到是整个Slice第一个MB的偏移量,后面的偏移量可以和前面这个偏移量的值取和%52 = 后面的qp量化参数
![](https://img.haomeiwen.com/i4193251/33b442d00e393b3c.png)
mb_pred(mb_type):目前处理的是I Slice只需要考虑下面部分内容,主要用于帧内预测结构的主要数据类型
除了intra_chroma_pred_mode帧内预测色度模式外,由两对语法元素值构成,分别带有4x4,8x8的标志,根据不同的transform size选择两种不同的值,同一时刻只能出现一种,不可能同时存在
![](https://img.haomeiwen.com/i4193251/115c1a8b47f149a6.png)
下面部分指的是参考帧的缓存和运动矢量残差,在研究帧间预测的时候再讨论
![](https://img.haomeiwen.com/i4193251/25c48ad480529e1f.png)
residual( 0, 15 ):表示帧内预测的预测残差数据经过变换量化系统来保存在残差的结构中,残差结构如下
![](https://img.haomeiwen.com/i4193251/30aa765e4746eb52.png)
残差数据结构里面根据熵编码算法分别采用了block_cavlc和block_cabac分别用于可变长编码和算术编码,以及亮度的残差化residual_luma( i16x16DClevel, i16x16AClevel, level, level8x8,
startIdx, endIdx )和色度残差化residual_block( ChromaDCLevel[ iCbCr ], 0, 4 * NumC8x8 − 1,
4 * NumC8x8 )
if( !entropy_coding_mode_flag )
residual_block = residual_block_cavlc
else
residual_block = residual_block_cabac
residual_luma:亮度残差部分,根据熵编码的不同采用了cavlc或cabac
if( !entropy_coding_mode_flag )
residual_block = residual_block_cavlc
else
residual_block = residual_block_cabac
![](https://img.haomeiwen.com/i4193251/e27fad06c9a70f9b.png)
CAVLC熵编码结构
coeff_token
trailing_ones_sign_flag
level_prefix
level_suffix
total_zeros
描述编码算法采用的是ce(v),采用的是上下文自适应编码的语法元素
![](https://img.haomeiwen.com/i4193251/02aff10b32ed4aa7.png)
![](https://img.haomeiwen.com/i4193251/501bdfd0a6b0bc84.png)