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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

x264代码剖析(十四):核心算法之宏块编码函数x264_macroblock_encode()

發(fā)布時(shí)間:2025/4/5 编程问答 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 x264代码剖析(十四):核心算法之宏块编码函数x264_macroblock_encode() 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

x264代碼剖析(十四):核心算法之宏塊編碼函數(shù)x264_macroblock_encode()

?

? ? ? ? 宏塊編碼函數(shù)x264_macroblock_encode()是完成變換與量化的主要函數(shù),而x264_macroblock_encode()調(diào)用了x264_macroblock_encode_internal()函數(shù),在x264_macroblock_encode_internal()函數(shù)中,主要完成了如下功能:

?

x264_macroblock_encode_skip():編碼Skip類型宏塊。

x264_mb_encode_i16x16():編碼Intra16x16類型的宏塊。該函數(shù)除了進(jìn)行DCT變換之外,還對(duì)16個(gè)小塊的DC系數(shù)進(jìn)行了Hadamard變換。

x264_mb_encode_i4x4():編碼Intra4x4類型的宏塊。

幀間宏塊編碼:這一部分代碼直接寫在了函數(shù)體里面。

x264_mb_encode_chroma():編碼色度塊。

?

? ? ? ? x264_macroblock_encode()函數(shù)與x264_macroblock_encode_internal()函數(shù)都處于encoder文件夾內(nèi)的macroblock.c,其調(diào)用關(guān)系圖如下所示:

?



1x264_macroblock_encode()函數(shù)

?

? ? ? ? x264_macroblock_encode()函數(shù)處于encoder文件夾內(nèi)的macroblock.c中,x264_macroblock_encode()封裝了x264_macroblock_encode_internal()。如果色度模式是YUV444的話,傳遞的參數(shù)plane_count=3chroma=0;如果不是YUV444的話,傳遞的參數(shù)plane_count=1chroma=1

?

對(duì)應(yīng)的代碼如下:

?

/******************************************************************/ /******************************************************************/ /* ======Analysed by RuiDong Fang ======Csdn Blog:http://blog.csdn.net/frd2009041510 ======Date:2016.03.22*/ /******************************************************************/ /******************************************************************//************====== 宏塊編碼函數(shù)x264_macroblock_encode() ======************/ /* 功能:x264_macroblock_encode()封裝了x264_macroblock_encode_internal(),即編碼的內(nèi)部函數(shù)——?dú)埐頓CT變換、量化 */ void x264_macroblock_encode( x264_t *h ) {if( CHROMA444 )x264_macroblock_encode_internal( h, 3, 0 );//YUV444相當(dāng)于把YUV3個(gè)分量都當(dāng)做Y編碼elsex264_macroblock_encode_internal( h, 1, 1 ); }

?

2x264_macroblock_encode_internal()函數(shù)

?

? ? ? ? x264_macroblock_encode_internal()函數(shù)也處于encoder文件夾內(nèi)的macroblock.c中,具體的代碼分析如下:

?

/************====== 宏塊編碼函數(shù)x264_macroblock_encode_internal() ======************/ /* 功能:調(diào)用了編碼-殘差DCT變換、量化-內(nèi)部函數(shù) */ /****************************************************************************** x264_macroblock_encode:*****************************************************************************/ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_count, int chroma ) {int i_qp = h->mb.i_qp;int b_decimate = h->mb.b_dct_decimate;int b_force_no_skip = 0;int nz;h->mb.i_cbp_luma = 0;for( int p = 0; p < plane_count; p++ )h->mb.cache.non_zero_count[x264_scan8[LUMA_DC+p]] = 0;/*======== PCM ========*/if( h->mb.i_type == I_PCM )//PCM{/* if PCM is chosen, we need to store reconstructed frame data */for( int p = 0; p < plane_count; p++ )h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fdec[p], FDEC_STRIDE, h->mb.pic.p_fenc[p], FENC_STRIDE, 16 );if( chroma ){int height = 16 >> CHROMA_V_SHIFT;h->mc.copy[PIXEL_8x8] ( h->mb.pic.p_fdec[1], FDEC_STRIDE, h->mb.pic.p_fenc[1], FENC_STRIDE, height );h->mc.copy[PIXEL_8x8] ( h->mb.pic.p_fdec[2], FDEC_STRIDE, h->mb.pic.p_fenc[2], FENC_STRIDE, height );}return;}if( !h->mb.b_allow_skip ){b_force_no_skip = 1;if( IS_SKIP(h->mb.i_type) ){if( h->mb.i_type == P_SKIP )h->mb.i_type = P_L0;else if( h->mb.i_type == B_SKIP )h->mb.i_type = B_DIRECT;}}//根據(jù)不同的宏塊類型,進(jìn)行編碼/*======== P-skip ========*/if( h->mb.i_type == P_SKIP ){/* don't do pskip motion compensation if it was already done in macroblock_analyse */if( !h->mb.b_skip_mc ){int mvx = x264_clip3( h->mb.cache.mv[0][x264_scan8[0]][0],h->mb.mv_min[0], h->mb.mv_max[0] );int mvy = x264_clip3( h->mb.cache.mv[0][x264_scan8[0]][1],h->mb.mv_min[1], h->mb.mv_max[1] );for( int p = 0; p < plane_count; p++ )h->mc.mc_luma( h->mb.pic.p_fdec[p], FDEC_STRIDE,&h->mb.pic.p_fref[0][0][p*4], h->mb.pic.i_stride[p],mvx, mvy, 16, 16, &h->sh.weight[0][p] );if( chroma ){int v_shift = CHROMA_V_SHIFT;int height = 16 >> v_shift;/* Special case for mv0, which is (of course) very common in P-skip mode. */if( mvx | mvy )h->mc.mc_chroma( h->mb.pic.p_fdec[1], h->mb.pic.p_fdec[2], FDEC_STRIDE,h->mb.pic.p_fref[0][0][4], h->mb.pic.i_stride[1],mvx, 2*mvy>>v_shift, 8, height );elseh->mc.load_deinterleave_chroma_fdec( h->mb.pic.p_fdec[1], h->mb.pic.p_fref[0][0][4],h->mb.pic.i_stride[1], height );if( h->sh.weight[0][1].weightfn )h->sh.weight[0][1].weightfn[8>>2]( h->mb.pic.p_fdec[1], FDEC_STRIDE,h->mb.pic.p_fdec[1], FDEC_STRIDE,&h->sh.weight[0][1], height );if( h->sh.weight[0][2].weightfn )h->sh.weight[0][2].weightfn[8>>2]( h->mb.pic.p_fdec[2], FDEC_STRIDE,h->mb.pic.p_fdec[2], FDEC_STRIDE,&h->sh.weight[0][2], height );}}x264_macroblock_encode_skip( h ); 編碼skip類型宏塊return;}/*======== B-skip ========*/if( h->mb.i_type == B_SKIP ){/* don't do bskip motion compensation if it was already done in macroblock_analyse */if( !h->mb.b_skip_mc )x264_mb_mc( h );x264_macroblock_encode_skip( h ); 編碼skip類型宏塊return;}/*======== 幀內(nèi) ========*/if( h->mb.i_type == I_16x16 ){h->mb.b_transform_8x8 = 0;for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp )x264_mb_encode_i16x16( h, p, i_qp ); 如果是Intra16x16類型,調(diào)用x264_mb_encode_i16x16()編碼宏塊(分別編碼Y,U,V)}else if( h->mb.i_type == I_8x8 ){h->mb.b_transform_8x8 = 1;/* If we already encoded 3 of the 4 i8x8 blocks, we don't have to do them again. */if( h->mb.i_skip_intra ){h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fdec[0], FDEC_STRIDE, h->mb.pic.i8x8_fdec_buf, 16, 16 );M32( &h->mb.cache.non_zero_count[x264_scan8[ 0]] ) = h->mb.pic.i8x8_nnz_buf[0];M32( &h->mb.cache.non_zero_count[x264_scan8[ 2]] ) = h->mb.pic.i8x8_nnz_buf[1];M32( &h->mb.cache.non_zero_count[x264_scan8[ 8]] ) = h->mb.pic.i8x8_nnz_buf[2];M32( &h->mb.cache.non_zero_count[x264_scan8[10]] ) = h->mb.pic.i8x8_nnz_buf[3];h->mb.i_cbp_luma = h->mb.pic.i8x8_cbp;/* In RD mode, restore the now-overwritten DCT data. */if( h->mb.i_skip_intra == 2 )h->mc.memcpy_aligned( h->dct.luma8x8, h->mb.pic.i8x8_dct_buf, sizeof(h->mb.pic.i8x8_dct_buf) );}for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ){for( int i = (p == 0 && h->mb.i_skip_intra) ? 3 : 0 ; i < 4; i++ ){int i_mode = h->mb.cache.intra4x4_pred_mode[x264_scan8[4*i]];x264_mb_encode_i8x8( h, p, i, i_qp, i_mode, NULL, 1 ); 如果是Intra8x8類型,循環(huán)4次調(diào)用x264_mb_encode_i8x8()編碼宏塊}}}else if( h->mb.i_type == I_4x4 ){h->mb.b_transform_8x8 = 0;/* If we already encoded 15 of the 16 i4x4 blocks, we don't have to do them again. */if( h->mb.i_skip_intra ){h->mc.copy[PIXEL_16x16]( h->mb.pic.p_fdec[0], FDEC_STRIDE, h->mb.pic.i4x4_fdec_buf, 16, 16 );M32( &h->mb.cache.non_zero_count[x264_scan8[ 0]] ) = h->mb.pic.i4x4_nnz_buf[0];M32( &h->mb.cache.non_zero_count[x264_scan8[ 2]] ) = h->mb.pic.i4x4_nnz_buf[1];M32( &h->mb.cache.non_zero_count[x264_scan8[ 8]] ) = h->mb.pic.i4x4_nnz_buf[2];M32( &h->mb.cache.non_zero_count[x264_scan8[10]] ) = h->mb.pic.i4x4_nnz_buf[3];h->mb.i_cbp_luma = h->mb.pic.i4x4_cbp;/* In RD mode, restore the now-overwritten DCT data. */if( h->mb.i_skip_intra == 2 )h->mc.memcpy_aligned( h->dct.luma4x4, h->mb.pic.i4x4_dct_buf, sizeof(h->mb.pic.i4x4_dct_buf) );}for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ){for( int i = (p == 0 && h->mb.i_skip_intra) ? 15 : 0 ; i < 16; i++ ){pixel *p_dst = &h->mb.pic.p_fdec[p][block_idx_xy_fdec[i]];int i_mode = h->mb.cache.intra4x4_pred_mode[x264_scan8[i]];if( (h->mb.i_neighbour4[i] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP )/* emulate missing topright samples */MPIXEL_X4( &p_dst[4-FDEC_STRIDE] ) = PIXEL_SPLAT_X4( p_dst[3-FDEC_STRIDE] );x264_mb_encode_i4x4( h, p, i, i_qp, i_mode, 1 ); 如果是Intra4x4類型,循環(huán)16次調(diào)用x264_mb_encode_i4x4()編碼宏塊}}}/*======== 幀間 ========*/else /* Inter MB */{int i_decimate_mb = 0;/* Don't repeat motion compensation if it was already done in non-RD transform analysis */if( !h->mb.b_skip_mc )x264_mb_mc( h );if( h->mb.b_lossless )//===================lossless情況{if( h->mb.b_transform_8x8 )for( int p = 0; p < plane_count; p++ )for( int i8x8 = 0; i8x8 < 4; i8x8++ ){int x = i8x8&1;int y = i8x8>>1;nz = h->zigzagf.sub_8x8( h->dct.luma8x8[p*4+i8x8], h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE,h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE );STORE_8x8_NNZ( p, i8x8, nz );h->mb.i_cbp_luma |= nz << i8x8;}elsefor( int p = 0; p < plane_count; p++ )for( int i4x4 = 0; i4x4 < 16; i4x4++ ){nz = h->zigzagf.sub_4x4( h->dct.luma4x4[p*16+i4x4],h->mb.pic.p_fenc[p]+block_idx_xy_fenc[i4x4],h->mb.pic.p_fdec[p]+block_idx_xy_fdec[i4x4] );h->mb.cache.non_zero_count[x264_scan8[p*16+i4x4]] = nz;h->mb.i_cbp_luma |= nz << (i4x4>>2);}}else if( h->mb.b_transform_8x8 )//===================DCT8x8情況{ALIGNED_ARRAY_N( dctcoef, dct8x8,[4],[64] );b_decimate &= !h->mb.b_trellis || !h->param.b_cabac; // 8x8 trellis is inherently optimal decimation for CABACfor( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ){CLEAR_16x16_NNZ( p );h->dctf.sub16x16_dct8( dct8x8, h->mb.pic.p_fenc[p], h->mb.pic.p_fdec[p] );h->nr_count[1+!!p*2] += h->mb.b_noise_reduction * 4;int plane_cbp = 0;for( int idx = 0; idx < 4; idx++ ){nz = x264_quant_8x8( h, dct8x8[idx], i_qp, ctx_cat_plane[DCT_LUMA_8x8][p], 0, p, idx );if( nz ){h->zigzagf.scan_8x8( h->dct.luma8x8[p*4+idx], dct8x8[idx] );if( b_decimate ){int i_decimate_8x8 = h->quantf.decimate_score64( h->dct.luma8x8[p*4+idx] );i_decimate_mb += i_decimate_8x8;if( i_decimate_8x8 >= 4 )plane_cbp |= 1<<idx;}elseplane_cbp |= 1<<idx;}}if( i_decimate_mb >= 6 || !b_decimate ){h->mb.i_cbp_luma |= plane_cbp;FOREACH_BIT( idx, 0, plane_cbp ){h->quantf.dequant_8x8( dct8x8[idx], h->dequant8_mf[p?CQM_8PC:CQM_8PY], i_qp );h->dctf.add8x8_idct8( &h->mb.pic.p_fdec[p][8*(idx&1) + 8*(idx>>1)*FDEC_STRIDE], dct8x8[idx] );STORE_8x8_NNZ( p, idx, 1 );}}}}else//===================最普通的情況{// 幀間預(yù)測:16x16 宏塊被劃分為8x8,每個(gè)8x8再次被劃分為4x4ALIGNED_ARRAY_N( dctcoef, dct4x4,[16],[16] );for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ){CLEAR_16x16_NNZ( p );//16x16DCT(實(shí)際上分解為16個(gè)4x4DCT) //求編碼幀p_fenc和重建幀p_fdec之間的殘差,然后進(jìn)行DCT變換h->dctf.sub16x16_dct( dct4x4, h->mb.pic.p_fenc[p], h->mb.pic.p_fdec[p] ); ///對(duì)16x16塊調(diào)用x264_dct_function_t的sub16x16_dct()匯編函數(shù),求得編碼宏塊數(shù)據(jù)p_fenc與重建宏塊數(shù)據(jù)p_fdec之間的殘差(“sub”),并對(duì)殘差進(jìn)行DCT變換if( h->mb.b_noise_reduction ){h->nr_count[0+!!p*2] += 16;for( int idx = 0; idx < 16; idx++ )h->quantf.denoise_dct( dct4x4[idx], h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 );}int plane_cbp = 0;//16x16的塊分成4個(gè)8x8的塊for( int i8x8 = 0; i8x8 < 4; i8x8++ ){int i_decimate_8x8 = b_decimate ? 0 : 6;int nnz8x8 = 0;if( h->mb.b_trellis ){for( int i4x4 = 0; i4x4 < 4; i4x4++ ){int idx = i8x8*4+i4x4;if( x264_quant_4x4_trellis( h, dct4x4[idx], CQM_4PY, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, !!p, p*16+idx ) ){h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4[idx] );h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[p?CQM_4PC:CQM_4PY], i_qp );if( i_decimate_8x8 < 6 )i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+idx] );h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = 1;nnz8x8 = 1;}}}else{//8x8的塊分成4個(gè)4x4的塊,每個(gè)4x4的塊再分別進(jìn)行量化nnz8x8 = nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[CQM_4PY][i_qp], h->quant4_bias[CQM_4PY][i_qp] ); /分成4個(gè)8x8的塊,對(duì)每個(gè)8x8塊分別調(diào)用x264_quant_function_t的quant_4x4x4()匯編函數(shù)進(jìn)行量化if( nz ){FOREACH_BIT( idx, i8x8*4, nz ){h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4[idx] );//建立重建幀h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[p?CQM_4PC:CQM_4PY], i_qp ); //分成16個(gè)4x4的塊,對(duì)每個(gè)4x4塊分別調(diào)用x264_quant_function_t的dequant_4x4()匯編函數(shù)進(jìn)行反量化(用于重建幀)if( i_decimate_8x8 < 6 )i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+idx] );h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = 1;}}}if( nnz8x8 ){i_decimate_mb += i_decimate_8x8;if( i_decimate_8x8 < 4 )STORE_8x8_NNZ( p, i8x8, 0 );elseplane_cbp |= 1<<i8x8;}}if( i_decimate_mb < 6 ){plane_cbp = 0;CLEAR_16x16_NNZ( p );}else{h->mb.i_cbp_luma |= plane_cbp;FOREACH_BIT( i8x8, 0, plane_cbp ){//用于建立重建幀 //殘差進(jìn)行DCT反變換之后,疊加到預(yù)測數(shù)據(jù)上h->dctf.add8x8_idct( &h->mb.pic.p_fdec[p][(i8x8&1)*8 + (i8x8>>1)*8*FDEC_STRIDE], &dct4x4[i8x8*4] ); 分成4個(gè)8x8的塊,對(duì)每個(gè)8x8塊分別調(diào)用x264_dct_function_t的add8x8_idct()匯編函數(shù),對(duì)殘差進(jìn)行DCT反變換,并將反變換后的數(shù)據(jù)疊加(“add”)至預(yù)測數(shù)據(jù)上(用于重建幀)}}}}}/* encode chroma */if( chroma ){if( IS_INTRA( h->mb.i_type ) ){int i_mode = h->mb.i_chroma_pred_mode;if( h->mb.b_lossless )x264_predict_lossless_chroma( h, i_mode );else{h->predict_chroma[i_mode]( h->mb.pic.p_fdec[1] );h->predict_chroma[i_mode]( h->mb.pic.p_fdec[2] );}}/* encode the 8x8 blocks */x264_mb_encode_chroma( h, !IS_INTRA( h->mb.i_type ), h->mb.i_chroma_qp ); /編碼色度塊}elseh->mb.i_cbp_chroma = 0;/* store cbp */int cbp = h->mb.i_cbp_chroma << 4 | h->mb.i_cbp_luma;if( h->param.b_cabac )cbp |= h->mb.cache.non_zero_count[x264_scan8[LUMA_DC ]] << 8| h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]] << 9| h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]] << 10;h->mb.cbp[h->mb.i_mb_xy] = cbp;/* Check for P_SKIP* XXX: in the me perhaps we should take x264_mb_predict_mv_pskip into account* (if multiple mv give same result)*/if( !b_force_no_skip ){if( h->mb.i_type == P_L0 && h->mb.i_partition == D_16x16 &&!(h->mb.i_cbp_luma | h->mb.i_cbp_chroma) &&M32( h->mb.cache.mv[0][x264_scan8[0]] ) == M32( h->mb.cache.pskip_mv )&& h->mb.cache.ref[0][x264_scan8[0]] == 0 ){h->mb.i_type = P_SKIP;}/* Check for B_SKIP */if( h->mb.i_type == B_DIRECT && !(h->mb.i_cbp_luma | h->mb.i_cbp_chroma) ){h->mb.i_type = B_SKIP;}} }


? ? ? ? 從源代碼可以看出,x264_macroblock_encode_internal()的流程大致如下:


1)、如果是Skip類型,調(diào)用x264_macroblock_encode_skip()編碼宏塊。

2)、如果是Intra16x16類型,調(diào)用x264_mb_encode_i16x16()編碼宏塊。

3)、如果是Intra4x4類型,循環(huán)16次調(diào)用x264_mb_encode_i4x4()編碼宏塊。

4)、如果是Inter類型,則不再調(diào)用子函數(shù),而是直接進(jìn)行編碼:

? ? ? ? a)、對(duì)16x16塊調(diào)用x264_dct_function_tsub16x16_dct()匯編函數(shù),求得編碼宏塊數(shù)據(jù)p_fenc與重建宏塊數(shù)據(jù)p_fdec之間的殘差(“sub”),并對(duì)殘差進(jìn)行DCT變換。

? ? ? ? b)、分成4個(gè)8x8的塊,對(duì)每個(gè)8x8塊分別調(diào)用x264_quant_function_tquant_4x4x4()匯編函數(shù)進(jìn)行量化。

? ? ? ? c)、分成16個(gè)4x4的塊,對(duì)每個(gè)4x4塊分別調(diào)用x264_quant_function_tdequant_4x4()匯編函數(shù)進(jìn)行反量化(用于重建幀)。

? ? ? ? d)、分成4個(gè)8x8的塊,對(duì)每個(gè)8x8塊分別調(diào)用x264_dct_function_tadd8x8_idct()匯編函數(shù),對(duì)殘差進(jìn)行DCT反變換,并將反變換后的數(shù)據(jù)疊加(“add”)至預(yù)測數(shù)據(jù)上(用于重建幀)。

5)、如果對(duì)色度編碼,調(diào)用x264_mb_encode_chroma()

?

? ? ? ? 從Inter宏塊編碼的步驟可以看出,編碼就是“DCT變換+量化”兩步的組合。在接下來的文章中將依次分析變換、量化的具體代碼。

總結(jié)

以上是生活随笔為你收集整理的x264代码剖析(十四):核心算法之宏块编码函数x264_macroblock_encode()的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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