x264代码剖析(八):encode()函数之x264_encoder_close()函数

2021-07-14 23:06

阅读:554

/******************************************************************/
/******************************************************************/
/*
======Analysed by RuiDong Fang
======Csdn Blog:http://blog.csdn.net/frd2009041510
======Date:2016.03.10
 */
/******************************************************************/
/******************************************************************/

/************====== x264_encoder_close()函数 ======************/
/*
功能:关闭编码器,同一时候输出一些统计信息。
*/
/****************************************************************************
 * x264_encoder_close:
 ****************************************************************************/
void    x264_encoder_close  ( x264_t *h )
{
    int64_t i_yuv_size = FRAME_SIZE( h->param.i_width * h->param.i_height );
    int64_t i_mb_count_size[2][7] = {{0}};
    char buf[200];
    int b_print_pcm = h->stat.i_mb_count[SLICE_TYPE_I][I_PCM]
                   || h->stat.i_mb_count[SLICE_TYPE_P][I_PCM]
                   || h->stat.i_mb_count[SLICE_TYPE_B][I_PCM];

    x264_lookahead_delete( h );	////////////////////////释放lookahead相关的变量

#if HAVE_OPENCL
    x264_opencl_lookahead_delete( h );
    x264_opencl_function_t *ocl = h->opencl.ocl;
#endif

    if( h->param.b_sliced_threads )
        x264_threadpool_wait_all( h );
    if( h->param.i_threads > 1 )
        x264_threadpool_delete( h->threadpool );
    if( h->param.i_lookahead_threads > 1 )
        x264_threadpool_delete( h->lookaheadpool );
    if( h->i_thread_frames > 1 )
    {
        for( int i = 0; i i_thread_frames; i++ )
            if( h->thread[i]->b_thread_active )
            {
                assert( h->thread[i]->fenc->i_reference_count == 1 );
                x264_frame_delete( h->thread[i]->fenc );
            }

        x264_t *thread_prev = h->thread[h->i_thread_phase];
        x264_thread_sync_ratecontrol( h, thread_prev, h );
        x264_thread_sync_ratecontrol( thread_prev, thread_prev, h );
        h->i_frame = thread_prev->i_frame + 1 - h->i_thread_frames;
    }
    h->i_frame++;

    /* Slices used and PSNR */
	/* 演示样例 
     * x264 [info]: frame I:2     Avg QP:20.51  size: 20184  PSNR Mean Y:45.32 U:47.54 V:47.62 Avg:45.94 Global:45.52 
     * x264 [info]: frame P:33    Avg QP:23.08  size:  3230  PSNR Mean Y:43.23 U:47.06 V:46.87 Avg:44.15 Global:44.00 
     * x264 [info]: frame B:65    Avg QP:27.87  size:   352  PSNR Mean Y:42.76 U:47.21 V:47.05 Avg:43.79 Global:43.65 
     */ 
    for( int i = 0; i stat.i_frame_count[i_slice] > 0 )
        {
            int i_count = h->stat.i_frame_count[i_slice];
            double dur =  h->stat.f_frame_duration[i_slice];
            if( h->param.analyse.b_psnr )
            {
                //输出统计信息-包括PSNR  
                //注意PSNR都是通过SSD换算过来的,换算方法就是调用x264_psnr()方法
				x264_log( h, X264_LOG_INFO,
                          "frame %c:%-5d Avg QP:%5.2f  size:%6.0f  PSNR Mean Y:%5.2f U:%5.2f V:%5.2f Avg:%5.2f Global:%5.2f\n",
                          slice_type_to_char[i_slice],
                          i_count,
                          h->stat.f_frame_qp[i_slice] / i_count,
                          (double)h->stat.i_frame_size[i_slice] / i_count,
                          h->stat.f_psnr_mean_y[i_slice] / dur, h->stat.f_psnr_mean_u[i_slice] / dur, h->stat.f_psnr_mean_v[i_slice] / dur,
                          h->stat.f_psnr_average[i_slice] / dur,
                          x264_psnr( h->stat.f_ssd_global[i_slice], dur * i_yuv_size ) );
            }
            else
            {
                //输出统计信息-不包括PSNR
				x264_log( h, X264_LOG_INFO,
                          "frame %c:%-5d Avg QP:%5.2f  size:%6.0f\n",
                          slice_type_to_char[i_slice],
                          i_count,
                          h->stat.f_frame_qp[i_slice] / i_count,
                          (double)h->stat.i_frame_size[i_slice] / i_count );
            }
        }
    }

	/* 演示样例 
     * x264 [info]: consecutive B-frames:  3.0% 10.0% 63.0% 24.0% 
     * 
     */
    if( h->param.i_bframe && h->stat.i_frame_count[SLICE_TYPE_B] )
    {
        //B帧相关信息
		char *p = buf;
        int den = 0;
        // weight by number of frames (including the I/P-frames) that are in a sequence of N B-frames
        for( int i = 0; i param.i_bframe; i++ )
            den += (i+1) * h->stat.i_consecutive_bframes[i];
        for( int i = 0; i param.i_bframe; i++ )
            p += sprintf( p, " %4.1f%%", 100. * (i+1) * h->stat.i_consecutive_bframes[i] / den );
        x264_log( h, X264_LOG_INFO, "consecutive B-frames:%s\n", buf );
    }

    for( int i_type = 0; i_type stat.i_mb_partition[i_type][i];
        }

    /* MB types used */
    /* 演示样例 
     * x264 [info]: mb I  I16..4: 15.3% 37.5% 47.3% 
     * x264 [info]: mb P  I16..4:  0.6%  0.4%  0.2%  P16..4: 34.6% 21.2% 12.7%  0.0%  0.0%    skip:30.4% 
     * x264 [info]: mb B  I16..4:  0.0%  0.0%  0.0%  B16..8: 21.2%  4.1%  0.7%  direct: 0.8%  skip:73.1%  L0:28.7% L1:53.0% BI:18.3% 
     */
	if( h->stat.i_frame_count[SLICE_TYPE_I] > 0 )
    {
        int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_I];
        double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_I] * h->mb.i_mb_count / 100.0;
        
		//Intra宏块信息-存于buf  
        //从左到右3个信息,依次为I16x16,I8x8,I4x4
		x264_print_intra( i_mb_count, i_count, b_print_pcm, buf );
        x264_log( h, X264_LOG_INFO, "mb I  %s\n", buf );
    }
    if( h->stat.i_frame_count[SLICE_TYPE_P] > 0 )
    {
        int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_P];
        double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_P] * h->mb.i_mb_count / 100.0;
        int64_t *i_mb_size = i_mb_count_size[SLICE_TYPE_P];

        x264_print_intra( i_mb_count, i_count, b_print_pcm, buf );//Intra宏块信息-存于buf
		
		//Intra宏块信息-放在最前面  
        //后面加入P宏块信息  
        //从左到右6个信息,依次为P16x16, P16x8+P8x16, P8x8, P8x4+P4x8, P4x4, PSKIP
        x264_log( h, X264_LOG_INFO,
                  "mb P  %s  P16..4: %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%%    skip:%4.1f%%\n",
                  buf,
                  i_mb_size[PIXEL_16x16] / (i_count*4),
                  (i_mb_size[PIXEL_16x8] + i_mb_size[PIXEL_8x16]) / (i_count*4),
                  i_mb_size[PIXEL_8x8] / (i_count*4),
                  (i_mb_size[PIXEL_8x4] + i_mb_size[PIXEL_4x8]) / (i_count*4),
                  i_mb_size[PIXEL_4x4] / (i_count*4),
                  i_mb_count[P_SKIP] / i_count );
    }
    if( h->stat.i_frame_count[SLICE_TYPE_B] > 0 )
    {
        int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_B];
        double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_B] * h->mb.i_mb_count / 100.0;
        double i_mb_list_count;
        int64_t *i_mb_size = i_mb_count_size[SLICE_TYPE_B];
        int64_t list_count[3] = {0}; /* 0 == L0, 1 == L1, 2 == BI */
        x264_print_intra( i_mb_count, i_count, b_print_pcm, buf );//Intra宏块信息
        for( int i = 0; i stat.i_mb_count[SLICE_TYPE_B][i] * 2;
            }
        list_count[0] += h->stat.i_mb_partition[SLICE_TYPE_B][D_L0_8x8];
        list_count[1] += h->stat.i_mb_partition[SLICE_TYPE_B][D_L1_8x8];
        list_count[2] += h->stat.i_mb_partition[SLICE_TYPE_B][D_BI_8x8];
        i_mb_count[B_DIRECT] += (h->stat.i_mb_partition[SLICE_TYPE_B][D_DIRECT_8x8]+2)/4;
        i_mb_list_count = (list_count[0] + list_count[1] + list_count[2]) / 100.0;
        
		//Intra宏块信息-放在最前面  
        //后面加入B宏块信息  
        //从左到右5个信息。依次为B16x16, B16x8+B8x16, B8x8, BDIRECT, BSKIP  
        //  
        //SKIP和DIRECT差别  
        //P_SKIP的CBP为0,无像素残差,无运动矢量残  
        //B_SKIP宏块的模式为B_DIRECT且CBP为0,无像素残差,无运动矢量残  
        //B_DIRECT的CBP不为0,有像素残差,无运动矢量残
		sprintf( buf + strlen(buf), "  B16..8: %4.1f%% %4.1f%% %4.1f%%  direct:%4.1f%%  skip:%4.1f%%",
                 i_mb_size[PIXEL_16x16] / (i_count*4),
                 (i_mb_size[PIXEL_16x8] + i_mb_size[PIXEL_8x16]) / (i_count*4),
                 i_mb_size[PIXEL_8x8] / (i_count*4),
                 i_mb_count[B_DIRECT] / i_count,
                 i_mb_count[B_SKIP]   / i_count );
        if( i_mb_list_count != 0 )
            sprintf( buf + strlen(buf), "  L0:%4.1f%% L1:%4.1f%% BI:%4.1f%%",
                     list_count[0] / i_mb_list_count,
                     list_count[1] / i_mb_list_count,
                     list_count[2] / i_mb_list_count );
        x264_log( h, X264_LOG_INFO, "mb B  %s\n", buf );
    }

    x264_ratecontrol_summary( h );	////////////////////////汇总码率控制信息

    if( h->stat.i_frame_count[SLICE_TYPE_I] + h->stat.i_frame_count[SLICE_TYPE_P] + h->stat.i_frame_count[SLICE_TYPE_B] > 0 )
    {
#define SUM3(p) (p[SLICE_TYPE_I] + p[SLICE_TYPE_P] + p[SLICE_TYPE_B])
#define SUM3b(p,o) (p[SLICE_TYPE_I][o] + p[SLICE_TYPE_P][o] + p[SLICE_TYPE_B][o])
        int64_t i_i8x8 = SUM3b( h->stat.i_mb_count, I_8x8 );
        int64_t i_intra = i_i8x8 + SUM3b( h->stat.i_mb_count, I_4x4 )
                                 + SUM3b( h->stat.i_mb_count, I_16x16 );
        int64_t i_all_intra = i_intra + SUM3b( h->stat.i_mb_count, I_PCM);
        int64_t i_skip = SUM3b( h->stat.i_mb_count, P_SKIP )
                       + SUM3b( h->stat.i_mb_count, B_SKIP );
        const int i_count = h->stat.i_frame_count[SLICE_TYPE_I] +
                            h->stat.i_frame_count[SLICE_TYPE_P] +
                            h->stat.i_frame_count[SLICE_TYPE_B];
        int64_t i_mb_count = (int64_t)i_count * h->mb.i_mb_count;
        int64_t i_inter = i_mb_count - i_skip - i_intra;
        const double duration = h->stat.f_frame_duration[SLICE_TYPE_I] +
                                h->stat.f_frame_duration[SLICE_TYPE_P] +
                                h->stat.f_frame_duration[SLICE_TYPE_B];
        float f_bitrate = SUM3(h->stat.i_frame_size) / duration / 125;

        if( PARAM_INTERLACED )//隔行
        {
            char *fieldstats = buf;
            fieldstats[0] = 0;
            if( i_inter )
                fieldstats += sprintf( fieldstats, " inter:%.1f%%", h->stat.i_mb_field[1] * 100.0 / i_inter );
            if( i_skip )
                fieldstats += sprintf( fieldstats, " skip:%.1f%%", h->stat.i_mb_field[2] * 100.0 / i_skip );
            x264_log( h, X264_LOG_INFO, "field mbs: intra: %.1f%%%s\n",
                      h->stat.i_mb_field[0] * 100.0 / i_intra, buf );
        }

        if( h->pps->b_transform_8x8_mode )//8x8DCT信息
        {
            buf[0] = 0;
            if( h->stat.i_mb_count_8x8dct[0] )
                sprintf( buf, " inter:%.1f%%", 100. * h->stat.i_mb_count_8x8dct[1] / h->stat.i_mb_count_8x8dct[0] );
            x264_log( h, X264_LOG_INFO, "8x8 transform intra:%.1f%%%s\n", 100. * i_i8x8 / i_intra, buf );
        }

        if( (h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO ||
            (h->stat.i_direct_frames[0] && h->stat.i_direct_frames[1]))
            && h->stat.i_frame_count[SLICE_TYPE_B] )
        {
            x264_log( h, X264_LOG_INFO, "direct mvs  spatial:%.1f%% temporal:%.1f%%\n",
                      h->stat.i_direct_frames[1] * 100. / h->stat.i_frame_count[SLICE_TYPE_B],
                      h->stat.i_direct_frames[0] * 100. / h->stat.i_frame_count[SLICE_TYPE_B] );
        }

        buf[0] = 0;
        int csize = CHROMA444 ? 4 : 1;
        if( i_mb_count != i_all_intra )
            sprintf( buf, " inter: %.1f%% %.1f%% %.1f%%",
                     h->stat.i_mb_cbp[1] * 100.0 / ((i_mb_count - i_all_intra)*4),
                     h->stat.i_mb_cbp[3] * 100.0 / ((i_mb_count - i_all_intra)*csize),
                     h->stat.i_mb_cbp[5] * 100.0 / ((i_mb_count - i_all_intra)*csize) );
        
		/* 
         * 演示样例 
         * x264 [info]: coded y,uvDC,uvAC intra: 74.1% 83.3% 58.9% inter: 10.4% 6.6% 0.4% 
         */
		x264_log( h, X264_LOG_INFO, "coded y,%s,%s intra: %.1f%% %.1f%% %.1f%%%s\n",
                  CHROMA444?

"u":"uvDC", CHROMA444?"v":"uvAC", h->stat.i_mb_cbp[0] * 100.0 / (i_all_intra*4), h->stat.i_mb_cbp[2] * 100.0 / (i_all_intra*csize), h->stat.i_mb_cbp[4] * 100.0 / (i_all_intra*csize), buf ); /* * 帧内预測信息 * 从上到下分别为I16x16,I8x8,I4x4 * 从左到右顺序为Vertical, Horizontal, DC, Plane .... * * 演示样例 * * x264 [info]: i16 v,h,dc,p: 21% 25% 7% 48% * x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 25% 23% 13% 6% 5% 5% 6% 8% 10% * x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 22% 20% 9% 7% 7% 8% 8% 7% 12% * x264 [info]: i8c dc,h,v,p: 43% 20% 27% 10% * */ int64_t fixed_pred_modes[4][9] = {{0}}; int64_t sum_pred_modes[4] = {0}; for( int i = 0; i stat.i_mb_pred_mode[0][i]; sum_pred_modes[0] += h->stat.i_mb_pred_mode[0][i]; } if( sum_pred_modes[0] ) x264_log( h, X264_LOG_INFO, "i16 v,h,dc,p: %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", fixed_pred_modes[0][0] * 100.0 / sum_pred_modes[0], fixed_pred_modes[0][1] * 100.0 / sum_pred_modes[0], fixed_pred_modes[0][2] * 100.0 / sum_pred_modes[0], fixed_pred_modes[0][3] * 100.0 / sum_pred_modes[0] ); for( int i = 1; i stat.i_mb_pred_mode[i][j]; sum_pred_modes[i] += h->stat.i_mb_pred_mode[i][j]; } if( sum_pred_modes[i] ) x264_log( h, X264_LOG_INFO, "i%d v,h,dc,ddl,ddr,vr,hd,vl,hu: %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", (3-i)*4, fixed_pred_modes[i][0] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][1] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][2] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][3] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][4] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][5] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][6] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][7] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][8] * 100.0 / sum_pred_modes[i] ); } for( int i = 0; i stat.i_mb_pred_mode[3][i]; sum_pred_modes[3] += h->stat.i_mb_pred_mode[3][i]; } if( sum_pred_modes[3] && !CHROMA444 ) x264_log( h, X264_LOG_INFO, "i8c dc,h,v,p: %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", fixed_pred_modes[3][0] * 100.0 / sum_pred_modes[3], fixed_pred_modes[3][1] * 100.0 / sum_pred_modes[3], fixed_pred_modes[3][2] * 100.0 / sum_pred_modes[3], fixed_pred_modes[3][3] * 100.0 / sum_pred_modes[3] ); if( h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE && h->stat.i_frame_count[SLICE_TYPE_P] > 0 ) x264_log( h, X264_LOG_INFO, "Weighted P-Frames: Y:%.1f%% UV:%.1f%%\n", h->stat.i_wpred[0] * 100.0 / h->stat.i_frame_count[SLICE_TYPE_P], h->stat.i_wpred[1] * 100.0 / h->stat.i_frame_count[SLICE_TYPE_P] ); /* * 參考帧信息 * 从左到右依次为不同序号的參考帧 * * 演示样例 * * x264 [info]: ref P L0: 62.5% 19.7% 13.8% 4.0% * x264 [info]: ref B L0: 88.8% 9.4% 1.9% * x264 [info]: ref B L1: 92.6% 7.4% * */ for( int i_list = 0; i_list stat.i_mb_count_ref[i_slice][i_list][i] ) { i_den += h->stat.i_mb_count_ref[i_slice][i_list][i]; i_max = i; } if( i_max == 0 ) continue; for( int i = 0; i stat.i_mb_count_ref[i_slice][i_list][i] / i_den ); x264_log( h, X264_LOG_INFO, "ref %c L%d:%s\n", "PB"[i_slice], i_list, buf ); } if( h->param.analyse.b_ssim ) { float ssim = SUM3( h->stat.f_ssim_mean_y ) / duration; x264_log( h, X264_LOG_INFO, "SSIM Mean Y:%.7f (%6.3fdb)\n", ssim, x264_ssim( ssim ) ); } /* * 演示样例 * * x264 [info]: PSNR Mean Y:42.967 U:47.163 V:47.000 Avg:43.950 Global:43.796 kb/s:339.67 * */ if( h->param.analyse.b_psnr ) { x264_log( h, X264_LOG_INFO, "PSNR Mean Y:%6.3f U:%6.3f V:%6.3f Avg:%6.3f Global:%6.3f kb/s:%.2f\n", SUM3( h->stat.f_psnr_mean_y ) / duration, SUM3( h->stat.f_psnr_mean_u ) / duration, SUM3( h->stat.f_psnr_mean_v ) / duration, SUM3( h->stat.f_psnr_average ) / duration, x264_psnr( SUM3( h->stat.f_ssd_global ), duration * i_yuv_size ), f_bitrate ); } else x264_log( h, X264_LOG_INFO, "kb/s:%.2f\n", f_bitrate ); } /* rc */ x264_ratecontrol_delete( h ); ////////////////////////关闭码率控制 /* param */ if( h->param.rc.psz_stat_out ) free( h->param.rc.psz_stat_out ); if( h->param.rc.psz_stat_in ) free( h->param.rc.psz_stat_in ); //free...... x264_cqm_delete( h ); x264_free( h->nal_buffer ); x264_free( h->reconfig_h ); x264_analyse_free_costs( h ); if( h->i_thread_frames > 1 ) h = h->thread[h->i_thread_phase]; /* frames */ x264_frame_delete_list( h->frames.unused[0] ); x264_frame_delete_list( h->frames.unused[1] ); x264_frame_delete_list( h->frames.current ); x264_frame_delete_list( h->frames.blank_unused ); h = h->thread[0]; for( int i = 0; i i_thread_frames; i++ ) if( h->thread[i]->b_thread_active ) for( int j = 0; j thread[i]->i_ref[0]; j++ ) if( h->thread[i]->fref[0][j] && h->thread[i]->fref[0][j]->b_duplicate ) x264_frame_delete( h->thread[i]->fref[0][j] ); if( h->param.i_lookahead_threads > 1 ) for( int i = 0; i param.i_lookahead_threads; i++ ) x264_free( h->lookahead_thread[i] ); for( int i = h->param.i_threads - 1; i >= 0; i-- ) { x264_frame_t **frame; if( !h->param.b_sliced_threads || i == 0 ) { for( frame = h->thread[i]->frames.reference; *frame; frame++ ) { assert( (*frame)->i_reference_count > 0 ); (*frame)->i_reference_count--; if( (*frame)->i_reference_count == 0 ) x264_frame_delete( *frame ); } frame = &h->thread[i]->fdec; if( *frame ) { assert( (*frame)->i_reference_count > 0 ); (*frame)->i_reference_count--; if( (*frame)->i_reference_count == 0 ) x264_frame_delete( *frame ); } x264_macroblock_cache_free( h->thread[i] ); } x264_macroblock_thread_free( h->thread[i], 0 ); x264_free( h->thread[i]->out.p_bitstream ); x264_free( h->thread[i]->out.nal ); x264_pthread_mutex_destroy( &h->thread[i]->mutex ); x264_pthread_cond_destroy( &h->thread[i]->cv ); x264_free( h->thread[i] ); } #if HAVE_OPENCL x264_opencl_close_library( ocl ); #endif }


评论


亲,登录后才可以留言!