x264代码剖析(九):x264_encoder_encode()函数之x264_slice's'_write()函数
x264代碼剖析(九):x264_encoder_encode()函數(shù)之x264_slice's'_write()函數(shù)
?
? ? ? ? x264_encoder_encode()函數(shù)的核心函數(shù)就是x264_slices_write()函數(shù)。在x264_slices_write()函數(shù)中,最主要的工作就是調(diào)用了x264_slice_write()函數(shù)(注意“x264_slices_write()”和“x264_slice_write()”名字差了一個(gè)“s”),x264_slice_write()函數(shù)才是真正完成編碼的核心函數(shù),如下圖所示。
1、x264_slices_write()函數(shù)
?
? ? ? ? 在x264_slices_write()函數(shù)中,最主要的工作就是調(diào)用了x264_slice_write()函數(shù),需要注意,x264_slices_write()調(diào)用了x264_slice_write()。其中x264_slices_write()的單位為幀,而x264_slice_write()的單位為Slice。最常見(jiàn)的情況下一個(gè)幀里面只有一個(gè)Slice,但是也有可能一個(gè)幀里面有多個(gè)Slice。對(duì)應(yīng)的代碼如下:
/******************************************************************/ /******************************************************************/ /* ======Analysed by RuiDong Fang ======Csdn Blog:http://blog.csdn.net/frd2009041510 ======Date:2016.03.10*/ /******************************************************************/ /******************************************************************//************====== x264_slices_write()函數(shù) ======************/ /* 功能:編碼數(shù)據(jù)(最關(guān)鍵的步驟),其中調(diào)用了x264_slice_write()完成了編碼的工作 (注意“x264_slices_write()”和“x264_slice_write()”名字差了一個(gè)“s”)。 */ static void *x264_slices_write( x264_t *h ) {int i_slice_num = 0;int last_thread_mb = h->sh.i_last_mb;/* init stats */memset( &h->stat.frame, 0, sizeof(h->stat.frame) );h->mb.b_reencode_mb = 0;//循環(huán)每一個(gè)slice(一幅圖像可以由多個(gè)Slice構(gòu)成)while( h->sh.i_first_mb + SLICE_MBAFF*h->mb.i_mb_stride <= last_thread_mb ){h->sh.i_last_mb = last_thread_mb;if( !i_slice_num || !x264_frame_new_slice( h, h->fdec ) ){if( h->param.i_slice_max_mbs ){if( SLICE_MBAFF ){// convert first to mbaff form, add slice-max-mbs, then convert back to normal formint last_mbaff = 2*(h->sh.i_first_mb % h->mb.i_mb_width)+ h->mb.i_mb_width*(h->sh.i_first_mb / h->mb.i_mb_width)+ h->param.i_slice_max_mbs - 1;int last_x = (last_mbaff % (2*h->mb.i_mb_width))/2;int last_y = (last_mbaff / (2*h->mb.i_mb_width))*2 + 1;h->sh.i_last_mb = last_x + h->mb.i_mb_stride*last_y;}else{h->sh.i_last_mb = h->sh.i_first_mb + h->param.i_slice_max_mbs - 1;if( h->sh.i_last_mb < last_thread_mb && last_thread_mb - h->sh.i_last_mb < h->param.i_slice_min_mbs )h->sh.i_last_mb = last_thread_mb - h->param.i_slice_min_mbs;}i_slice_num++;}else if( h->param.i_slice_count && !h->param.b_sliced_threads ){int height = h->mb.i_mb_height >> PARAM_INTERLACED;int width = h->mb.i_mb_width << PARAM_INTERLACED;i_slice_num++;h->sh.i_last_mb = (height * i_slice_num + h->param.i_slice_count/2) / h->param.i_slice_count * width - 1;}}h->sh.i_last_mb = X264_MIN( h->sh.i_last_mb, last_thread_mb );//真正的編碼——編碼1個(gè)Slice //x264_stack_align()應(yīng)該是平臺(tái)優(yōu)化過(guò)程中內(nèi)存對(duì)齊的工作 //實(shí)際上就是調(diào)用x264_slice_write()if( x264_stack_align( x264_slice_write, h ) ) //調(diào)用x264_slice_write(),進(jìn)入核心編碼函數(shù)塊goto fail;h->sh.i_first_mb = h->sh.i_last_mb + 1;//注意這里對(duì)i_first_mb進(jìn)行了賦值// if i_first_mb is not the last mb in a row then go to the next mb in MBAFF orderif( SLICE_MBAFF && h->sh.i_first_mb % h->mb.i_mb_width )h->sh.i_first_mb -= h->mb.i_mb_stride;}return (void *)0;fail:/* Tell other threads we're done, so they wouldn't wait for it */if( h->param.b_sliced_threads )x264_threadslice_cond_broadcast( h, 2 );return (void *)-1; }
2、x264_slice_write()函數(shù)
?
? ? ? ? x264_slice_write()是完成編碼工作的函數(shù)。該函數(shù)中包含了去塊效應(yīng)濾波,運(yùn)動(dòng)估計(jì),宏塊編碼,熵編碼等模塊。x264_slice_write()調(diào)用了如下函數(shù):
x264_nal_start():開(kāi)始寫(xiě)一個(gè)NALU。
x264_macroblock_thread_init():初始化宏塊重建數(shù)據(jù)緩存fdec_buf[]和編碼數(shù)據(jù)緩存fenc_buf[]。
x264_slice_header_write():輸出?Slice?Header。
x264_fdec_filter_row():濾波模塊。該模塊包含了環(huán)路濾波,半像素插值,SSIM/PSNR的計(jì)算。
x264_macroblock_cache_load():將要編碼的宏塊的周?chē)暮陦K的信息讀進(jìn)來(lái)。
x264_macroblock_analyse():分析模塊。該模塊包含了幀內(nèi)預(yù)測(cè)模式分析以及幀間運(yùn)動(dòng)估計(jì)等。
x264_macroblock_encode():宏塊編碼模塊。該模塊通過(guò)對(duì)殘差的DCT變換、量化等方式對(duì)宏塊進(jìn)行編碼。
x264_macroblock_write_cabac():CABAC熵編碼模塊。
x264_macroblock_write_cavlc():CAVLC熵編碼模塊。
x264_macroblock_cache_save():保存當(dāng)前宏塊的信息。
x264_ratecontrol_mb():碼率控制。
x264_nal_end():結(jié)束寫(xiě)一個(gè)NALU。
?
? ? ? ? x264_slice_write()用于編碼一個(gè)Slice。該函數(shù)的定義位于encoder\encoder.c,對(duì)應(yīng)的代碼分析如下:
/******************************************************************/ /******************************************************************/ /* ======Analysed by RuiDong Fang ======Csdn Blog:http://blog.csdn.net/frd2009041510 ======Date:2016.03.10*/ /******************************************************************/ /******************************************************************//************====== x264_slice_write()函數(shù) ======************/ /* 功能:編碼一個(gè)Slice */ static intptr_t x264_slice_write( x264_t *h ) {int i_skip;int mb_xy, i_mb_x, i_mb_y;//宏塊的序號(hào),以及序號(hào)對(duì)應(yīng)的x,y坐標(biāo)/* NALUs other than the first use a 3-byte startcode.* Add one extra byte for the rbsp, and one more for the final CABAC putbyte.* Then add an extra 5 bytes just in case, to account for random NAL escapes and* other inaccuracies. */int overhead_guess = (NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal)) + 1 + h->param.b_cabac + 5;int slice_max_size = h->param.i_slice_max_size > 0 ? (h->param.i_slice_max_size-overhead_guess)*8 : 0;int back_up_bitstream_cavlc = !h->param.b_cabac && h->sps->i_profile_idc < PROFILE_HIGH;int back_up_bitstream = slice_max_size || back_up_bitstream_cavlc;int starting_bits = bs_pos(&h->out.bs);int b_deblock = h->sh.i_disable_deblocking_filter_idc != 1;int b_hpel = h->fdec->b_kept_as_ref;int orig_last_mb = h->sh.i_last_mb;int thread_last_mb = h->i_threadslice_end * h->mb.i_mb_width - 1;uint8_t *last_emu_check; #define BS_BAK_SLICE_MAX_SIZE 0 #define BS_BAK_CAVLC_OVERFLOW 1 #define BS_BAK_SLICE_MIN_MBS 2 #define BS_BAK_ROW_VBV 3x264_bs_bak_t bs_bak[4];b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv;bs_realign( &h->out.bs );/* Slice */x264_nal_start( h, h->i_nal_type, h->i_nal_ref_idc ); //開(kāi)始輸出一個(gè)NAL,后面對(duì)應(yīng)著x264_nal_end()h->out.nal[h->out.i_nal].i_first_mb = h->sh.i_first_mb;/* Slice header *///存儲(chǔ)宏塊像素的緩存fdec_buf和fenc_buf的初始化 //宏塊編碼緩存p_fenc[0],p_fenc[1],p_fenc[2] //宏塊重建緩存p_fdec[0],p_fdec[1],p_fdec[2] //[0]存Y,[1]存U,[2]存Vx264_macroblock_thread_init( h ); //初始化宏塊重建數(shù)據(jù)緩存fdec_buf[]和編碼數(shù)據(jù)緩存fenc_buf[]/* Set the QP equal to the first QP in the slice for more accurate CABAC initialization. */h->mb.i_mb_xy = h->sh.i_first_mb;h->sh.i_qp = x264_ratecontrol_mb_qp( h );h->sh.i_qp = SPEC_QP( h->sh.i_qp );h->sh.i_qp_delta = h->sh.i_qp - h->pps->i_pic_init_qp;x264_slice_header_write( &h->out.bs, &h->sh, h->i_nal_ref_idc ); //輸出 Slice Headerif( h->param.b_cabac )//如果使用CABAC,需要初始化 {/* alignment needed */bs_align_1( &h->out.bs );/* init cabac */x264_cabac_context_init( h, &h->cabac, h->sh.i_type, x264_clip3( h->sh.i_qp-QP_BD_OFFSET, 0, 51 ), h->sh.i_cabac_init_idc );x264_cabac_encode_init ( &h->cabac, h->out.bs.p, h->out.bs.p_end );last_emu_check = h->cabac.p;}elselast_emu_check = h->out.bs.p;h->mb.i_last_qp = h->sh.i_qp;h->mb.i_last_dqp = 0;h->mb.field_decoding_flag = 0;i_mb_y = h->sh.i_first_mb / h->mb.i_mb_width;//宏塊位置-縱坐標(biāo)(初始值)i_mb_x = h->sh.i_first_mb % h->mb.i_mb_width;//宏塊位置-橫坐標(biāo)(初始值)i_skip = 0;//一個(gè)大循環(huán) //對(duì)一個(gè)slice中每個(gè)宏塊進(jìn)行編碼while( 1 ){mb_xy = i_mb_x + i_mb_y * h->mb.i_mb_width;//宏塊序號(hào)。由i_mb_x和i_mb_y計(jì)算而來(lái)。int mb_spos = bs_pos(&h->out.bs) + x264_cabac_pos(&h->cabac);if( i_mb_x == 0 )//一行的開(kāi)始{if( x264_bitstream_check_buffer( h ) )return -1;if( !(i_mb_y & SLICE_MBAFF) && h->param.rc.i_vbv_buffer_size )x264_bitstream_backup( h, &bs_bak[BS_BAK_ROW_VBV], i_skip, 1 );if( !h->mb.b_reencode_mb )x264_fdec_filter_row( h, i_mb_y, 0 ); //濾波模塊。該模塊包含了環(huán)路濾波,半像素插值,SSIM/PSNR的計(jì)算(一次處理一行宏塊)}if( back_up_bitstream ){if( back_up_bitstream_cavlc )x264_bitstream_backup( h, &bs_bak[BS_BAK_CAVLC_OVERFLOW], i_skip, 0 );if( slice_max_size && !(i_mb_y & SLICE_MBAFF) ){x264_bitstream_backup( h, &bs_bak[BS_BAK_SLICE_MAX_SIZE], i_skip, 0 );if( (thread_last_mb+1-mb_xy) == h->param.i_slice_min_mbs )x264_bitstream_backup( h, &bs_bak[BS_BAK_SLICE_MIN_MBS], i_skip, 0 );}}if( PARAM_INTERLACED ){if( h->mb.b_adaptive_mbaff ){if( !(i_mb_y&1) ){/* FIXME: VSAD is fast but fairly poor at choosing the best interlace type. */h->mb.b_interlaced = x264_field_vsad( h, i_mb_x, i_mb_y );memcpy( &h->zigzagf, MB_INTERLACED ? &h->zigzagf_interlaced : &h->zigzagf_progressive, sizeof(h->zigzagf) );if( !MB_INTERLACED && (i_mb_y+2) == h->mb.i_mb_height )x264_expand_border_mbpair( h, i_mb_x, i_mb_y );}}h->mb.field[mb_xy] = MB_INTERLACED;}/* load cache *///將要編碼的宏塊的周?chē)暮陦K的值讀進(jìn)來(lái) //主要是上面、左邊塊的值if( SLICE_MBAFF )x264_macroblock_cache_load_interlaced( h, i_mb_x, i_mb_y ); //將要編碼的宏塊的周?chē)暮陦K的信息讀進(jìn)來(lái)elsex264_macroblock_cache_load_progressive( h, i_mb_x, i_mb_y ); //將要編碼的宏塊的周?chē)暮陦K的信息讀進(jìn)來(lái)x264_macroblock_analyse( h ); //分析模塊。該模塊包含了幀內(nèi)預(yù)測(cè)模式分析以及幀間運(yùn)動(dòng)估計(jì)等/* encode this macroblock -> be careful it can change the mb type to P_SKIP if needed */ reencode:x264_macroblock_encode( h ); //宏塊編碼模塊。該模塊通過(guò)對(duì)殘差的DCT變換、量化等方式對(duì)宏塊進(jìn)行編碼//輸出CABACif( h->param.b_cabac ){if( mb_xy > h->sh.i_first_mb && !(SLICE_MBAFF && (i_mb_y&1)) )x264_cabac_encode_terminal( &h->cabac );if( IS_SKIP( h->mb.i_type ) )x264_cabac_mb_skip( h, 1 );else{if( h->sh.i_type != SLICE_TYPE_I )x264_cabac_mb_skip( h, 0 );x264_macroblock_write_cabac( h, &h->cabac ); //CABAC熵編碼模塊}}else{//輸出CAVLCif( IS_SKIP( h->mb.i_type ) )i_skip++;else{if( h->sh.i_type != SLICE_TYPE_I ){bs_write_ue( &h->out.bs, i_skip ); /* skip run */i_skip = 0;}x264_macroblock_write_cavlc( h ); //CAVLC熵編碼模塊/* If there was a CAVLC level code overflow, try again at a higher QP. */if( h->mb.b_overflow ){h->mb.i_chroma_qp = h->chroma_qp_table[++h->mb.i_qp];h->mb.i_skip_intra = 0;h->mb.b_skip_mc = 0;h->mb.b_overflow = 0;x264_bitstream_restore( h, &bs_bak[BS_BAK_CAVLC_OVERFLOW], &i_skip, 0 );goto reencode;}}}int total_bits = bs_pos(&h->out.bs) + x264_cabac_pos(&h->cabac);int mb_size = total_bits - mb_spos;if( slice_max_size && (!SLICE_MBAFF || (i_mb_y&1)) ){/* Count the skip run, just in case. */if( !h->param.b_cabac )total_bits += bs_size_ue_big( i_skip );/* Check for escape bytes. */uint8_t *end = h->param.b_cabac ? h->cabac.p : h->out.bs.p;for( ; last_emu_check < end - 2; last_emu_check++ )if( last_emu_check[0] == 0 && last_emu_check[1] == 0 && last_emu_check[2] <= 3 ){slice_max_size -= 8;last_emu_check++;}/* We'll just re-encode this last macroblock if we go over the max slice size. */if( total_bits - starting_bits > slice_max_size && !h->mb.b_reencode_mb ){if( !x264_frame_new_slice( h, h->fdec ) ){/* Handle the most obnoxious slice-min-mbs edge case: we need to end the slice* because it's gone over the maximum size, but doing so would violate slice-min-mbs.* If possible, roll back to the last checkpoint and try again.* We could try raising QP, but that would break in the case where a slice spans multiple* rows, which the re-encoding infrastructure can't currently handle. */if( mb_xy <= thread_last_mb && (thread_last_mb+1-mb_xy) < h->param.i_slice_min_mbs ){if( thread_last_mb-h->param.i_slice_min_mbs < h->sh.i_first_mb+h->param.i_slice_min_mbs ){x264_log( h, X264_LOG_WARNING, "slice-max-size violated (frame %d, cause: slice-min-mbs)\n", h->i_frame );slice_max_size = 0;goto cont;}x264_bitstream_restore( h, &bs_bak[BS_BAK_SLICE_MIN_MBS], &i_skip, 0 );h->mb.b_reencode_mb = 1;h->sh.i_last_mb = thread_last_mb-h->param.i_slice_min_mbs;break;}if( mb_xy-SLICE_MBAFF*h->mb.i_mb_stride != h->sh.i_first_mb ){x264_bitstream_restore( h, &bs_bak[BS_BAK_SLICE_MAX_SIZE], &i_skip, 0 );h->mb.b_reencode_mb = 1;if( SLICE_MBAFF ){// set to bottom of previous mbpairif( i_mb_x )h->sh.i_last_mb = mb_xy-1+h->mb.i_mb_stride*(!(i_mb_y&1));elseh->sh.i_last_mb = (i_mb_y-2+!(i_mb_y&1))*h->mb.i_mb_stride + h->mb.i_mb_width - 1;}elseh->sh.i_last_mb = mb_xy-1;break;}elseh->sh.i_last_mb = mb_xy;}elseslice_max_size = 0;}} cont:h->mb.b_reencode_mb = 0;/* save cache *///保存當(dāng)前宏塊的的值,用于以后的宏塊的編碼 //包括Intra4x4宏塊幀內(nèi)預(yù)測(cè)模式,DCT非零系數(shù),運(yùn)動(dòng)矢量,參考幀序號(hào)等等x264_macroblock_cache_save( h ); //保存當(dāng)前宏塊的信息if( x264_ratecontrol_mb( h, mb_size ) < 0 ) //碼率控制{x264_bitstream_restore( h, &bs_bak[BS_BAK_ROW_VBV], &i_skip, 1 );h->mb.b_reencode_mb = 1;i_mb_x = 0;i_mb_y = i_mb_y - SLICE_MBAFF;h->mb.i_mb_prev_xy = i_mb_y * h->mb.i_mb_stride - 1;h->sh.i_last_mb = orig_last_mb;continue;}/* accumulate mb stats *///對(duì)stat結(jié)構(gòu)體中的統(tǒng)計(jì)信息進(jìn)行賦值h->stat.frame.i_mb_count[h->mb.i_type]++;int b_intra = IS_INTRA( h->mb.i_type );int b_skip = IS_SKIP( h->mb.i_type );if( h->param.i_log_level >= X264_LOG_INFO || h->param.rc.b_stat_write ){if( !b_intra && !b_skip && !IS_DIRECT( h->mb.i_type ) ){if( h->mb.i_partition != D_8x8 )h->stat.frame.i_mb_partition[h->mb.i_partition] += 4;elsefor( int i = 0; i < 4; i++ )h->stat.frame.i_mb_partition[h->mb.i_sub_partition[i]] ++;if( h->param.i_frame_reference > 1 )for( int i_list = 0; i_list <= (h->sh.i_type == SLICE_TYPE_B); i_list++ )for( int i = 0; i < 4; i++ ){int i_ref = h->mb.cache.ref[i_list][ x264_scan8[4*i] ];if( i_ref >= 0 )h->stat.frame.i_mb_count_ref[i_list][i_ref] ++;}}}if( h->param.i_log_level >= X264_LOG_INFO ){if( h->mb.i_cbp_luma | h->mb.i_cbp_chroma ){if( CHROMA444 ){for( int i = 0; i < 4; i++ )if( h->mb.i_cbp_luma & (1 << i) )for( int p = 0; p < 3; p++ ){int s8 = i*4+p*16;int nnz8x8 = M16( &h->mb.cache.non_zero_count[x264_scan8[s8]+0] )| M16( &h->mb.cache.non_zero_count[x264_scan8[s8]+8] );h->stat.frame.i_mb_cbp[!b_intra + p*2] += !!nnz8x8;}}else{int cbpsum = (h->mb.i_cbp_luma&1) + ((h->mb.i_cbp_luma>>1)&1)+ ((h->mb.i_cbp_luma>>2)&1) + (h->mb.i_cbp_luma>>3);h->stat.frame.i_mb_cbp[!b_intra + 0] += cbpsum;h->stat.frame.i_mb_cbp[!b_intra + 2] += !!h->mb.i_cbp_chroma;h->stat.frame.i_mb_cbp[!b_intra + 4] += h->mb.i_cbp_chroma >> 1;}}if( h->mb.i_cbp_luma && !b_intra ){h->stat.frame.i_mb_count_8x8dct[0] ++;h->stat.frame.i_mb_count_8x8dct[1] += h->mb.b_transform_8x8;}if( b_intra && h->mb.i_type != I_PCM ){if( h->mb.i_type == I_16x16 )h->stat.frame.i_mb_pred_mode[0][h->mb.i_intra16x16_pred_mode]++;else if( h->mb.i_type == I_8x8 )for( int i = 0; i < 16; i += 4 )h->stat.frame.i_mb_pred_mode[1][h->mb.cache.intra4x4_pred_mode[x264_scan8[i]]]++;else //if( h->mb.i_type == I_4x4 )for( int i = 0; i < 16; i++ )h->stat.frame.i_mb_pred_mode[2][h->mb.cache.intra4x4_pred_mode[x264_scan8[i]]]++;h->stat.frame.i_mb_pred_mode[3][x264_mb_chroma_pred_mode_fix[h->mb.i_chroma_pred_mode]]++;}h->stat.frame.i_mb_field[b_intra?0:b_skip?2:1] += MB_INTERLACED;}//對(duì)stat結(jié)構(gòu)體中的統(tǒng)計(jì)信息進(jìn)行賦值結(jié)束/* calculate deblock strength values (actual deblocking is done per-row along with hpel) *///計(jì)算去塊效應(yīng)濾波器強(qiáng)度Bs //這里沒(méi)有濾波if( b_deblock )x264_macroblock_deblock_strength( h );if( mb_xy == h->sh.i_last_mb )//如果處理完最后一個(gè)宏塊,就跳出大循環(huán)break;if( SLICE_MBAFF ){i_mb_x += i_mb_y & 1;i_mb_y ^= i_mb_x < h->mb.i_mb_width;}elsei_mb_x++; //宏塊序號(hào)x加1if( i_mb_x == h->mb.i_mb_width )//處理完一行宏塊{//該處理下一行了i_mb_y++;//宏塊序號(hào)y加1i_mb_x = 0;//宏塊序號(hào)x設(shè)置為0}}if( h->sh.i_last_mb < h->sh.i_first_mb )return 0;h->out.nal[h->out.i_nal].i_last_mb = h->sh.i_last_mb;if( h->param.b_cabac )//熵編碼的收尾工作{x264_cabac_encode_flush( h, &h->cabac );h->out.bs.p = h->cabac.p;}else{if( i_skip > 0 )bs_write_ue( &h->out.bs, i_skip ); /* last skip run *//* rbsp_slice_trailing_bits */bs_rbsp_trailing( &h->out.bs );bs_flush( &h->out.bs );}//結(jié)束輸出一個(gè)NAL //前面對(duì)應(yīng)著x264_nal_start()if( x264_nal_end( h ) ) //結(jié)束寫(xiě)一個(gè)NALUreturn -1;if( h->sh.i_last_mb == (h->i_threadslice_end * h->mb.i_mb_width - 1) ){h->stat.frame.i_misc_bits = bs_pos( &h->out.bs )+ (h->out.i_nal*NALU_OVERHEAD * 8)- h->stat.frame.i_tex_bits- h->stat.frame.i_mv_bits;x264_fdec_filter_row( h, h->i_threadslice_end, 0 );if( h->param.b_sliced_threads ){/* Tell the main thread we're done. */x264_threadslice_cond_broadcast( h, 1 );/* Do hpel now */for( int mb_y = h->i_threadslice_start; mb_y <= h->i_threadslice_end; mb_y++ )x264_fdec_filter_row( h, mb_y, 1 );x264_threadslice_cond_broadcast( h, 2 );/* Do the first row of hpel, now that the previous slice is done */if( h->i_thread_idx > 0 ){x264_threadslice_cond_wait( h->thread[h->i_thread_idx-1], 2 );x264_fdec_filter_row( h, h->i_threadslice_start + (1 << SLICE_MBAFF), 2 );}}/* Free mb info after the last thread's done using it */if( h->fdec->mb_info_free && (!h->param.b_sliced_threads || h->i_thread_idx == (h->param.i_threads-1)) ){h->fdec->mb_info_free( h->fdec->mb_info );h->fdec->mb_info = NULL;h->fdec->mb_info_free = NULL;}}return 0; }
? ? ? ? 根據(jù)源代碼簡(jiǎn)單梳理了x264_slice_write()的流程,如下所示:
(1)、調(diào)用x264_nal_start()開(kāi)始輸出一個(gè)NALU。
(2)、x264_macroblock_thread_init():初始化宏塊重建像素緩存fdec_buf[]和編碼像素緩存fenc_buf[]。
(3)、調(diào)用x264_slice_header_write()輸出?Slice?Header。
(4)、進(jìn)入一個(gè)循環(huán),該循環(huán)每執(zhí)行一遍編碼一個(gè)宏塊:
? ? ? ? ? ? ? ?a)、?每處理一行宏塊,調(diào)用一次x264_fdec_filter_row()執(zhí)行濾波模塊。
? ? ? ? ? ? ? ?b)、?調(diào)用x264_macroblock_cache_load_progressive()將要編碼的宏塊的周?chē)暮陦K的信息讀進(jìn)來(lái)。
? ? ? ? ? ? ? ?c)?、調(diào)用x264_macroblock_analyse()執(zhí)行分析模塊。
? ? ? ? ? ? ? ?d)?、調(diào)用x264_macroblock_encode()執(zhí)行宏塊編碼模塊。
? ? ? ? ? ? ? ?e)?、調(diào)用x264_macroblock_write_cabac()/x264_macroblock_write_cavlc()執(zhí)行熵編碼模塊。
? ? ? ? ? ? ? ?f)?、調(diào)用x264_macroblock_cache_save()保存當(dāng)前宏塊的信息。
? ? ? ? ? ? ? g)?、調(diào)用x264_ratecontrol_mb()執(zhí)行碼率控制。
? ? ? ? ? ? ? h)?、準(zhǔn)備處理下一個(gè)宏塊。
(5)、調(diào)用x264_nal_end()結(jié)束輸出一個(gè)NALU。
?
? ? ? ? 到這兒,其實(shí)還沒(méi)進(jìn)入真正的H.264視頻編碼算法,后續(xù)將正式進(jìn)入,依次分析幀內(nèi)預(yù)測(cè)、幀間預(yù)測(cè)、變換與量化、去方塊濾波、熵編碼、碼率控制等等。總結(jié)
以上是生活随笔為你收集整理的x264代码剖析(九):x264_encoder_encode()函数之x264_slice's'_write()函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 学习SPRING在春天 - Learn
- 下一篇: 辛德瑞拉