学习笔记(一)(x264编码流程)
學習筆記(一)(x264編碼流程)
<script type=text/javascript></script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript> </script> <script> window.google_render_ad(); </script>
?????? 經過一段時間的學習我對h264也有了一個初步的大體的了解,今天在這里說一下h264中x264的開源code的編碼的解析并附一張我自己畫的流程圖便于大家理解,又不對的地方清大家指教一二,偶必定三顧茅廬尋得真理。:)
????????首先我們 進入x264.c中的main函數.
剛開始是讀取默認參數,如果你設置了參數的話會修改param的.
????? i_ret = Encode( ¶m, fin, fout );
這條語句使過程進入x264.c中的Encode函數.(這個函數就是x264的編碼程序)
??????????????????? ?????????????????? X.264_encode函數.
?A?? ?? i_frame_total = 0;
if( !fseek( fyuv, 0, SEEK_END ) )
???? {
??????? int64_t i_size = ftell( fyuv );
??????? fseek( fyuv, 0, SEEK_SET );
??????? i_frame_total = i_size / ( param->i_width * param->i_height * 3 / 2 )
}
這段調用了fseek()函數,對輸入的視頻文件計算其總幀數。
B.?????函數 h = x264_encoder_open( param )對不正確的參數進行修改,并對各結構體參數和cabac編碼,預測等需要的參數進行初始化.然后才能進行下一步的編碼。
C.???? 函數 pic = x264_picture_new( h );定義在/CORE/common.c中.
??????此函數的作用是分給能容納sizeof(x264_picture_t)字節數的空間,然后進行初始化.
????? 這里說明一下x264_picture_t和x264_frame_t的區別.前者是說明一個視頻序列中每幀的特點.后者存放每幀實際的象素值.
D.???????調用fread()函數一次讀入一幀,分亮度和色度分別讀取.這里要看到c語言中的File文件有一個文件位置指示器,調用fread()函數會使文件指示器自動移位,這就是一幀一幀讀取的實現過程.
?????? for( i_frame = 0, i_file = 0; i_ctrl_c == 0 ; i_frame++ )
??? {
??????? int???????? i_nal;
??????? x264_nal_t? *nal;
?int???????? i;
/* read a frame */
??????? if( fread( pic->plane[0], 1, param->i_width * param->i_height, fyuv ) <= 0 ||
??????????? fread( pic->plane[1], 1, param->i_width * param->i_height / 4, fyuv ) <= 0 ||
??????????? fread( pic->plane[2], 1, param->i_width * param->i_height / 4, fyuv ) <= 0 )
??????? {
??????????? break;
??????? }這里文件已經指示器發生了位移
????????? if( x264_encoder_encode( h, &nal, &i_nal, pic ) < 0 )
??????? {
??????????? fprintf( stderr, “x264_encoder_encode failed/n” );
??????? }
??????? ……
??????? }
E.????? 進入x264_encoder_encode( h, &nal, &i_nal, pic )函數,該函數定義在/Enc/encoder.c中.
?????????函數中先定義了如下三個參數:
?????????????? ?int???? i_nal_type;???nal存放的數據類型, 可以是sps,pps等多種.??????????????????
??????????????? int???? i_nal_ref_idc;? nal的優先級,nal重要性的標志位.
??????????????? int???? i_slice_type;?? slice的類型的?
???????? 這里先說明一下:我們假設一個視頻序列如下:
?????????????????? I ?B ?B ?P ?B?B ? P
?????????我們編碼是按I? P? B? B? P? B? B的順序,這就是frame的編號
???????? 但是編碼器如何來區分他們并把他們重新排序呢?
???????? 我們來看看編碼器是如何區分讀入的一幀是I幀,P幀,或者B幀?
???????? 以I ? B ? B ? P ? B?B ? P為例.
?
??????? if( h->i_frame % (h->param.i_iframe * h->param.i_idrframe) == 0 ){
???????????????? 確定這是立即刷新片.
?????????}
?????????? if( h->param.i_bframe > 0 )//判斷h是否為B幀然后對其進行下一步操作.
????????? 我們編完I幀后碰到了一個B幀,這時我們先不對它進編碼.而是采用frame =???????? x264_encoder_frame_put_from_picture( h, h->frame_next, pic )函數將這個B幀放進h->frame_next中.
??????????在h中同時定義了下面幾個幀數組用以實現幀的管理.
????????????? x264_frame_t?? *bframe_current[X264_BFRAME_MAX]; /* store the sequence of b frame being encoded */
??????????????x264_frame_t??? *frame_next[X264_BFRAME_MAX+1];?? /* store the next sequence of??frames to be encoded *///這個是定義下一個幀,但不一定是B幀.
???????????? x264_frame_t??? *frame_unused[X264_BFRAME_MAX+1]; /* store unused frames */
???????? 同時還有下面4個函數(定義在/ENCODER/encoder.c中).
????????????? x264_encoder_frame_put_from_picture();
????????????? x264_encoder_frame_put() ();
????????????? x264_encoder_frame_get();
????????????? x264_frame_copy_picture();
????????這3個數組和4個函數可以說完成了整個幀的類型的判定問題.在不對P幀進行編碼之前,我們不對B幀進行編碼,只是把B幀放進緩沖區(就是前面提到的數組).
????????例如視頻序列:I?B? B? P? B? B? P
先確立第一個幀的類型,然后進行編碼.然后是2個B幀,我們把它放進緩沖區數組.然后是P幀,我們可以判定它的類型并進行編碼.同時,我們將緩沖區的B幀放進h->bframe_current[i],不過這時P幀前的兩個B幀并沒有編碼.當讀到P幀后面的第一個B幀時,我們實際上才將h->bframe_current數組中的第一個B幀編碼,也就是將在I幀后面的第一個B幀編碼.依此類推.(幀的有關理解學習筆記(二))
F.???? 建立參考幀列表的操作,這里調用了函數x264_reference_build_list( h, h->fdec->i_poc ); (定義在/ENCODER/encoder.c中).
??????? 光調用這個函數是不行的,它是和后面的這個函數(如下)一起配合工作的.
?????????????????????? if( i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE )//判斷為B幀.
?????????????????????? {
??????????????????????? x264_reference_update( h );
??????????????????????? }
??????? If條件是判斷當前幀是否是B幀,如果是的話就不更新參考列表,因為B幀本來就不能作為參考幀嘛!如果是I幀或P幀的話,就更新參考幀列表.
G.???? 下面是寫slice的操作.
???????????????????? /* Init bitstream context */
???????????????????? h->out.i_nal = 0;//out的聲明在bs.h中.
???????????????????? bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream );//空出8位.
?
?????????????????????/* Write SPS and PPS */
???????????????????? if( i_nal_type == NAL_SLICE_IDR )
???????????????????????? {
?????????????????????????? /* generate sequence parameters */
?????????????????????????? ?x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );
??????????????????????????? x264_sps_write( &h->out.bs, h->sps );
??????????????????????????? x264_nal_end( h );
?
???????????????????????????? /* generate picture parameters */
?????????????????????????? ?x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST );
??????????????????????????? x264_pps_write( &h->out.bs, h->pps );
?????????????????????????? ?x264_nal_end( h );
??????????????????????????
?????????x264_slice_write()(定義在/ENCODER/encoder.c中),這里面是編碼的最主要部分..
?????????下面這個循環,它是采用for循環對一幀圖像的所有塊依次進行編碼.
??????????????? for( mb_xy = 0, i_skip = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )//h->sps->i_mb_width指的是從寬度上說有多少個宏快.??? {
?????????????? ?const int i_mb_y = mb_xy / h->sps->i_mb_width;
????????????????const int i_mb_x = mb_xy % h->sps->i_mb_width;//這兩個變量是定義宏塊的位置..
?
??????????????? ?/* load cache */
??????????????? x264_macroblock_cache_load( h, i_mb_x, i_mb_y );//是把當前宏塊的up宏塊和left宏塊的intra4×4_pred_mode,non_zero_count加載進來,放到一個數組里面,這個數組用來直接得到當前宏塊的左側和上面宏塊的相關值.要想得到當前塊的預測值,要先知道上面,左面的預測值,它的目的是替代getneighbour函數.
??????????????? /* analyse parameters
??????????????? * Slice I: choose I_4×4 or I_16×16 mode
??????????????? * Slice P: choose between using P mode or intra (4×4 or 16×16)
??????????????? * */
?????????????????TIMER_START( i_mtime_analyse );
??????????????? ?x264_macroblock_analyse( h );//定義在analyse.h中.
?????????????????TIMER_STOP( i_mtime_analyse );
?
???????????????? ?/* encode this macrobock -> be carefull it can change the mb type to P_SKIP if needed */
????????????????? TIMER_START( i_mtime_encode );
????????????????? x264_macroblock_encode( h );//定義在Enc/encoder.c中.
????????????????? TIMER_STOP( i_mtime_encode );
??????? 到這就已經完成編碼的主要過程了,后面就是熵編碼的過程了.
?
總結
以上是生活随笔為你收集整理的学习笔记(一)(x264编码流程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NVIDIA史上最鸡肋、还特长寿的显卡:
- 下一篇: 陕西养老保险app怎么给爸妈缴费