日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

学习笔记(一)(x264编码流程)

發(fā)布時間:2023/12/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习笔记(一)(x264编码流程) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

學(xué)習(xí)筆記(一)(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>

?????? 經(jīng)過一段時間的學(xué)習(xí)我對h264也有了一個初步的大體的了解,今天在這里說一下h264中x264的開源code的編碼的解析并附一張我自己畫的流程圖便于大家理解,又不對的地方清大家指教一二,偶必定三顧茅廬尋得真理。:)

????????首先我們 進入x264.c中的main函數(shù).
剛開始是讀取默認參數(shù),如果你設(shè)置了參數(shù)的話會修改param的.
????? i_ret = Encode( &param, fin, fout );
這條語句使過程進入x264.c中的Encode函數(shù).(這個函數(shù)就是x264的編碼程序)
??????????????????? ?????????????????? X.264_encode函數(shù).
?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 )
}

這段調(diào)用了fseek()函數(shù),對輸入的視頻文件計算其總幀數(shù)。

B.?????函數(shù) h = x264_encoder_open( param )對不正確的參數(shù)進行修改,并對各結(jié)構(gòu)體參數(shù)和cabac編碼,預(yù)測等需要的參數(shù)進行初始化.然后才能進行下一步的編碼。

C.???? 函數(shù) pic = x264_picture_new( h );定義在/CORE/common.c中.

??????此函數(shù)的作用是分給能容納sizeof(x264_picture_t)字節(jié)數(shù)的空間,然后進行初始化.
????? 這里說明一下x264_picture_t和x264_frame_t的區(qū)別.前者是說明一個視頻序列中每幀的特點.后者存放每幀實際的象素值.

D.???????調(diào)用fread()函數(shù)一次讀入一幀,分亮度和色度分別讀取.這里要看到c語言中的File文件有一個文件位置指示器,調(diào)用fread()函數(shù)會使文件指示器自動移位,這就是一幀一幀讀取的實現(xiàn)過程.

?????? 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;
??????? }這里文件已經(jīng)指示器發(fā)生了位移
????????? 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 )函數(shù),該函數(shù)定義在/Enc/encoder.c中.

?????????函數(shù)中先定義了如下三個參數(shù):
?????????????? ?int???? i_nal_type;???nal存放的數(shù)據(jù)類型, 可以是sps,pps等多種.??????????????????
??????????????? int???? i_nal_ref_idc;? nal的優(yōu)先級,nal重要性的標志位.
??????????????? int???? i_slice_type;?? slice的類型的?

???????? 這里先說明一下:我們假設(shè)一個視頻序列如下:
?????????????????? I ?B ?B ?P ?B?B ? P
?????????我們編碼是按I? P? B? B? P? B? B的順序,這就是frame的編號
???????? 但是編碼器如何來區(qū)分他們并把他們重新排序呢?

???????? 我們來看看編碼器是如何區(qū)分讀入的一幀是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 )函數(shù)將這個B幀放進h->frame_next中.
??????????在h中同時定義了下面幾個幀數(shù)組用以實現(xiàn)幀的管理.
????????????? 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個函數(shù)(定義在/ENCODER/encoder.c中).
????????????? x264_encoder_frame_put_from_picture();
????????????? x264_encoder_frame_put() ();
????????????? x264_encoder_frame_get();
????????????? x264_frame_copy_picture();
????????這3個數(shù)組和4個函數(shù)可以說完成了整個幀的類型的判定問題.在不對P幀進行編碼之前,我們不對B幀進行編碼,只是把B幀放進緩沖區(qū)(就是前面提到的數(shù)組).
????????例如視頻序列:I?B? B? P? B? B? P
先確立第一個幀的類型,然后進行編碼.然后是2個B幀,我們把它放進緩沖區(qū)數(shù)組.然后是P幀,我們可以判定它的類型并進行編碼.同時,我們將緩沖區(qū)的B幀放進h->bframe_current[i],不過這時P幀前的兩個B幀并沒有編碼.當讀到P幀后面的第一個B幀時,我們實際上才將h->bframe_current數(shù)組中的第一個B幀編碼,也就是將在I幀后面的第一個B幀編碼.依此類推.(幀的有關(guān)理解學(xué)習(xí)筆記(二)

F.???? 建立參考幀列表的操作,這里調(diào)用了函數(shù)x264_reference_build_list( h, h->fdec->i_poc ); (定義在/ENCODER/encoder.c中).
??????? 光調(diào)用這個函數(shù)是不行的,它是和后面的這個函數(shù)(如下)一起配合工作的.
?????????????????????? 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中),這里面是編碼的最主要部分..
?????????下面這個循環(huán),它是采用for循環(huán)對一幀圖像的所有塊依次進行編碼.
??????????????? 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加載進來,放到一個數(shù)組里面,這個數(shù)組用來直接得到當前宏塊的左側(cè)和上面宏塊的相關(guān)值.要想得到當前塊的預(yù)測值,要先知道上面,左面的預(yù)測值,它的目的是替代getneighbour函數(shù).
??????????????? /* 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 );
??????? 到這就已經(jīng)完成編碼的主要過程了,后面就是熵編碼的過程了.

?

總結(jié)

以上是生活随笔為你收集整理的学习笔记(一)(x264编码流程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。