x264代碼剖析(八):encode()函數之x264_encoder_close()函數


x264代碼剖析(八):encode()函數之x264_encoder_close()函數

 

        encode()函數是x264的主干函數,主要包括x264_encoder_open()函數、x264_encoder_headers()函數、x264_encoder_encode()函數與x264_encoder_close()函數四大部分,其中x264_encoder_encode()函數是其核心部分,具體的H.264視頻編碼算法均在此模塊。上三篇博文主要分析了x264_encoder_open()函數、x264_encoder_headers()函數與x264_encoder_encode()函數(后續會繼續深入),本文主要學習x264_encoder_close()函數。

 

        x264_encoder_close()libx264的一個API函數。該函數用於關閉編碼器,同時輸出一些統計信息。如下圖所示,調用了以下函數:

x264_lookahead_delete():釋放Lookahead相關的變量。

x264_ratecontrol_summary():匯總碼率控制信息。

x264_ratecontrol_delete():關閉碼率控制。




        對應的代碼如下:


/******************************************************************/
/******************************************************************/
/*
======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 < h->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 < 3; i++ )
{
static const uint8_t slice_order[] = { SLICE_TYPE_I, SLICE_TYPE_P, SLICE_TYPE_B };
int i_slice = slice_order[i];

if( h->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 <= h->param.i_bframe; i++ )
den += (i+1) * h->stat.i_consecutive_bframes[i];
for( int i = 0; i <= h->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 < 2; i_type++ )
for( int i = 0; i < X264_PARTTYPE_MAX; i++ )
{
if( i == D_DIRECT_8x8 ) continue; /* direct is counted as its own type */
i_mb_count_size[i_type][x264_mb_partition_pixel_table[i]] += h->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 < X264_PARTTYPE_MAX; i++ )
for( int j = 0; j < 2; j++ )
{
int l0 = x264_mb_type_list_table[i][0][j];
int l1 = x264_mb_type_list_table[i][1][j];
if( l0 || l1 )
list_count[l1+l0*l1] += h->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 <= I_PRED_16x16_DC_128; i++ )
{
fixed_pred_modes[0][x264_mb_pred_mode16x16_fix[i]] += h->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 <= 2; i++ )
{
for( int j = 0; j <= I_PRED_8x8_DC_128; j++ )
{
fixed_pred_modes[i][x264_mb_pred_mode4x4_fix(j)] += h->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 <= I_PRED_CHROMA_DC_128; i++ )
{
fixed_pred_modes[3][x264_mb_chroma_pred_mode_fix[i]] += h->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 < 2; i_list++ )
for( int i_slice = 0; i_slice < 2; i_slice++ )
{
char *p = buf;
int64_t i_den = 0;
int i_max = 0;
for( int i = 0; i < X264_REF_MAX*2; i++ )
if( h->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 <= i_max; i++ )
p += sprintf( p, " %4.1f%%", 100. * h->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 < h->i_thread_frames; i++ )
if( h->thread[i]->b_thread_active )
for( int j = 0; j < h->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 < h->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
}

        最后給出結果示意圖,如下圖:




        至此,x264的主干函數(x264_encoder_open()函數、x264_encoder_headers()函數、x264_encoder_encode()函數與x264_encoder_close()函數)就簡單粗暴地呈現出來了,接下來將深入H.264算法繼續進行分析。



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com