在 H.264 定義的碼流中,句法元素被組織成有層次的結構,分別描述各個層次的信息,如下圖所示
?
?
?
????????? 在H.264 中,句法元素共被組織成? 序列、圖像、片、宏塊、子宏塊五個層次。
????????? 在這樣的結構中,每一層的頭部和它的數據部分形成管理與被管理的強依賴關系,頭部的句法元素是該層數據的核心,而一旦頭部丟失,數據部分的信息幾乎不可能再被正確解碼出來,尤其在序列層及圖像層。
?
?
?
????? 在 H.264 中,分層結構最大的不同是取消了序列層和圖像層,并將原本屬于序列和圖像頭部的大部分句法元素游離出來形成序列和圖像兩級參數集,其余的部分則放入片層。參數集是一個獨立的數據單位,不依賴于參數集外的其他句法元素。由于參數集是獨立的,可以被多次重發或者采用特殊技術加以保護。
????? 復雜通信中的碼流中可能出現的數據單位:
?
?????? IDR: 一個序列的第一個圖像叫做 IDR 圖像(立即刷新圖像),IDR 圖像都是 I圖像。H.264 引入 IDR 圖像是為了解碼的重同步,當解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數據全部輸出或拋棄,重新查找參數集,開始一個新的序列。IDR 圖像一定是 I 圖像,但 I 圖像不一定是 IDR 圖像。
?
NAL&VCL: H.264 的功能分為兩層,即視頻編碼層(VCL)和網絡提取層(NAL,Network Abstraction Layer)。VCL 數據即編碼處理的輸出,它表示被壓縮編碼后的視頻數據序列。在 VCL 數據傳輸或存儲之前,這些編碼的 VCL 數據,先被映射或封裝進 NAL 單元中。?
????? 每個 NAL 單元包括一個原始字節序列負荷(RBSP)、一組對應于視頻編碼數據的 NAL 頭信息。NAL 單元序列的結構如下:
?
???? RBSP的類型:
RBSP 類型 描??????????? 述?
參數集 PS? 序列的全局參數,如圖像尺寸、視頻格式等等?
增強信息 SEI? 視頻序列解碼的增強信息?
圖像定界符 PD? 視頻圖像的邊界?
編碼片? 片的頭信息和數據?
數據分割? DP 片層的數據,用于錯誤恢復解碼?
序列結束符? 表明下一圖像為 IDR 圖像?
流結束符? 表明該流中已沒有圖像?
填充數據? 啞元數據,用于填充字節?
????? PS: 包括序列參數集 SPS 和圖像參數集 PPS
??????????? SPS 包含的是針對一連續編碼視頻序列的參數,如標識符 seq_parameter_set_id、幀數及 POC 的約束、參考幀數目、解碼圖像尺寸和幀場編碼模式選擇標識等等。
??????????? PPS對應的是一個序列中某一幅圖像或者某幾幅圖像,其參數如標識符 pic_parameter_set_id、可選的 seq_parameter_set_id、熵編碼模式選擇標識、片組數目、初始量化參數和去方塊濾波系數調整標識等等。
????? 數據分割:組成片的編碼數據存放在 3 個獨立的 DP(數據分割,A、B、C)中,各自包含一個編碼片的子集。分割A包含片頭和片中每個宏塊頭數據。分割B包含幀內和 SI 片宏塊的編碼殘差數據。分割 C包含幀間宏塊的編碼殘差數據。每個分割可放在獨立的 NAL 單元并獨立傳輸。
NAL 層句法 :
nal_unit( NumBytesInNALunit ) {?
??? // forbidden_zero_bit? 等于 0
??? forbidden_zero_bit??
??? // nal_ref_idc?? 指示當前 NAL 的優先級。取值范圍為 0-3,? 值越高,表示當前 NAL 越重要,需要優先受到保護。H.264 規定如果當前 NAL 是屬于參考幀的片,或是序列參數集,或是圖像參數集這些重要的數據單位時,本句法元素必須大于 0。???
??? nal_ref_idc??
??? // nal_unit_type 指明當前 NAL unit 的類型
??? nal_unit_type?
??? NumBytesInRBSP = 0?
??? /* rbsp_byte[i]??? RBSP 的第 i 個字節。RBSP 指原始字節載荷,它是 NAL 單元的數據部分的封裝格式,封裝的數據來自 SODB(原始數據比特流)。SODB 是編碼后的原始數據,SODB 經封裝為 RBSP 后放入 NAL 的數據部分。下面介紹一個 RBSP 的生成順序。
??????? 從 SODB 到 RBSP 的生成過程:
??????? -????? 如果 SODB 內容是空的,生成的 RBSP 也是空的
??????? -????? 否則,RBSP 由如下的方式生成:
?????? 1) RBSP 的第一個字節直接取自 SODB 的第 1 到 8 個比特,(RBSP 字節內的比特按照從左到右對應為從高到低的順序排列,most? significant),以此類推,RBSP 其余的每個字節都直接取自 SODB的相應比特。RBSP? 的最后一個字節包含 SODB? 的最后幾個比特,及如下的 rbsp_trailing_bits()
?????? 2) rbsp_trailing_bits()的第一個比特是 1,接下來填充 0,直到字節對齊。(填充 0 的目的也是為了字節對齊)
?????? 3) 最后添加若干個 cabac_zero_word(其值等于 0x0000)???????????
??? */
??? for( i = 1; i < NumBytesInNALunit; i++ ) {??????????
??????? if( i + 2 < NumBytesInNALunit && next_bits( 24 )??? = =??? 0x000003 ) {?????????
??????????? rbsp_byte[ NumBytesInRBSP++ ]??
??????????? rbsp_byte[ NumBytesInRBSP++ ]??
??????????? i += 2??????????
??????????? //emulation_prevention_three_byte????? NAL 內部為防止與起始碼競爭而引入的填充字節? ,值為 0x03。
??????????? emulation_prevention_three_byte???
??????? } else??????????
??????????? rbsp_byte[ NumBytesInRBSP++ ]???
??? }?????????
}
?
seq_parameter_set_rbsp( ) {?
??? // profile_idc? level_idc? 指明所用? profile、level
??? profile_idc??
??? // constraint_set0_flag? 等于 1 時表示必須遵從附錄 A.2.1 所指明的所有制約條件。等于 0 時表示不必遵從所有條件。
??? constraint_set0_flag??
??? // constraint_set1_flag? 等于 1 時表示必須遵從附錄 A.2.2 所指明的所有制約條件。等于 0 時表示不必遵從所有條件。
??? constraint_set1_flag???
??? // constraint_set2_flag? 等于 1 時表示必須遵從附錄 A.2.3 所指明的所有制約條件。等于 0 時表示不必遵從所有條件。
?? constraint_set2_flag??
??? // reserved_zero_5bits? 在目前的標準中本句法元素必須等于 0,其他的值保留做將來用,解碼器應該忽略本句法元素的值。
??? reserved_zero_5bits /* equal to 0 */???
??? level_idc?????
??? // seq_parameter_set_id? 指明本序列參數集的? id 號,這個 id 號將被 picture 參數集引用,本句法元素的值應該在[0,31]。?
??? seq_parameter_set_id???
??? // log2_max_frame_num_minus4? 這個句法元素主要是為讀取另一個句法元素 frame_num? 服務的,frame_num? 是最重要的句法元素之一,它標識所屬圖像的解碼順序 。這個句法元素同時也指明了 frame_num 的所能達到的最大值: MaxFrameNum = 2*exp( log2_max_frame_num_minus4 + 4 )
??? log2_max_frame_num_minus4??
??? // pic_order_cnt_type? 指明了 poc? (picture? order? count)? 的編碼方法,poc 標識圖像的播放順序。由poc 可以由 frame-num 通過映射關系計算得來,也可以索性由編碼器顯式地傳送。
??? pic_order_cnt_type????????
??? if( pic_order_cnt_type??? ==??? 0 )??
?????? // log2_max_pic_order_cnt_lsb_minus4? 指明了變量? MaxPicOrderCntLsb 的值: MaxPicOrderCntLsb = pow(2, (log2_max_pic_order_cnt_lsb_minus4 + 4) )
??????? log2_max_pic_order_cnt_lsb_minus4???
??? else if( pic_order_cnt_type??? ==??? 1 ) {???
??????? // delta_pic_order_always_zero_flag? 等于 1 時,句法元素 delta_pic_order_cnt[0]和 delta_pic_order_cnt[1]
不在片頭出現,并且它們的值默認為 0;? 本句法元素等于 0 時,上述的兩個句法元素將在片頭出現。?
??????? delta_pic_order_always_zero_flag???
??????? // offset_for_non_ref_pic?? 被用來計算非參考幀或場的 POC,本句法元素的值應該在[pow(-2, 31)? , pow(2, 31)? – 1]。?
?????? offset_for_non_ref_pic???
??????? // offset_for_top_to_bottom_field? 被用來計算幀的底場的 POC,? 本句法元素的值應該在[pow(-2, 31)? , pow(2, 31)? – 1]。?
??????? offset_for_top_to_bottom_field???
?????? // num_ref_frames_in_pic_order_cnt_cycle? 被用來解碼POC, 本句法元素的值應該在[0,255]。
??????? num_ref_frames_in_pic_order_cnt_cycle???
??????? // offset_for_ref__frame[i]? 用于解碼 POC,本句法元素對循環num_ref_frames_in_pic_order_cycle 中的每一個元素指定一個偏移。
??????? for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )?
??????????? offset_for_ref_frame[ i ]???
??? }???
??? // num_ref_frames?? 指定參考幀隊列可能達到的最大長度,解碼器依照這個句法元素的值開辟存儲區,這個存儲區用于存放已解碼的參考幀,H.264 規定最多可用 16 個參考幀,本句法元素的值最大為 16。值得注意的是這個長度以幀為單位,如果在場模式下,應該相應地擴展一倍。
??? num_ref_frames??
?? // gaps_in_frame_num_value_allowed_flag? 這個句法元素等于 1 時,表示允許句法元素 frame_num 可以不連續。當傳輸信道堵塞嚴重時,編碼器來不及將編碼后的圖像全部發出,這時允許丟棄若干幀圖像。
?? gaps_in_frame_num_value_allowed_flag??
??? // pic_width_in_mbs_minus1? 本句法元素加 1 后指明圖像寬度,以宏塊為單位: PicWidthInMbs = pic_width_in_mbs_minus1 + 1 通過這個句法元素解碼器可以計算得到亮度分量以像素為單位的圖像寬度: PicWidthInSamplesL = PicWidthInMbs * 16?
??? pic_width_in_mbs_minus1???
??? // pic_height_in_map_units_minus1?? 本句法元素加 1 后指明圖像高度: PicHeightInMapUnits = pic_height_in_map_units_minus1 + 1?
??? pic_height_in_map_units_minus1???
??? // frame_mbs_only_flag?? 本句法元素等于 0 時表示本序列中所有圖像的編碼模式都是幀,沒有其他編碼模式存在;本句法元素等于 1 時? ,表示本序列中圖像的編碼模式可能是幀,也可能是場或幀場自適應,某個圖像具體是哪一種要由其他句法元素決定。
??? frame_mbs_only_flag???
??? // mb_adaptive_frame_field_flag?? 指明本序列是否屬于幀場自適應模式。mb_adaptive_frame_field_flag等于1時表明在本序列中的圖像如果不是場模式就是幀場自適應模式,等于0時表示本序列中的圖像如果不是場模式就是幀模式。。表? 列舉了一個序列中可能出現的編碼模式:
??? if( !frame_mbs_only_flag )??
??????? mb_adaptive_frame_field_flag???
??? // direct_8x8_inference_flag??? 用于指明 B 片的直接和 skip 模式下運動矢量的預測方法。
??? direct_8x8_inference_flag???
??? // frame_cropping_flag?? 用于指明解碼器是否要將圖像裁剪后輸出,如果是的話,后面緊跟著的四個句法元素分別指出左右、上下裁剪的寬度。?
??? frame_cropping_flag??
??? if( frame_cropping_flag ) {??
??????? frame_crop_left_offset???
??????? frame_crop_right_offset??
??????? frame_crop_top_offset??
?????? frame_crop_bottom_offset???
??? }??
??? // vui_parameters_present_flag????? 指明 vui 子結構是否出現在碼流中,vui 用以表征視頻格式等額外信息。
??? vui_parameters_present_flag??
???? if( vui_parameters_present_flag )??
??????? vui_parameters( )????????
???? rbsp_trailing_bits( )???????
}??
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?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/13/5476663.aspxref_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 )??????????
??? }??????????
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5476763.aspx
?
pred_weight_table( ) {??
?? // luma_log2_weight_denom??? 給出參考幀列表中參考圖像所有亮度的加權系數,是個初始值luma_log2_weight_denom? 值的范圍是? 0 to 7。?
??? luma_log2_weight_denom???
??? // chroma_log2_weight_denom? 給出參考幀列表中參考圖像所有色度的加權系數,是個初始值chroma_log2_weight_denom? 值的范圍是? 0 to 7。?
??? chroma_log2_weight_denom???
??? for( i = 0; i <= num_ref_idx_l0_active_minus1; i++ ) {???????
??????? // luma_weight_l0_flag? 等于 1? 時,指的是在參考序列 0 中的亮度的加權系數存在;等于 0 時,在參考序列 0 中的亮度的加權系數不存在。???
??????? luma_weight_l0_flag???
??????? if( luma_weight_l0_flag ) {??????????
??????????? // luma_weight_l0[ i ]? 用參考序列 0 預測亮度值時,所用的加權系數。如果? luma_weight_l0_flag is = 0, luma_weight_l0[ i ] = pow(2, luma_log2_weight_denom )
??????????? luma_weight_l0[ i ]??
??????????? // luma_offset_l0[ i ]? 用參考序列 0 預測亮度值時,所用的加權系數的額外的偏移。luma_offset_l0[ i ]? 值的范圍–128 to 127。如果? luma_weight_l0_flag is = 0, luma_offset_l0[ i ] = 0??
??????????? luma_offset_l0[ i ]???
??????? }?????????
??????? chroma_weight_l0_flag???
??????? if( chroma_weight_l0_flag )?????????
??????????? for( j =0; j < 2; j++ ) {?????????
??????????????? chroma_weight_l0[ i ][ j ]???
??????????????? chroma_offset_l0[ i ][ j ]??
??????????? }?????????
??? }?????????
??? if( slice_type??? = =??? B )?????????
??????? for( i = 0; i <= num_ref_idx_l1_active_minus1; i++ ) {?????????
??????????? luma_weight_l1_flag??
??????????? if( luma_weight_l1_flag ) {?????????
??????????????? luma_weight_l1[ i ]??
??????????????? luma_offset_l1[ i ]?
??????????? }?????????
??????????? chroma_weight_l1_flag???
??????????? if( chroma_weight_l1_flag )?????????
??????????????? for( j = 0; j < 2; j++ ) {?????????
??????????????????? chroma_weight_l1[ i ][ j ]??
??????????????????? chroma_offset_l1[ i ][ j ]??
??????????????? }?????????
??????? }?????????
}
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5476851.aspx
?
?
重排序(reordering)操作是對參考幀隊列重新排序,而標記(marking)操作負責將參考圖像移入或移出參考幀隊列。
dec_ref_pic_marking( ) {?
??? if( nal_unit_type??? = =??? 5 ) {???????????
??????? // no_output_of_prior_pics_flag? 僅在當前圖像是 IDR 圖像時出現這個句法元素,指明是否要將前面已解碼的圖像全部輸出。?
??????? no_output_of_prior_pics_flag??
??????? // long_term_reference_flag??? 與上個圖像一樣,僅在當前圖像是 IDR 圖像時出現這一句法元素。這個句法元素指明是否使用長期參考這個機制。如果取值為 1,表明使用長期參考,并且每個 IDR 圖像被解碼后自動成為長期參考幀,否則(取值為 0),IDR 圖像被解碼后自動成為短期參考幀。?
??????? long_term_reference_flag???
??? } else {??????????
??????? // adaptive_ref_pic_marking_mode_flag???????? 指明標記(marking)操作的模式,
?????????? adaptive_ref_pic_marking_mode_flag???????? 標記(marking)模式
?????????? 0????????????????????????????????????????????????????????????????? 先入先出(FIFO):使用滑動窗的機制,先入先出,在這種模式
?????????????????????????????????????????????????????????????????????????????? 下沒有辦法對長期參考幀進行操作。
?????????? 1????????????????????????????????????????????????????????????????? 自適應標記(marking):后續碼流中會有一系列句法元素顯式指
?????????????????????????????????????????????????????????????????????????????? 明操作的步驟。自適應是指編碼器可根據情況隨機靈活地作出決策。?
??????? adaptive_ref_pic_marking_mode_flag???
??????? if( adaptive_ref_pic_marking_mode_flag )??????????
??????????? do {??????????
??????????????? /* memory_management_control_operation? 在自適應標記(marking)模式中,指明本次操作的具體內容
??????????????? memory_management_control_operation?????????? 標記(marking)操作
??????????????? 0????????????????????????????????????????????????????????????????????????? 結束循環,退出標記(marding)操作。?
??????????????? 1????????????????????????????????????????????????????????????????????????? 將一個短期參考圖像標記為非參考圖像,也
??????????????????????????????????????????????????????????????????????????????????????????? 即將一個短期參考圖像移出參考幀隊列。
??????????????? 2????????????????????????????????????????????????????????????????????????? 將一個長期參考圖像標記為非參考圖像,也
??????????????????????????????????????????????????????????????????????????????????????????? 即將一個長期參考圖像移出參考幀隊列。
??????????????? 3????????????????????????????????????????????????????????????????????????? 將一個短期參考圖像轉為長期參考圖像。
??????????????? 4????????????????????????????????????????????????????????????????????????? 指明長期參考幀的最大數目。
??????????????? 5????????????????????????????????????????????????????????????????????????? 清空參考幀隊列,將所有參考圖像移出參考
??????????????????????????????????????????????????????????????????????????????????????????? 幀隊列,并禁用長期參考機制
??????????????? 6????????????????????????????????????????????????????????????????????????? 將當前圖像存為一個長期參考幀。 */
?????????????? memory_management_control_operation??
??????????????? if( memory_management_control_operation??? = =??? 1??? | |
??????????????????? memory_management_control_operation??? = =??? 3 )
??????????????????? // difference_of_pic_nums_minus1??? 當 memory_management_control_operation 等于 3? 或 1 時,由? 這個
句法元素可以計算得到需要操作的圖像在短期參考隊列中的序號。參考幀隊列中必須存在這個圖像。
??????????????????? difference_of_pic_nums_minus1??
??????????????? if(memory_management_control_operation??? = =??? 2??? )?????????
??????????????????? // long_term_pic_num??? 當 memory_management_control_operation 等于 2 時,? 從此句法元素得到所要
操作的長期參考圖像的序號。???
??????????????????? long_term_pic_num???
??????????????? if( memory_management_control_operation??? = =??? 3??? | |
??????????????????? memory_management_control_operation??? = =??? 6 )
??????????????????? // long_term_frame_idx??? 當? memory_management_control_operation 等于 3 或 6? ,分配一個長期參考
幀的序號給一個圖像。?
??????????????????? long_term_frame_idx???
??????????????? if( memory_management_control_operation??? = =??? 4 )?????????
?????????????????? // max_long_term_frame_idx_plus1? 此句法元素減1, 指明長期參考隊列的最大數目 。max_long_term_frame_idx_plus1 值的范圍? 0 to num_ref_frames。???
??????????????????? max_long_term_frame_idx_plus1???
??????????? } while( memory_management_control_operation??? !=??? 0 )??????????
??? }??????????
}
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5476906.aspx
?
slice_data( ) {??
??? if( entropy_coding_mode_flag )????????????
??????? while( !byte_aligned( ) )?????????????
??????????? // cabac_alignment_one_bit??? 當熵編碼模式是CABAC 時,此時要求數據字節對齊,即數據從下一個字節的第一個比特開始,如果還沒有字節對齊將出現若干個 cabac_alignment_one_bit 作為填充。?
?????????? cabac_alignment_one_bit??
??? CurrMbAddr = first_mb_in_slice * ( 1 + MbaffFrameFlag )????????????
??? moreDataFlag = 1????????????
??? prevMbSkipped = 0????????????
??? do {????????????
??????? if( slice_type??? !=??? I??? &&??? slice_type??? !=??? SI )????????????
??????????? if( !entropy_coding_mode_flag ) {?
??????????????? // mb_skip_run??? 當圖像采用幀間預測編碼時,H.264 允許在圖像平坦的區域使用“跳躍”塊,“跳躍”塊本身不攜帶任何數據,解碼器通過周圍已重建的宏塊的數據來恢復“跳躍”塊。當熵編碼為 CAVLC 或 CABAC 時,“跳躍”塊的表示方法不同。當 entropy_coding_mode_flag為1,即熵編碼為CABAC時 ,是每個“ 跳 躍 ”塊都會有句法元素mb_skip_flag指明,而entropy_coding_mode_flag 等于 0,即熵編碼為CAVLC時,用一種行程的方法給出緊連著的“跳躍”塊的數目,即句法元素 mb_skip_run。mb_skip_run 值的范圍 0 to PicSizeInMbs – CurrMbAddr? 。????????????
??????????????? mb_skip_run???
??????????????? prevMbSkipped = ( mb_skip_run > 0 )????????????
??????????????? for( i=0; i??????????????????? CurrMbAddr = NextMbAddress( CurrMbAddr )????????????
??????????????? moreDataFlag = more_rbsp_data( )????????????
??????????? } else {????????????
??????????????? // mb_skip_flag? 指明當前宏塊是否是跳躍編碼模式的宏塊
??????????????? mb_skip_flag???
??????????????? moreDataFlag = !mb_skip_flag????????????
??????????? }????????????
??????? if( moreDataFlag ) {????????????
??????????? if( MbaffFrameFlag && ( CurrMbAddr % 2??? = =??? 0??? | |????
??????????????? ( CurrMbAddr % 2??? = =??? 1??? &&??? prevMbSkipped ) ) )
??????????????? // mb_field_decoding_flag? 在幀場自適應圖像中,指明當前宏塊所屬的宏塊對是幀模式還是場模式。0 幀模式;1 場模式。如果一個宏塊對的兩個宏塊句法結構中都沒有出現這個句法元素,即它們都是“跳躍”塊時,本句法元素由以下決定:
??????????????????? -? 如果這個宏塊對與相鄰的、左邊的宏塊對屬于同一個片時,這個宏塊對的 mb_field_decoding_flag的值等于左邊的宏塊對的 mb_field_decoding_flag 的值。
??????????????????? -?? 否則,這個宏塊對的 mb_field_decoding_flag?? 的值等于上邊同屬于一個片的宏塊對的mb_field_decoding_flag 的值。 -? 如果這個宏塊對既沒有相鄰的、上邊同屬于一個片的宏塊對;也沒有相鄰的、左邊同屬于一個片的宏塊對,這個宏塊對的 mb_field_decoding_flag 的值等于 0,即幀模式。 end_of_slice_flag? 指明是否到了片的結尾。
??????????????? mb_field_decoding_flag???
??????????? macroblock_layer( )???????
??????? }????????????
??????? if( !entropy_coding_mode_flag )????????????
??????????? moreDataFlag = more_rbsp_data( )????????????
??????? else {????????????
??????????? if( slice_type??? !=??? I??? &&??? slice_type??? !=??? SI )????????????
??????????????? prevMbSkipped = mb_skip_flag????????????
??????????? if( MbaffFrameFlag??? &&??? CurrMbAddr % 2??? = =??? 0 )????????????
??????????????? moreDataFlag = 1????????????
??????????? else {????????????
??????????????? end_of_slice_flag??
??????????????? moreDataFlag = !end_of_slice_flag????????????
??????????? }
??????? }????????????
??????? CurrMbAddr = NextMbAddress( CurrMbAddr )????????????
??? } while( moreDataFlag )????????????
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5477026.aspx
?
?
macroblock_layer( ) {?? ??? // mb_type??? 指明當前宏塊的類型。H.264規定,不同的片中允許出現的宏塊類型也不同。下表指明在各種片類型中允許出現的宏塊種類。? ???????????????????????? 片類型????????????????? 允許出現的宏塊種類 ???????????????????????? I (slice)?????????????? I? 宏塊 ???????????????????????? P (slice)????????????? P 宏塊、??? I 宏塊 ???????????????????????? B (slice)????????????? B 宏塊、??? I 宏塊 ???????????????????????? SI (slice)???????????? SI 宏塊、? I 宏塊 ???????????????????????? SP (slice)??????????? P 宏塊、??? I? 宏塊? ??? mb_typ
?
?
mb_pred( mb_type ) {??
??? if( MbPartPredMode( mb_type, 0 )??? = =??? Intra_4x4??? | |????
??????? MbPartPredMode( mb_type, 0 )??? = =??? Intra_16x16 ) {
??????? if( MbPartPredMode( mb_type, 0 )??? = =??? Intra_4x4 )????????
??????????? for( luma4x4BlkIdx=0; luma4x4BlkIdx<16; luma4x4BlkIdx++ ) {???
??????????????? // prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ] rem_intra4x4_pred_mode[ luma4x4BlkIdx ] 幀內預測的模式也是需要預測的,? prev_intra4x4_pred_mode_flag 用來指明幀內預測時,亮度分量的預測模式的預測值是否就是真實預測模式,如果是,就不需另外再傳預測模式。如果不是,就由 rem_intra4x4_pred_mode 指定真實預測模式。???????
??????????????? prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ]??
??????????????? if( !prev_intra4x4_pred_mode_flag[ luma4x4BlkIdx ] )????????
?????????????????? rem_intra4x4_pred_mode[ luma4x4BlkIdx ]??
??????????? }????????
??????? // intra_chroma_pred_mode? 在幀內預測時指定色度的預測模式,
??????????? intra_chroma_pred_mode??????? 預測模式
??????????? 0?????????????????????????????????????????????? DC
??????????? 1?????????????????????????????????????????????? Horizontal
??????????? 2?????????????????????????????????????????????? Vertical????????????
??????????? 3?????????????????????????????????????????????? Plane?
??????? intra_chroma_pred_mode??
??? } else if( MbPartPredMode( mb_type, 0 )??? !=??? Direct ) {????????
??????? for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)????????????????
??????????? if( ( num_ref_idx_l0_active_minus1 > 0??? | |
??????????????????? mb_field_decoding_flag ) &&????
??????????????? MbPartPredMode( mb_type, mbPartIdx )??? !=??? Pred_L1 )
??????????????? // ref_idx_l0[ mbPartIdx]用參考幀隊列 L0 進行預測,即前向預測時,參考圖像在參考幀隊列中的序號。其中 mbPartIdx 是宏塊分區的序號。 如 果 當 前 宏 塊 是非場宏塊 ,? 則ref_idx_l0[ mbPartIdx ] 值的范圍是0到 num_ref_idx_l0_active_minus1。 否則,如果當前宏塊是場宏塊,(宏塊所在圖像是場,當圖像是幀場自適應時當前宏塊處于場編碼的宏塊對),ref_idx_l0[ mbPartIdx]值的范圍是 0? 到 2*num_ref_idx_l0_active_minus1 + 1,如前所述,此時參考幀隊列的幀都將拆成場,故參考隊列長度加倍。
??????????????? ref_idx_l0[ mbPartIdx ]??
??????? for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)????????????????
??????????? if( ( num_ref_idx_l1_active_minus1??? >??? 0??? | |
??????????????????? mb_field_decoding_flag ) &&????
??????????????? MbPartPredMode( mb_type, mbPartIdx )??? !=??? Pred_L0 )
??????????????? ref_idx_l1[ mbPartIdx ]??
??????? for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)????????????????
??????????? if( MbPartPredMode ( mb_type, mbPartIdx )??? !=??? Pred_L1 )????????
??????????????? for( compIdx = 0; compIdx < 2; compIdx++ )????????
?????????????????? // mvd_l0[ mbPartIdx ][ 0 ][ compIdx ]? 運動矢量的預測值和實際值之間的差。mbPartIdx? 是宏塊分區的序號。CompIdx = 0 時水平運動矢量;? CompIdx = 1 垂直運動矢量。?
??????????????????? mvd_l0[ mbPartIdx ][ 0 ][ compIdx ]??
??????? for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)????????????????
??????????? if( MbPartPredMode( mb_type, mbPartIdx )??? !=??? Pred_L0 )????????
??????????????? for( compIdx = 0; compIdx < 2; compIdx++ )????????
??????????????????? mvd_l1[ mbPartIdx ][ 0 ][ compIdx ]???
??? }????????
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5477351.aspx
?
?
sub_mb_pred( mb_type ) {??
??? for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )?????????
??????? // sub_mb_type[ mbPartIdx ]??? 指明子宏塊的預測類型,在不同的宏塊類型中這個句法元素的語義不一樣。?????
??????? sub_mb_type[ mbPartIdx ]??
??? for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )?????????????
??????? if( ( num_ref_idx_l0_active_minus1??? >??? 0??? | |??
mb_field_decoding_flag ) &&
??????????? mb_type??? !=??? P_8x8ref0??? &&
??????????? sub_mb_type[ mbPartIdx ]??? !=??? B_Direct_8x8??? &&
??????????? SubMbPredMode( sub_mb_type[ mbPartIdx ] )??? !=??? Pred_L1 )
??????????? ref_idx_l0[ mbPartIdx ]???
??? for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )?????????????
??????? if( (num_ref_idx_l1_active_minus1??? >??? 0??? | |??? mb_field_decoding_flag )
&&
??????????????? sub_mb_type[ mbPartIdx ]??? !=??? B_Direct_8x8??? &&
??????????????? SubMbPredMode( sub_mb_type[ mbPartIdx ] )??? !=??? Pred_L0 )
??????????? ref_idx_l1[ mbPartIdx ]??
??? for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )?????????????
??????? if( sub_mb_type[ mbPartIdx ]??? !=??? B_Direct_8x8??? &&
??????????? SubMbPredMode( sub_mb_type[ mbPartIdx ] )??? !=??? Pred_L1 )
??????????? for( subMbPartIdx = 0;??
????????????????????? subMbPartIdx < NumSubMbPart( sub_mb_type[ mbPartIdx ] );
????????????????????? subMbPartIdx++)
??????????????? for( compIdx = 0; compIdx < 2; compIdx++ )?????????
??????????????????? mvd_l0[ mbPartIdx ][ subMbPartIdx ][ compIdx ]??
??? for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )?????????
??????? if( sub_mb_type[ mbPartIdx ]??? !=??? B_Direct_8x8??? &&
??????????? SubMbPredMode( sub_mb_type[ mbPartIdx ] )??? !=??? Pred_L0 )
??????????? for( subMbPartIdx = 0;??
????????????????????? subMbPartIdx < NumSubMbPart( sub_mb_type[ mbPartIdx ] );
????????????????????? subMbPartIdx++)
??????????????? for( compIdx = 0; compIdx < 2; compIdx++ )?????????
??????????????????? mvd_l1[ mbPartIdx ][ subMbPartIdx ][ compIdx ]??
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5477437.aspx
?
residual( ) {?
??? if( !entropy_coding_mode_flag )??????????
??????? residual_block = residual_block_cavlc??????????
??? else??????????
??????? residual_block = residual_block_cabac??????????
??? if( MbPartPredMode( mb_type, 0 )??? = =??? Intra_16x16 )??????????
??????? residual_block( Intra16x16DCLevel, 16 )????
??? for( i8x8 = 0; i8x8 < 4; i8x8++ )??? /* each luma 8x8 block */??????????
??????? for( i4x4 = 0; i4x4 < 4; i4x4++ )??? /* each 4x4 sub-block of block */??????????
??????????? if( CodedBlockPatternLuma & ( 1 << i8x8 ) ) {????????????
??????????????? if( MbPartPredMode( mb_type, 0 )??? = =??? Intra_16x16 )??????????
??????????????????? residual_block( Intra16x16ACLevel[ i8x8 * 4 + i4x4 ], 15 )???
??????????????? else??????????
??????????????????? residual_block( LumaLevel[ i8x8 * 4 + i4x4 ], 16 )??????????
??????????? } else {??????????
??????????????? if( MbPartPredMode( mb_type, 0 )??? = =??? Intra_16x16 )??????????
??????????????????? for( i = 0; i < 15; i++ )????????????
??????????????????????? Intra16x16ACLevel[ i8x8 * 4 + i4x4 ][ i ] = 0??????????
??????????????? else??????????
??????????????????? for( i = 0; i < 16; i++ )??????????
??????????????????????? LumaLevel[ i8x8 * 4 + i4x4 ][ i ] = 0??????????
??????????? }??????????
??? for( iCbCr = 0; iCbCr < 2; iCbCr++ )??????????
??????? if( CodedBlockPatternChroma & 3 )??? /* chroma DC residual present */???????????????????
??????????? residual_block( ChromaDCLevel[ iCbCr ], 4 )???????
??????? else??????????
??????????? for( i = 0; i < 4; i++ )??????????
??????????????? ChromaDCLevel[ iCbCr ][ i ] = 0??????????
??? for( iCbCr = 0; iCbCr < 2; iCbCr++ )??????????
??????? for( i4x4 = 0; i4x4 < 4; i4x4++ )??????????
??????????? if( CodedBlockPatternChroma & 2 )????
??????????????? /* chroma AC residual present */??
??????????????? residual_block( ChromaACLevel[ iCbCr ][ i4x4 ], 15 )??????
??????????? else??????????
??????????????? for( i = 0; i < 15; i++ )??????????
??????????????????? ChromaACLevel[ iCbCr ][ i4x4 ][ i ] = 0??????????
}
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5477442.aspx
?
?
residual_block_cavlc( coeffLevel, maxNumCoeff ) {? C????? Descriptor
??? for( i = 0; i < maxNumCoeff; i++ )??????????
??????? coeffLevel[ i ] = 0?????
??? // coeff_token????? 指明了非零系數的個數,拖尾系數的個數。??????
??? coeff_token?
??? if( TotalCoeff( coeff_token ) > 0 ) {??????????
??????? if( TotalCoeff( coeff_token ) > 10??? &&??? TrailingOnes( coeff_token ) <
3 )
??????????? suffixLength = 1??????????
??????? else??????????
??????????? suffixLength = 0??????????
??????? for( i = 0; i < TotalCoeff( coeff_token ); i++ )??????????
??????????? if( i < TrailingOnes( coeff_token ) ) {???????????
??????????????? // trailing_ones_sign_flag? 拖尾系數的符號
??????????????????? -???? 如果trailing_ones_sign_flag = 0,? 相應的拖尾系數是+1。
??????????????????? -???? 否則,trailing_ones_sign_flag =1,相應的拖尾系數是-1。?
??????????????? trailing_ones_sign_flag??
??????????????? level[ i ] = 1 – 2 * trailing_ones_sign_flag??????????
??????????? } else {??????????
??????????????? // level_prefix and level_suffix? 非零系數值的前綴和后綴。?
??????????????? level_prefix?
??????????????? levelCode = ( level_prefix << suffixLength )??????????
??????????????? if( suffixLength > 0??? | |??? level_prefix >= 14 ) {??????????
??????????????????? level_suffix??
??????????????????? levelCode += level_suffix??????????
??????????????? }??????????
??????????????? if( level_prefix??? = =??? 15??? &&??? suffixLength??? = =??? 0 )??????????
??????????????????? levelCode += 15??????????
??????????????? if( i??? = =??? TrailingOnes( coeff_token )??? &&????
????????????????????? TrailingOnes( coeff_token ) < 3 )
??????????????????? levelCode += 2??????????
??????????????? if( levelCode % 2??? = =??? 0 )??????????
??????????????????? level[ i ] = ( levelCode + 2 ) >> 1??????????
??????????????? else??????????
??????????????????? level[ i ] = ( –levelCode – 1 ) >> 1??????????
??????????????? if( suffixLength??? = =??? 0 )??????????
??????????????????? suffixLength = 1??????????
??????????????? if( Abs( level[ i ] )??? >??? ( 3 << ( suffixLength – 1 ) )??? &&????
????????????????????? suffixLength < 6 )
??????????????????? suffixLength++??????????
??????????? }??????????
??????? if( TotalCoeff( coeff_token ) < maxNumCoeff ) {??????????
??????????? // total_zeros??? 系數中 0 的總個數。
??????????? total_zeros???
??????????? zerosLeft = total_zeros??????????
??????? } else??????????
??????????? zerosLeft = 0??????????
??????? for( i = 0; i < TotalCoeff( coeff_token ) – 1; i++ ) {??????????
??????????? if( zerosLeft > 0 ) {??????????
???????????????
??????????????? run_before???
??????????????? run[ i ] = run_before??????????
??????????? } else??????????
??????????????? run[ i ] = 0??????????
??????????? zerosLeft = zerosLeft – run[ i ]??????????
??????? }??????????
??????? run[ TotalCoeff( coeff_token ) – 1 ] = zerosLeft??????????
??????? coeffNum = -1??????????
??????? for( i = TotalCoeff( coeff_token ) – 1; i >= 0; i-- ) {??????????
??????????? coeffNum += run[ i ] + 1??????????
??????????? coeffLevel[ coeffNum ] = level[ i ]????????????
??????? }??????????
??? }??????????
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5477464.aspx