1. 程式人生 > >JM、H.264中一些引數的設定和含義

JM、H.264中一些引數的設定和含義

一·引數說明 
這一節闡述的是encoder.cfg 中的引數對編碼過程的影響 
要注意的是encoder.cfg 中的引數跟input 結構體中的變數是一一對應的 

   StartFrame:從視訊流的第幾幀開始編碼 
  FramesToBeEncoded:指明瞭除去 B幀後將要被編碼的幀數 
input->no_frames = FramesToBeEncoded 
  FrameSkip:指明瞭編碼過程中跳過的幀數,中間有 B 幀也算跳過一幀。 
   NumberBFrames:相鄰 I、P幀或相鄰的 P幀之間的 B 幀個數,必須有 
NumberBFrames< FrameSkip 
input->successive_Bframe = NumberBFrames 
   IntraPeriod:I 幀出現的頻率。若 IntraPeriod="3",則每 3 幀(不含 B 幀)中有一 I 幀; 
IntraPeriod="0" 時只有第一幀是 I 幀。 
   IDRIntraEnable:此值為1時每個 I幀都是 IDR,否則只有第一個 I幀是 IDR。 

舉例:在 StartFrame="0" 
FramesToBeEncoded="5" 
FrameSkip="3" 
NumberBFrames="2" 
IntraPeriod="3" 
IDRIntraEnable="1" 
的情況下編碼情況如下,其中紅色代表 IDR 幀  
表 1 
視訊流  0  1  2  3  4  5 6 7 8 9 10 11 12 13 14  15  16  17
編碼流  I  B  B    P  B B   P B B   I B B    P   
編碼順序  0  2  3    1  5 6   4 8 9   7 11 12    10   
二·pic_order_cnt_type 為 0 的情況 
這種情況下顯式的計算 POC 
(1)  編碼端 I 幀或 P 幀 toppoc 的計算 
這個過程在 main()函式的組迴圈 
“for (img->number=0; img->number < input->no_frames; img->number++){ }” 
中實現 
z  IntraPeriod或 IDRIntraEnable 為零時 
這種情況下只有第一個 I 幀是 IDR 幀,比較簡單。對於 I幀或 P 幀,其頂場的 POC 為 
(img->number) * (2*(input->successive_Bframe+1)) z  IntraPeriod和 IDRIntraEnable 都不為零時 
這種情況下每個 I 幀都是 IDR 幀,其 POC 必須設定為零, I幀出現的頻率為 IntraPeriod,
故其 toppoc為 
(img->number % input->intra_period) * (2*(input->successive_Bframe+1)) 
z  說明: 
原程式中使用了巨集定義 IMG_NUMBER 
“#define IMG_NUMBER (img->number - start_frame_no_in_this_IGOP)” 
通過搜start_frame_no_in_this_IGOP可知這個變數在NumberOfFrameInSecondIGOP為0
(encoder_main.cfg 中就是這樣設定的)時恆為 0,故有 
IMG_NUMBER = img->number 
(2)  編碼端 B幀 POC 的計算 
由表一可知,在編完一 I 幀或 P 幀之後才開始對它前面的 B幀進行編碼 

for (img->number=0; img->number < input->no_frames; img->number++) 

……I,P 幀編碼…… 
if ((input->successive_Bframe != 0) && (IMG_NUMBER > 0))   

…… 
for(img->b_frame_to_code=1; img->b_frame_to_code<=input->successive_Bframe;    
img->b_frame_to_code++) 



z  IntraPeriod或 IDRIntraEnable 為零時toppoc 等於 
2+(img->number-1) * (2*(input->successive_Bframe+1))  
+2* (img->b_frame_to_code-1) 
a)  第一個 2 指得是 IDR 的兩個場; 
b)  img->number要減一是因為要對當前幀(img->number)前面的 B幀進行編碼; 

z  IntraPeriod和 IDRIntraEnable 都不為零時 toppoc等於 
2+(img->number % input->intra_period-1) * (2*(input->successive_Bframe+1)) 
+2* (img->b_frame_to_code-1) 
IDR 幀前面 
(3)  toppoc 到 pic_order_cnt_lsb 的轉化 
img->pic_order_cnt_lsb 
=img->toppoc & 
~((((unsigned int)( –1)) << (log2_max_pic_order_cnt_lsb_minus4+4))) 

z  (unsigned int)(-1)的十六進位制形式是 0xffffffff,即它的每一位都是 1; 
z  log2_max_pic_order_cnt_lsb_minus4+4是圖象數目(包括 B 幀)最大值的位數 z  當 toppoc >0時,img->pic_order_cnt_lsb=img->toppoc 
當 toppoc <0時,img->pic_order_cnt_lsb= max_pic_order_cnt+ img->toppoc 
其中 max_pic_order_cnt=1<<( log2_max_pic_order_cnt_lsb_minus4+4) 
z  疑問: 
不知道 toppoc 到 pic_order_cnt_lsb 這個過程有什麼意義; 
POC 的值會從 0 變到很大,為什麼不對它進行熵編碼; 
(4)  解碼端 toppoc 的恢復 
此過程在函式 decode_poc 中執行。其思想是對於 IDR 前的 B 幀 
Toppoc = pic_order_cnt_lsb - max_pic_order_cnt 
否則  
Toppoc = pic_order_cnt_lsb 
是否減去 max_pic_order_cnt 由變數 PicOrderCntMsb 決定,對於 IDR 前的 B 幀 
PicOrderCntMsb = (– max_pic_order_cnt) 
否則 
PicOrderCntMsb = 0 
到這就不難理解 PicOrderCntMsb 的含義了, PicOrderCntMsb 反映了 toppoc的值是否小於 0。
至於另外兩個引數:PrevPicOrderCntMsb 總是為 0;PrevPicOrderCntLsb 在當前圖象是 IDR
或 IDR 前(視訊流中)的 B 幀時為0,否則等於前一圖象(編碼序列中)的 PicOrderCntLsb。  
三·pic_order_cnt_type 為 1 的情況 
這種情況下通過 frame_num來計算 POC 
(1)frame_num 簡介 
參考《畢厚傑》7.3.4 節中 frame_num 條款的解釋,對於表 1 中的圖象序列,其 frame_num      
的值參考如下: 

表 2 
視訊流  0  1  2  4  5 6 8 9 10 12 13 14  16 
編碼流  I  B  B  P  B B P B B I B B P 
編碼順序  0  2  3  1  5 6 4 8 9  7 11 12  10 
frame_num  0  2  2  1  3 3 2 1 1  0 2 2 1 
poc  0  2  4  6  8 10 12 -4 -2 0 2 4 6 

(2)演算法思想以及其解碼端的實現 
z  對於 IDR 幀,poc = 0; 
z  對於 I 幀或P 幀 
poc = frame_num*2*(input->successive_Bframe+1) 
或   
poc = 2*(input->successive_Bframe+1) 
+ (frame_num – 1)*2*(input->successive_Bframe+1) 解碼端實現 
poc = img->ExpectedPicOrderCnt 
+ img->delta_pic_order_cnt[0]   (在 I,P 幀下為 0) 
z  對於 I 幀或P 幀之前的 B 幀(視訊流中) 
poc = (frame_num – 1)*2*(input->successive_Bframe+1) 
– 2*(input->successive_Bframe+1 – img->b_frame_to_code) 
或 
poc = 2*(input->successive_Bframe+1) 
+ (frame_num – 1 – 1)*2*(input->successive_Bframe+1) 
+ 2*( img->b_frame_to_code – 1) 
– 2*input->successive_Bframe 
解碼端的實現 
poc = img->ExpectedPicOrderCnt 
+ img->delta_pic_order_cnt[0] 
+ active_sps->offset_for_non_ref_pic 
z  變數說明 
a)  其中 img->b_frame_to_code請參見標題一·(2) 
b)  img->disposable_flag = (nalu->nal_reference_idc = = 0),而 nal_reference_idc 只在 B 幀時
為0,即img->disposable_flag只在B幀時為1。這也是在B幀情況下img->AbsFrameNum
要比 I 幀或P 幀多減去一個 1 的原因。 
c)  其它變數參見下面小題; 
(3)編碼端引數設定 
a)  img->num_ref_frames_in_pic_order_cnt_cycle: 
這個引數在 init_poc( )函式中設定為 1 後就再沒改動過; 
b)  img->offset_for_ref_frame[0]  : 
在 StoredBPictures為0 時等於 2*(input->successive_Bframe+1); 
c)  img->offset_for_ref_frame[1]  : 
沒什麼用,264 標頭檔案中不會儲存此變數; 
d)  img->delta_pic_order_cnt[0]  : 
這個變數只對 B 幀有用,等於 2*(img->b_frame_to_code –1);  對於 I 幀或 P 幀,   
其值為 0; 
e)  active_sps->offset_for_non_ref_pic: 
只對 B 幀有用,在 StoredBPictures 為0 時等於–2*input->successive_Bframe,