原文出自 http://blog.csdn.net/xfding/article/details/5476763 (轉載收集)
(四)圖像參數集語義
?
pic_parameter_set_rbsp( ) {??
???
// pic_parameter_set_id 用以指定本參數集的序號,該序號在各片的片頭被引用。
??
pic_parameter_set_id
??
???
// seq_parameter_set_id? 指明本圖像參數集所引用的序列參數集的序號。
???
seq_parameter_set_id
??
??
// entropy_coding_mode_flag? 指明熵編碼的選擇,本句法元素為0時,表示熵編碼使用 CAVLC,本句法元素為1時表示熵編碼使用 CABAC?
???
entropy_coding_mode_flag
??
???
// pic_order_present_flag??????? POC 的三種計算方法在片層還各需要用一些句法元素作為參數,本句法元素等于1時表示在片頭會有句法元素指明這些參數;本句法元素等于0時,表示片頭不會給出這些參數,這些參數使用默認值
???
pic_order_present_flag
??
???
// num_slice_groups_minus1? 本句法元素加1后指明圖像中片組的個數。H.264? 中沒有專門的句法元素用于指明是否使用片組模式,當本句法元素等于0(即只有一個片組),表示不使用片組模式,后面也不會跟有用于計算片組映射的句法元素。?
???
num_slice_groups_minus1
??
??? if(
num_slice_groups_minus1
> 0 ) {???
???????
/* slice_group_map_type? 用以指明片組分割類型。?
?????????? map_units 的定義:
????????? -? 當 frame_mbs_only_flag 等于1時,map_units 指的就是宏塊
????????? -? 當 frame_mbs_only_flag 等于0時?
????????????? -? 幀場自適應模式時,map_units 指的是宏塊對
????????????? -? 場模式時,map_units 指的是宏塊
????????????? -? 幀模式時,map_units 指的是與宏塊對相類似的,上下兩個連續宏塊的組合體。????? */
???????
slice_group_map_type
???????
??????? if( slice_group_map_type??? = =??? 0 )????????
??????????? for( iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++ )????????
???????????????
// run_length_minus1[i]???? 用以指明當片組類型等于0時,每個片組連續的 map_units 個數
???????????????
run_length_minus1
[ iGroup ]???
??????? else if(
slice_group_map_type
??? = =??? 2 )????????
??????????? for( iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++ ) {????????
???????????????
// top_left[i],bottom_right[i]?? 用以指明當片組類型等于2時,矩形區域的左上及右下位置。
???????????????
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_direction_flag
???
??????????
// slice_group_change_rate_minus1?????? 用以指明變量 SliceGroupChangeRAte
???????????
slice_group_change_rate_minus1???
??????? } else if(
slice_group_map_type
??? = =??? 6 ) {???
??????????
// pic_size_in_map_units_minus1?? 在片組類型等于6時,用以指明圖像以 map_units 為單位的大小。?????
???????????
pic_size_in_map_units_minus1
???
??????????? for( i = 0; i <= pic_size_in_map_units_minus1; i++ )????????
???????????????
// slice_group_id[i]?????????? 在片組類型等于6時,用以指明某個 map_units 屬于哪個片組。
???????????????
slice_group_id
[ i ]???
??????? }????????
??? }????????
??
// num_ref_idx_l0_active_minus1? 加1后指明目前參考幀隊列的長度,即有多少個參考幀(包括短期和長期)。值得注意的是,當目前解碼圖像是場模式下,參考幀隊列的長度應該是本句法元素再乘以2,因為場模式下各幀必須被分解以場對形式存在。(這里所說的場模式包括圖像的場及幀場自適應下的處于場模式的宏塊對)? 本句法元素的值有可能在片頭被重載。?
????? 在序列參數集中有句法元素 num_ref_frames 也是跟參考幀隊列有關,它們的區別是num_ref_frames指明參考幀隊列的最大值,解碼 器用它的值來分配內存空 間;num_ref_idx_l0_active_minus1 指明在這個隊列中當前實際的、已存在的參考幀數目,這從它的名字“active”中也可以看出來。圖像時,并不是直接傳送該圖像的編號,而是傳送該圖像在參考幀隊列中的序號。這個序號并不是在碼流中傳送的,這個句法元素是 H.264 中最重要的句法元素之一,編碼器要通知解碼器某個運動矢量所指向的是哪個參考而是編碼器和解碼器同步地、用相同的方法將參考圖像放入隊列,從而獲得一個序號。這個隊列在每解一個圖像,甚至是每個片后都會動態地更新。維護參考幀隊列是編解碼器十分重要的工作,而本句法元素是維護參考幀隊列的重要依據。參考幀隊列的復雜的維護機制是 H.264 重要也是很有特色的組成部分?
???
num_ref_idx_l0_active_minus1??
??? num_ref_idx_l1_active_minus1
?
???
// weighted_pred_flag? 用以指明是否允許P和SP片的加權預測,如果允許,在片頭會出現用以計算加權預測的句法元素。
??
weighted_pred_flag
???
???
// weighted_bipred_flag?? 用以指明是否允許 B 片的加權預測,本句法元素等于 0 時表示使用默認加權預測模式,等于 1 時表示使用顯式加權預測模式,等于 2 時表示使用隱式加權預測模式。?
???
weighted_bipred_idc
???
???
// pic_init_qp_minus26? 加 26 后用以指明亮度分量的量化參數的初始值。在 H.264 中,量化參數分三個級別給出:圖像參數集、片頭、宏塊。在圖像參數集給出的是一個初始值。
???
pic_init_qp_minus26
???
/* relative to 26 */
???
???
pic_init_qs_minus26
???
/* relative to 26 */
??
???
// chroma_qp_index_offset?? 色度分量的量化參數是根據亮度分量的量化參數計算出來的,本句法元素用以指明計算時用到的參數。
???
chroma_qp_index_offset
???
??
// deblocking_filter_control_present_flag? 編碼器可以通過句法元素顯式地控制去塊濾波的強度,本句法元素指明是在片頭是否會有句法元素傳遞這個控制信息。如果本句法元素等于 0,那些用于傳遞濾波強度的句法元素不會出現,解碼器將獨立地計算出濾波強度。
???
deblocking_filter_control_present_flag
??
???
// constrained_intra_pred_flag? 在 P 和 B 片中,幀內編碼的宏塊的鄰近宏塊可能是采用的幀間編碼。當本句法元素等于 1 時,表示幀內編碼的宏塊不能用幀間編碼的宏塊的像素作為自己的預測,即幀內編碼的宏塊只能用鄰近幀內編碼的宏塊的像素作為自己的預測;而本句法元素等于 0 時,表示不存在這種限制。
???
constrained_intra_pred_flag
??
???
// redundant_pic_cnt_present_flag 指明是否會出現 redundant_pic_cnt? 句法元素。
???
redundant_pic_cnt_present_flag??
??? rbsp_trailing_bits
( )???????
}
?
(五)片頭句法
slice_header
( ) {?
???
// first_mb_in_slice? 片中的第一個宏塊的地址,? 片通過這個句法元素來標定它自己的地址。 要注意的是在幀場自適應模式下,宏塊都是成對出現,這時本句法元素表示的是第幾個宏塊對,對應的第一個宏塊的真實地址應該是2 * first_mb_in_slice?
???
first_mb_in_slice
???
??? /* slice_type??? 指明片的類型
?????? slice_type????????? Name of slice_type
?????? 0??????????????????????? P (P slice)
?????? 1??????????????????????? B (B slice)
?????? 2??????????????????????? I (I slice)
?????? 3??????????????????????? SP (SP slice)
?????? 4??????????????????????? SI (SI slice)
?????? 5??????????????????????? P (P slice)
?????? 6??????????????????????? B (B slice)
?????? 7??????????????????????? I (I slice)
?????? 8??????????????????????? SP (SP slice)
?????? 9??????????????????????? SI (SI slice) */
???
slice_type
???
???
// pic_parameter_set_id? 圖像參數集的索引號.? 范圍 0? 到 255。?
???
pic_parameter_set_id
???
???
// frame_num? 每個參考幀都有一個依次連續的 frame_num 作為它們的標識,這指明了各圖像的解碼順序。但事實上我們可以看到,frame_num 的出現沒有 if 語句限定條件,這表明非參考幀的片頭也會出現 frame_num。只是當該個圖像是參考幀時,它所攜帶的這個句法元素在解碼時才有意義。
??? H.264 對 frame_num的值作了如下規定:當參數集中的句法元素gaps_in_frame_num_value_allowed_flag 不為1 時,每個圖像的 frame_num? 值是它前一個參考幀的frame_num 值增加 1。這句話包含有兩層意思:
??? 1)? 當 gaps_in_frame_num_value_allowed_flag? 不為 1,即 frame_num? 連續的情況下,每個圖像的frame_num 由前一個參考幀圖像對應的值加 1,著重點是“前一個參考幀”。
?????????? 前面我們曾經提到,對于非參考幀來說,它的 frame_num? 值在解碼過程中是沒有意義的,因為frame_num? 值是參考幀特有的,它的主要作用是在該圖像被其他圖像引用作運動補償的參考時提供一個標識。但 H.264 并沒有在非參考幀圖像中取消這一句法元素,原因是在 POC 的第二種和第三種解碼方法中可以通過非參考幀的 frame_num 值計算出他們的 POC 值。
??? 2)? 當 gaps_in_frame_num_value_allowed_flag 等于 1,前文已經提到,這時若網絡阻塞,編碼器可以將編碼后的若干圖像丟棄,而不用另行通知解碼器。在這種情況下,解碼器必須有機制將缺失的frame_num 及所對應的圖像填補,否則后續圖像若將運動矢量指向缺失的圖像將會產生解碼錯誤。?
???
frame_num
???
??? if( !
frame_mbs_only_flag
) {?
??????? // field_pic_flag???? 這是在片層標識圖像編碼模式的唯一一個句法元素。所謂的編碼模式是指的幀編碼、場編碼、幀場自適應編碼。當這個句法元素取值為 1 時? 屬于場編碼; 0 時為非場編碼。
????????
??????
field_pic_flag
???
??????? if(
field_pic_flag
)??????????
???????????
// bottom_field_flag?? 等于 1 時表示當前圖像是屬于底場;等于 0 時表示當前圖像是屬于頂場。
???????????
bottom_field_flag
???
??? }?????????
??? if(
nal_unit_type
??? ==??? 5 )?????????
???????
// idr_pic_id????? IDR? 圖像的標識。不同的 IDR 圖像有不同的 idr_pic_id 值。值得注意的是,IDR 圖像有不等價于 I 圖像,只有在作為 IDR 圖像的 I 幀才有這個句法元素,在場模式下,IDR 幀的兩個場有相同的 idr_pic_id 值。idr_pic_id 的取值范圍是? [0,65535],和 frame_num 類似,當它的值超出這個范圍時,它會以循環的方式重新開始計數。??
???????
idr_pic_id
??
??? if(
pic_order_cnt_type
??? ==??? 0 ) {????
???????
// pic_order_cnt_lsb??? 在 POC 的第一種算法中本句法元素來計算 POC 值,在 POC 的第一種算法中是顯式地傳遞 POC 的值,而其他兩種算法是通過 frame_num 來映射 POC 的值。
???????
pic_order_cnt_lsb
????????
??????? if(
pic_order_present_flag
&&??? !
field_pic_flag
)?????????
???????????
// delta_pic_order_cnt_bottom??? 如果是在場模式下,場對中的兩個場都各自被構造為一個圖像,它們有各自的 POC 算法來分別計算兩個場的 POC 值,也就是一個場對擁有一對 POC 值;而在是幀模式或是幀場自適應模式下,一個圖像只能根據片頭的句法元素計算出一個 POC 值。根據 H.264 的規定,在序列中有可能出現場的情況,即 frame_mbs_only_flag 不為 1 時,每個幀或幀場自適應的圖像在解碼完后必須分解為兩個場,以供后續圖像中的場作為參考圖像。所以當 frame_mb_only_flag? 不為 1時,幀或幀場自適應中包含的兩個場也必須有各自的 POC 值。通過本句法元素,可以在已經解開的幀或幀場自適應圖像的 POC 基礎上新映射一個 POC 值,并把它賦給底場。當然,象句法表指出的那樣,這個句法元素只用在 POC 的第一個算法中。
???????????
delta_pic_order_cnt_bottom???
??? }?????????
??? if(
pic_order_cnt_type
= = 1 && !
delta_pic_order_always_zero_flag
) {??????
??????
// delta_pic_order_cnt[0], delta_pic_order_cnt[1]:POC 的第二和第三種算法是從 frame_num 映射得來,這兩個句法元素用于映射算法。delta_pic_order_cnt[0]用于幀編碼方式下的底場和場編碼方式的場,delta_pic_order_cnt[1] 用于幀編碼方式下的頂場。????
???????
delta_pic_order_cnt
[ 0 ]?
??????? if(
pic_order_present_flag
??? &&??? !
field_pic_flag
)?????????
???????????
delta_pic_order_cnt
[ 1 ]??
??? }?????????
??? if(
redundant_pic_cnt_present_flag
)????????
???????
// redundant_pic_cnt??? 冗余片的 id 號。?
???????
redundant_pic_cnt
??
??? if(
slice_type
??? ==??? B )?????????
???????
// direct_spatial_mv_pred_flag? 指出在B圖像的直接預測的模式下,用時間預測還是用空間預測。1:空間預測;0:時間預測。?
???????
direct_spatial_mv_pred_flag
??
??? if(
slice_type
= = P | |
slice_type
= = SP | |
slice_type
= = B ) {?????????
???????
// num_ref_idx_active_override_flag??? 在圖像參數集中我們看到已經出現句法元素num_ref_idx_l0_active_minus1 和num_ref_idx_l1_active_minus1 指定當前參考幀隊列中實際可用的參考幀的數目。在片頭可以重載這對句法元素,以給某特定圖像更大的靈活度。這個句法元素就是指明片頭是否會重載,如果該句法元素等于 1,下面會出現新的 num_ref_idx_l0_active_minus1? 和num_ref_idx_l1_active_minus1 值。?
???????
num_ref_idx_active_override_flag?
??????? if(
num_ref_idx_active_override_flag
) {?????????
???????????
num_ref_idx_l0_active_minus1?
??????????? if( slice_type??? ==??? B )?????????
???????????????
num_ref_idx_l1_active_minus1
??
??????? }?????????
??? }?????
???
// 參考幀隊列重排序(reordering)句法
???
ref_pic_list_reordering
( )??????????
??? if( (
weighted_pred_flag
??? &&??? (
slice_type
== P??? | |???
slice_type
== SP ) )?? | |
??????? (
weighted_bipred_idc
??? ==??? 1??? &&???
slice_type
??? ==??? B ) )
???????
// 加權預測句法
?
???????
pred_weight_table
( )??????
??? if(
nal_ref_idc
!= 0 )?????????
???????
// 參考幀隊列標記(marking)句法?
??????
dec_ref_pic_marking
( )????????
??? if( entropy_coding_mode_flag??? &&??? slice_type??? !=??? I??? &&?? slice_type??? !=??? SI )
???????
// cabac_init_idc? 給出 cabac 初始化時表格的選擇,范圍 0 到 2。
???????
cabac_init_idc
??
???
// slice_qp_delta? 指出在用于當前片的所有宏塊的量化參數的初始值。SliceQPY = 26+ pic_init_qp_minus26 + slice_qp_delta?? 范圍是? 0 to 51。 H.264? 中量化參數是分圖像參數集、片頭、宏塊頭三層給出的,前兩層各自給出一個偏移值,這個句法元素就是片層的偏移。
???
slice_qp_delta
???
??? if(
slice_type
??? = =??? SP??? | |???
slice_type
??? = =??? SI ) {?????????
??????? if(
slice_type
??? = =??? SP )?????????
???????????
// sp_for_switch_flag? 指出SP 幀中的p 宏塊的解碼方式是否是switching 模式?
???????????
sp_for_switch_flag
?
???????????
// slice_qs_delta? 與 slice_qp_delta 的與語義相似,用在 SI 和 SP 中的?
???????????
slice_qs_delta
??
??? }?????????
??? if(
deblocking_filter_control_present_flag
) {?????
???????
// disable_deblocking_filter_idc? H.264 指定了一套算法可以在解碼器端獨立地計算圖像中各邊界的濾波強度進行濾波。除了解碼器獨立計算之外,編碼器也可以傳遞句法元素來干涉濾波強度,當這個句法元素指定了在塊的邊界是否要用濾波,同時指明那個塊的邊界不用塊濾波?????
???????
disable_deblocking_filter_idc
??
??????? if(
disable_deblocking_filter_idc
??? !=??? 1 ) {???
???????????
// slice_alpha/beta_c0_offset_div2? 給出用于增強? α/beta 和? t C0 的偏移值
????????
???????????
slice_alpha_c0_offset_div2??
??????????? slice_beta_offset_div2
???
??????? }?????????
??? }?????????
??? if(
num_slice_groups_minus1
> 0??? &&
???????
slice_group_map_type
>= 3??? &&???
slice_group_map_type
<= 5)
?????
? // slice_group_change_cycle? 當片組的類型是 3, 4,??? 5,由句法元素可獲得片組中? 映射單元的數目:
???????
slice_group_change_cycle
?
}
?
(六)參考幀隊列重排序(reordering)句法
ref_pic_list_reordering( ) {
??
??? if(
slice_type
??? !=??? I??? &&???
slice_type
??? !=??? SI ) {?????????????
???????
// ref_pic_list_reordering_flag_l0?? 指明是否進行重排序操作,這個句法元素等于1 時表明緊跟著會有一系列句法元素用于參考幀隊列的重排序。
??????
ref_pic_list_reordering_flag_l0
??
??????? if(
ref_pic_list_reordering_flag_l0
)??????????
??????????? do {??????????
???????????????
// reordering_of_pic_nums_idc????? 指明執行哪種重排序操作
?????????????????? reordering_of_pic_nums_idc?????? 操作
?????????????????? 0????????????????????????????????????????????????? 短期參考幀重排序,abs_diff_pic_num_minus1會出現在碼流中,從當
?????????????????????????????????????????????????????????????????????? 前圖像的PicNum減去? (abs_diff_pic_num_minus1? +? 1)? 后指明需要重
?????????????????????????????????????????????????????????????????????? 排序的圖像。
?????????????????? 1????????????????????????????????????????????????? 短期參考幀重排序,abs_diff_pic_num_minus1會出現在碼流中,從當
?????????????????????????????????????????????????????????????????????? 前圖像的PicNum加上? (abs_diff_pic_num_minus1? +? 1)? 后指明需要重
?????????????????????????????????????????????????????????????????????? 排序的圖像。
?????????????????? 2????????????????????????????????????????????????? 長期參考幀重排序,long_term_pic_num會出現在碼流中,指明需要重
?????????????????????????????????????????????????????????????????????? 排序的圖像。
?????????????????? 3????????????????????????????????????????????????? 結束循環,退出重排序操作。?
???????????????
reordering_of_pic_nums_idc
?
??????????????? if(
reordering_of_pic_nums_idc
??? ==??? 0??? | |
???????????????????
reordering_of_pic_nums_idc
??? ==??? 1 )?
???????????????????
// abs_diff_pic_num_minus1?? 在對短期參考幀重排序時指明重排序圖像與當前的差
???????????????????
abs_diff_pic_num_minus1
??
??????????????? else if(
reordering_of_pic_nums_idc
??? = =??? 2 )????????
???????????????????
// long_term_pic_num???? 在對長期參考幀重排序時指明重排序圖像
??
??????????????????
long_term_pic_num
?
??????????? } while(
reordering_of_pic_nums_idc
??? !=??? 3 )??????????
??? }??????????
??? if(
slice_type
??? ==??? B ) {??????????
??????
ref_pic_list_reordering_flag_l1
??
??????? if(
ref_pic_list_reordering_flag_l1
)??????????
??????????? do {??????????
???????????????
reordering_of_pic_nums_idc??
??????????????? if(
reordering_of_pic_nums_idc
??? = =??? 0??? | |
???????????????????
reordering_of_pic_nums_idc
??? = =??? 1 )
??????????????????
abs_diff_pic_num_minus1??
??????????????? else if(
reordering_of_pic_nums_idc
??? = =??? 2 )??????????
???????????????????
long_term_pic_num
???
??????????? } while(
reordering_of_pic_nums_idc
??? !=??? 3 )??????????
??? }??????????
}
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
