同序列參數集SPS一樣,圖像參數集PPS在解碼的過程中,也将起到至關重要的作用。我們已經知道,在h264的句法元素分層結構上,由片引用PPS,PPS再引用SPS,進而得到解碼所需的全部句法元素。
PPS同SPS一樣,也是從一段視訊序列的基礎上,抽取出大部分公共編解碼資訊,進而形成的SPS和PPS。是以呢,我們接下來就會感受到,PPS裡的句法元素的語義,也是作用在視訊序列上的。
因為SPS和PPS是h264碼流中最重要的兩個NAL單元,是以它們通常位于碼流的最前面,也即碼流開頭的兩個NALU,第一個是SPS,第二個就是PPS。是以由前面可知,當從碼流中解析到第二個NALU時,它的nal_unit_type的值應為8。
同樣根據h264協定文檔7.4.1節可知,PPS的RBSP資料的元素構成,可參考pic_parameter_set_rbsp()部分,也即7.3.2.2節。

1、PPS的句法結構
在7.3.2.2節規定了PPS的RBSP句法,不過與SPS不同,PPS在文檔裡,并沒有顯式的分為pic_parameter_set_data()和rbsp_trailing_bits() 。不過我們友善起見,可以在心裡默默的将它劃分為兩大類:
pic_parameter_set_rbsp() {
pic_parameter_set_data();
rbsp_trailing_bits();
}
其中的pic_parameter_set_data()也即包含在RBSP中的SODB部分,所有編解碼所需的句法元素都在裡面。下面我們忽略rbsp_trailing_bits(),來簡單看一下pic_parameter_set_rbsp()中句法元素所具有的功能。
1.1 pic_parameter_set_rbsp()結構
如7.3.2.2節所示的一樣,裡面的句法元素很多,它們的功能如下:
pic_parameter_set_rbsp() {
// 1. pps_id(唯一辨別這個pps)和sps_id(這個pps引用的sps的id),
// 2. 熵編碼flag,采用的是CAVLC還是CABAC
// 3. 計算poc所需句法元素
// 4. FMO相關
// 5. 參考圖像清單相關
// 6. 權重預測
// 7. 量化相關
// 8. DCT相關
// 9. scaling_list相關
}
因為更接近片層,是以PPS所表現出的功能,相對SPS來說也更具體。像熵編碼模式、FMO等這些呢,PPS裡都能描述到。不過也正因如此呢,要了解PPS裡的句法元素的語義,也需要更寬廣的知識面,需要對h264的編解碼流程較為熟悉。
但是呢,即使我們現在對CAVLC、CABAC、POC、FMO、參考圖像清單、預測、量化、DCT等這些重要的知識點不太了解,我們也不用灰心。因為這些以後都會詳細講到,在這裡呢,我們隻需知道,這幾項的編解碼所用到的句法元素,在PPS裡都有涉及。在後面深入學習各知識點的時候,再對照PPS裡的句法元素前來查閱即可。
我們先将上述的幾個功能,對照pic_parameter_set_rbsp()的句法元素進行劃分如下:
pic_parameter_set_rbsp( ) {
/* —————————— pps_id、sps_id Start —————————— */
pic_parameter_set_id
seq_parameter_set_id
/* —————————— pps_id、sps_id End —————————— */
entropy_coding_mode_flag // 熵編碼
bottom_field_pic_order_in_frame_present_flag // POC
/* —————————— FMO相關 Start —————————— */
num_slice_groups_minus1
if( num_slice_groups_minus1 > 0 ) {
slice_group_map_type
if( slice_group_map_type = = 0 )
for( iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++ )
run_length_minus1[ iGroup ]
else if( slice_group_map_type = = 2 )
for( iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++ ) {
top_left[ iGroup ]
bottom_right[ iGroup ]
}
else if( slice_group_map_type = = 3 | |
slice_group_map_type = = 4 | |
slice_group_map_type = = 5 ) {
slice_group_change_direction_flag
slice_group_change_rate_minus1
} else if( slice_group_map_type = = 6 ) {
pic_size_in_map_units_minus1
for( i = 0; i <= pic_size_in_map_units_minus1; i++ )
slice_group_id[ i ]
}
}
/* —————————— FMO相關 End —————————— */
/* —————————— 參考圖像清單 Start —————————— */
num_ref_idx_l0_default_active_minus1
num_ref_idx_l1_default_active_minus1
/* —————————— 參考圖像清單 End —————————— */
/* —————————— 權重預測 Start —————————— */
weighted_pred_flag
weighted_bipred_idc
/* —————————— 權重預測 End —————————— */
/* —————————— 量化 Start —————————— */
pic_init_qp_minus26 /* relative to 26 */
pic_init_qs_minus26 /* relative to 26 */
chroma_qp_index_offset
/* —————————— 量化 End —————————— */
deblocking_filter_control_present_flag
constrained_intra_pred_flag
redundant_pic_cnt_present_flag
if( more_rbsp_data( ) ) {
// DCT變換
transform_8x8_mode_flag
/* —————————— Scaling_list Start —————————— */
pic_scaling_matrix_present_flag
if( pic_scaling_matrix_present_flag )
for( i = 0; i < 6 +
( ( chroma_format_idc != 3 ) ? 2 : 6 ) * transform_8x8_mode_flag;
i++ ) {
pic_scaling_list_present_flag[ i ]
if( pic_scaling_list_present_flag[ i ] )
if( i < 6 )
scaling_list( ScalingList4x4[ i ], 16,
UseDefaultScalingMatrix4x4Flag[ i ] )
else
scaling_list( ScalingList8x8[ i − 6 ], 64,
UseDefaultScalingMatrix8x8Flag[ i − 6 ] )
}
/* —————————— Scaling_list End —————————— */
second_chroma_qp_index_offset
}
rbsp_trailing_bits( )
}
2、PPS語義
詳細語義如下:
pic_parameter_set_rbsp( ) {
/* —————————— pps_id、sps_id Start —————————— */
// 唯一辨別這個pps,供片頭引用使用
pic_parameter_set_id
// 本圖像參數集所引用的序列參數集的id
seq_parameter_set_id
/* —————————— pps_id、sps_id End —————————— */
/*
在講描述子時,曾提到這個文法元素。它用于指定文法元素的熵編碼方式,
當entropy_coding_mode_flag為0時,表示熵編碼使用CAVLC,解析文法元素時使用左邊的描述子
當entropy_coding_mode_flag為1時,表示熵編碼使用CABAC,解析文法元素時使用右邊的描述子
*/
entropy_coding_mode_flag
/*
PPS裡唯一一個與計算POC相關的句法元素,用于控制在slice_header中,是否有用于計算底場POC的句法元素出現
*/
bottom_field_pic_order_in_frame_present_flag
/* —————————— FMO相關 Start —————————— */
/*
這個句法元素加1,用于表明圖像中的片組個數。h264沒有專門的句法元素表明是否使用FMO。是以
當num_slice_groups_minus1 等于 0時,表示隻有1個片組,也即不使用FMO
當num_slice_groups_minus1大于0時,即表示使用FMO,這時後面會有用于計算片組映射的其他句法元素
*/
num_slice_groups_minus1
if( num_slice_groups_minus1 > 0 ) {
/*
指定FMO的映射模式,取值為[0, 6],0~6的每個值都對應一種映射模式,我們曾在【H.264/AVC 的分層結構與畫面劃分】裡講過。不過
聯系到句法元素,更具體的還需要另行介紹,後面視情形可能會單獨開一篇再次介紹FMO
*/
slice_group_map_type
if( slice_group_map_type = = 0 )
for( iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++ )
/*
當映射模式為0時,需要參數的句法元素,表示每個片組連續的map_units數目。取值範圍為[0, PicSizeInMapUnits-1]
*/
run_length_minus1[ iGroup ]
else if( slice_group_map_type = = 2 )
/*
當映射模式為0時,需要參數的句法元素,top_left[ i ] 和 bottom_right[ i ] 分别表示一個矩形的左上角和右下角。
*/
for( iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++ ) {
top_left[ iGroup ]
bottom_right[ iGroup ]
}
else if( slice_group_map_type = = 3 | |
slice_group_map_type = = 4 | |
slice_group_map_type = = 5 ) {
/*
通常與slice_group_change_rate_minus1一起,用來表示當slice_group_map_type為3、4、5時精确的映射類型。
*/
slice_group_change_direction_flag
/*
slice_group_change_rate_minus1用來指定
SliceGroupChangeRate的值,它表示一個片組的大小,
從一個圖像到下一個圖像的改變的倍數,以map_units為
機關。取值範圍為[0, PicSizeInMapUnits-1]
*/
slice_group_change_rate_minus1
} else if( slice_group_map_type = = 6 ) {
/*
用于指明當slice_group_map_type等于6時,圖像以map_units為機關的大小
*/
pic_size_in_map_units_minus1
for( i = 0; i <= pic_size_in_map_units_minus1; i++ )
/*
用于指明當slice_group_map_type等于6時,某個map_units屬于哪個片組
*/
slice_group_id[ i ]
}
}
/* —————————— FMO相關 End —————————— */
/* —————————— 參考圖像清單 Start —————————— */
/*
加1後表明參考圖像清單0的最大參考索引号,這個句法元素是針對幀宏塊
來說的,比如假設編碼模式為宏塊級别的幀場自适應,那麼幀場自适應下
的幀宏塊解碼的最大索引值就是
num_ref_idx_l0_default_active_minus1,而
2*num_ref_idx_l0_default_active_minus1+1是場宏塊解碼的最
大索引值。num_ref_idx_l0_default_active_minus1的取值範圍
為:[0, 31]
*/
num_ref_idx_l0_default_active_minus1
/*
和num_ref_idx_l0_default_active_minus1具有同樣的定義,
隻不過這個是用來描述清單1的
*/
num_ref_idx_l1_default_active_minus1
/* —————————— 參考圖像清單 End —————————— */
/* —————————— 權重預測 Start —————————— */
/*
表示P和SP片是否應該使用權重預測,等于0表示不應使用,等于1表
示應使用。
*/
weighted_pred_flag
/*
取值[0, 2]
等于0表示B片應該采取預設的權重預測
等于1表示B片應使用顯式的權重預測
等于2表示B片應使用隐式的權重預測
*/
weighted_bipred_idc
/* —————————— 權重預測 End —————————— */
/* —————————— 量化 Start —————————— */
/*
取值[-26, 25]
加26後表示每個片的亮度分量的量化參數的初始值,在片頭和宏塊
中,進一步會有額外的量化參數給出,幾個量化參數一起決定真正的
量化值
*/
pic_init_qp_minus26 /* relative to 26 */
/*
與pic_init_qp_minus26的語義一緻,隻不過作用于SI和SP片。
*/
pic_init_qs_minus26 /* relative to 26 */
/*
取值[-12, 12]
用于計算色度分量的量化參數,需要注意的時,計算時需要結合亮度
分量的量化參數
*/
chroma_qp_index_offset
/* —————————— 量化 End —————————— */
/*
用于表示,是否有控制去塊濾波強度的文法元素值,在片頭出現。
如果deblocking_filter_control_present_flag等于1, 表
示編碼器已經設定了去塊濾波強度,也即片頭中句法元素的值
如果deblocking_filter_control_present_flag等于0,表示
編碼器沒有設定,那麼解碼器就要獨立計算出去塊濾波強度
*/
deblocking_filter_control_present_flag
/*
在P和B片中,當宏塊進行幀内編碼時,它的鄰近宏塊可能采用的是幀
間編碼。
那麼當constrained_intra_pred_flag等于1時,表示幀内編碼的
宏塊,不能使用幀間編碼的宏塊的像素值作為自己的預測值,也就是
它隻能使用鄰近幀内編碼的宏塊的像素值作為自己的預測
當constrained_intra_pred_flag等于0時,表示不存在這種限制
*/
constrained_intra_pred_flag
/*
用于控制是否顯示redundant_pic_cnt
*/
redundant_pic_cnt_present_flag
if( more_rbsp_data( ) ) {
/*
等于1表示目前亮度宏塊使用的是8x8的DCT變換
等于0表示目前亮度宏塊沒有使用8x8的DCT變換
*/
transform_8x8_mode_flag
/* —————————— Scaling_list Start —————————— */
/*
用于表示是否存在縮放比例清單Scaling_list
*/
pic_scaling_matrix_present_flag
if( pic_scaling_matrix_present_flag )
for( i = 0; i < 6 +
( ( chroma_format_idc != 3 ) ? 2 : 6 ) * transform_8x8_mode_flag;
i++ ) {
pic_scaling_list_present_flag[ i ]
if( pic_scaling_list_present_flag[ i ] )
if( i < 6 )
scaling_list( ScalingList4x4[ i ], 16,
UseDefaultScalingMatrix4x4Flag[ i ] )
else
scaling_list( ScalingList8x8[ i − 6 ], 64,
UseDefaultScalingMatrix8x8Flag[ i − 6 ] )
}
/* —————————— Scaling_list End —————————— */
/*
色度分量Cr與亮度分量Y的量化內插補點,取值範圍為[-12, 12]
當second_chroma_qp_index_offset不存在時,預設值為
chroma_qp_index_offset
*/
second_chroma_qp_index_offset
}
rbsp_trailing_bits( )
}
準确的來說,以上語義看不懂也沒關系,因為關系到每個知識點,我們都可以單開一篇文章來詳細介紹。而且在圖像參數集裡面,我們并沒有擷取到用于講解某一知識點的全部句法元素。是以在後面講到slice_header以後,一些知識點就可以詳細介紹,比如如何計算POC、編碼模式、參考圖像清單等。