📄 encoder.c
字号:
i_frame_size = x264_slices_write( h );//写入切片数据,这是编码的关键了
/* restore CPU state (before using float again) */
/// x264_cpu_restore( h->param.cpu );
if( i_slice_type == SLICE_TYPE_P && !h->param.rc.b_stat_read
&& h->param.i_scenecut_threshold >= 0 )
{
const int *mbs = h->stat.frame.i_mb_count;
int i_mb_i = mbs[I_16x16] + mbs[I_8x8] + mbs[I_4x4];
int i_mb_p = mbs[P_L0] + mbs[P_8x8];
int i_mb_s = mbs[P_SKIP];
int i_mb = h->sps->i_mb_width * h->sps->i_mb_height;
int64_t i_inter_cost = h->stat.frame.i_inter_cost;
int64_t i_intra_cost = h->stat.frame.i_intra_cost;
float f_bias;
int i_gop_size = h->fenc->i_frame - h->frames.i_last_idr;
float f_thresh_max = h->param.i_scenecut_threshold / 100.0;
/* magic numbers pulled out of thin air */
float f_thresh_min = f_thresh_max * h->param.i_keyint_min
/ ( h->param.i_keyint_max * 4 );
if( h->param.i_keyint_min == h->param.i_keyint_max )
f_thresh_min= f_thresh_max;
/* macroblock_analyse() doesn't further analyse skipped mbs,
* so we have to guess their cost */
if( i_mb_s < i_mb )
i_intra_cost = i_intra_cost * i_mb / (i_mb - i_mb_s);
if( i_gop_size < h->param.i_keyint_min / 4 )
f_bias = f_thresh_min / 4;
else if( i_gop_size <= h->param.i_keyint_min )
f_bias = f_thresh_min * i_gop_size / h->param.i_keyint_min;
else
{
f_bias = f_thresh_min
+ ( f_thresh_max - f_thresh_min )
* ( i_gop_size - h->param.i_keyint_min )
/ ( h->param.i_keyint_max - h->param.i_keyint_min );
}
f_bias = X264_MIN( f_bias, 1.0 );
/* Bad P will be reencoded as I */
if( i_mb_s < i_mb &&
i_inter_cost >= (1.0 - f_bias) * i_intra_cost )
{
int b;
x264_log( h, X264_LOG_DEBUG, "scene cut at %d Icost:%.0f Pcost:%.0f ratio:%.3f bias=%.3f lastIDR:%d (I:%d P:%d S:%d)\n",
h->fenc->i_frame,
(double)i_intra_cost, (double)i_inter_cost,
(double)i_inter_cost / i_intra_cost,
f_bias, i_gop_size,
i_mb_i, i_mb_p, i_mb_s );
/* Restore frame num */
h->i_frame_num--;
for( b = 0; h->frames.current[b] && IS_X264_TYPE_B( h->frames.current[b]->i_type ); b++ );
if( b > 0 )
{
/* If using B-frames, force GOP to be closed.
* Even if this frame is going to be I and not IDR, forcing a
* P-frame before the scenecut will probably help compression.
*
* We don't yet know exactly which frame is the scene cut, so
* we can't assign an I-frame. Instead, change the previous
* B-frame to P, and rearrange coding order. */
if( h->param.b_bframe_adaptive || b > 1 )
h->fenc->i_type = X264_TYPE_AUTO;
x264_frame_sort_pts( h->frames.current );
x264_frame_push( h->frames.next, h->fenc );
h->fenc = h->frames.current[b-1];
h->frames.current[b-1] = NULL;
h->fenc->i_type = X264_TYPE_P;
x264_frame_sort_dts( h->frames.current );
}
/* Do IDR if needed */
else if( i_gop_size >= h->param.i_keyint_min )
{
x264_frame_t *tmp;
/* Reset */
h->i_frame_num = 0;
/* Reinit field of fenc */
h->fenc->i_type = X264_TYPE_IDR;
h->fenc->i_poc = 0;
/* Put enqueued frames back in the pool */
while( (tmp = x264_frame_get( h->frames.current ) ) != NULL )
x264_frame_put( h->frames.next, tmp );
x264_frame_sort_pts( h->frames.next );
}
else
{
h->fenc->i_type = X264_TYPE_I;
}
goto do_encode;
}
}
/* End bitstream, set output *///bit流结束,设置输出
*pi_nal = h->out.i_nal;
*pp_nal = h->out.nal;
fprintf(stderr,"x264_encoder_encode:pi_nal=%d\n",*pi_nal);//add
for(a=0;a<4;a++)//add
{//add
fprintf(stderr,"x264_encoder_encode:pp_nal=%d\n",h->out.nal[a].i_payload);//add
fprintf(stderr,"x264_encoder_encode:pp_nal=%d\n",h->out.nal[a].i_ref_idc);//add
fprintf(stderr,"x264_encoder_encode:pp_nal=%d\n",h->out.nal[a].i_type);//add
fprintf(stderr,"x264_encoder_encode:pp_nal=%d\n",*h->out.nal[a].p_payload);//add
}//add
/* Set output picture properties *///设置输出图片属性
if( i_slice_type == SLICE_TYPE_I )
pic_out->i_type = i_nal_type == NAL_SLICE_IDR ? X264_TYPE_IDR : X264_TYPE_I;
else if( i_slice_type == SLICE_TYPE_P )
pic_out->i_type = X264_TYPE_P;
else
pic_out->i_type = X264_TYPE_B;
pic_out->i_pts = h->fenc->i_pts;
pic_out->img.i_plane = h->fdec->i_plane;
for(i = 0; i < 4; i++){
pic_out->img.i_stride[i] = h->fdec->i_stride[i];
pic_out->img.plane[i] = h->fdec->plane[i];
}
/* ---------------------- Update encoder state ------------------------- *///更新编码器状态
/* update rc */
/// x264_cpu_restore( h->param.cpu );
x264_ratecontrol_end( h, i_frame_size * 8 );
/* handle references */
if( i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE )
x264_reference_update( h );
#ifdef DEBUG_DUMP_FRAME
else
x264_fdec_deblock( h );
#endif
x264_frame_put( h->frames.unused, h->fenc );
/* increase frame count */
h->i_frame++;
/* restore CPU state (before using float again) */
/// x264_cpu_restore( h->param.cpu );
x264_noise_reduction_update( h );
/// TIMER_STOP( i_mtime_encode_frame );
/* ---------------------- Compute/Print statistics --------------------- *///计算和打印统计数值
/* Slice stat */
h->stat.i_slice_count[i_slice_type]++;
h->stat.i_slice_size[i_slice_type] += i_frame_size + NALU_OVERHEAD;
h->stat.i_slice_qp[i_slice_type] += i_global_qp;
for( i = 0; i < 19; i++ )
h->stat.i_mb_count[h->sh.i_type][i] += h->stat.frame.i_mb_count[i];
for( i = 0; i < 2; i++ )
h->stat.i_mb_count_8x8dct[i] += h->stat.frame.i_mb_count_8x8dct[i];
if( h->sh.i_type != SLICE_TYPE_I )
{
for( i = 0; i < 7; i++ )
h->stat.i_mb_count_size[h->sh.i_type][i] += h->stat.frame.i_mb_count_size[i];
for( i = 0; i < 16; i++ )
h->stat.i_mb_count_ref[h->sh.i_type][i] += h->stat.frame.i_mb_count_ref[i];
}
if( i_slice_type == SLICE_TYPE_B )
{
h->stat.i_direct_frames[ h->sh.b_direct_spatial_mv_pred ] ++;
if( h->mb.b_direct_auto_write )
{
//FIXME somewhat arbitrary time constants
if( h->stat.i_direct_score[0] + h->stat.i_direct_score[1] > h->mb.i_mb_count )
{
for( i = 0; i < 2; i++ )
h->stat.i_direct_score[i] = h->stat.i_direct_score[i] * 9/10;
}
for( i = 0; i < 2; i++ )
h->stat.i_direct_score[i] += h->stat.frame.i_direct_score[i];
}
}
if( h->param.analyse.b_psnr )
{
int64_t i_sqe_y, i_sqe_u, i_sqe_v;
/* PSNR */
i_sqe_y = x264_pixel_ssd_wxh( &h->pixf, frame_psnr->plane[0], frame_psnr->i_stride[0], h->fenc->plane[0], h->fenc->i_stride[0], h->param.i_width, h->param.i_height );
i_sqe_u = x264_pixel_ssd_wxh( &h->pixf, frame_psnr->plane[1], frame_psnr->i_stride[1], h->fenc->plane[1], h->fenc->i_stride[1], h->param.i_width/2, h->param.i_height/2);
i_sqe_v = x264_pixel_ssd_wxh( &h->pixf, frame_psnr->plane[2], frame_psnr->i_stride[2], h->fenc->plane[2], h->fenc->i_stride[2], h->param.i_width/2, h->param.i_height/2);
/// x264_cpu_restore( h->param.cpu );
h->stat.i_sqe_global[i_slice_type] += i_sqe_y + i_sqe_u + i_sqe_v;
h->stat.f_psnr_average[i_slice_type] += x264_psnr( i_sqe_y + i_sqe_u + i_sqe_v, 3 * h->param.i_width * h->param.i_height / 2 );
h->stat.f_psnr_mean_y[i_slice_type] += x264_psnr( i_sqe_y, h->param.i_width * h->param.i_height );
h->stat.f_psnr_mean_u[i_slice_type] += x264_psnr( i_sqe_u, h->param.i_width * h->param.i_height / 4 );
h->stat.f_psnr_mean_v[i_slice_type] += x264_psnr( i_sqe_v, h->param.i_width * h->param.i_height / 4 );
snprintf( psz_message, 80, " PSNR Y:%2.2f U:%2.2f V:%2.2f",
x264_psnr( i_sqe_y, h->param.i_width * h->param.i_height ),
x264_psnr( i_sqe_u, h->param.i_width * h->param.i_height / 4),
x264_psnr( i_sqe_v, h->param.i_width * h->param.i_height / 4) );
psz_message[79] = '\0';
}
else
{
psz_message[0] = '\0';
}
x264_log( h, X264_LOG_DEBUG,
"frame=%4d QP=%i NAL=%d Slice:%c Poc:%-3d I:%-4d P:%-4d SKIP:%-4d size=%d bytes%s\n",
h->i_frame - 1,
i_global_qp,
i_nal_ref_idc,
i_slice_type == SLICE_TYPE_I ? 'I' : (i_slice_type == SLICE_TYPE_P ? 'P' : 'B' ),
frame_psnr->i_poc,
h->stat.frame.i_mb_count_i,
h->stat.frame.i_mb_count_p,
h->stat.frame.i_mb_count_skip,
i_frame_size,
psz_message );
#ifdef DEBUG_MB_TYPE
{
static const char mb_chars[] = { 'i', 'i', 'I', 'C', 'P', '8', 'S',
'D', '<', 'X', 'B', 'X', '>', 'B', 'B', 'B', 'B', '8', 'S' };
int mb_xy;
for( mb_xy = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
{
if( h->mb.type[mb_xy] < 19 && h->mb.type[mb_xy] >= 0 )
fprintf( stderr, "%c ", mb_chars[ h->mb.type[mb_xy] ] );
else
fprintf( stderr, "? " );
if( (mb_xy+1) % h->sps->i_mb_width == 0 )
fprintf( stderr, "\n" );
}
}
#endif
#ifdef DEBUG_DUMP_FRAME//判断是否存放重建的帧
/* Dump reconstructed frame */
x264_frame_dump( h, frame_psnr, "fdec.yuv" );
#endif
return 0;
}
/****************************************************************************
* x264_encoder_close:
****************************************************************************/
void x264_encoder_close ( x264_t *h )
{
#ifdef DEBUG_BENCHMARK
int64_t i_mtime_total = i_mtime_analyse + i_mtime_encode + i_mtime_write + i_mtime_filter + 1;
#endif
int64_t i_yuv_size = 3 * h->param.i_width * h->param.i_height / 2;
int i;
#ifdef DEBUG_BENCHMARK
x264_log( h, X264_LOG_INFO,
"analyse=%d(%lldms) encode=%d(%lldms) write=%d(%lldms) filter=%d(%lldms)\n",
(int)(100*i_mtime_analyse/i_mtime_total), i_mtime_analyse/1000,
(int)(100*i_mtime_encode/i_mtime_total), i_mtime_encode/1000,
(int)(100*i_mtime_write/i_mtime_total), i_mtime_write/1000,
(int)(100*i_mtime_filter/i_mtime_total), i_mtime_filter/1000 );
#endif
/* Slices used and PSNR */
for( i=0; i<5; i++ )
{
static const int slice_order[] = { SLICE_TYPE_I, SLICE_TYPE_SI, SLICE_TYPE_P, SLICE_TYPE_SP, SLICE_TYPE_B };
static const char *slice_name[] = { "P", "B", "I", "SP", "SI" };
int i_slice = slice_order[i];
if( h->stat.i_slice_count[i_slice] > 0 )
{
const int i_count = h->stat.i_slice_count[i_slice];
if( h->param.analyse.b_psnr )
{
x264_log( h, X264_LOG_INFO,
"slice %s:%-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_name[i_slice],
i_count,
(double)h->stat.i_slice_qp[i_slice] / i_count,
(double)h->stat.i_slice_size[i_slice] / i_count,
h->stat.f_psnr_mean_y[i_slice] / i_count, h->stat.f_psnr_mean_u[i_slice] / i_count, h->stat.f_psnr_mean_v[i_slice] / i_count,
h->stat.f_psnr_average[i_slice] / i_count,
x264_psnr( h->stat.i_sqe_global[i_slice], i_count * i_yuv_size ) );
}
else
{
x264_log( h, X264_LOG_INFO,
"slice %s:%-5d Avg QP:%5.2f size:%6.0f\n",
slice_name[i_slice],
i_count,
(double)h->stat.i_slice_qp[i_slice] / i_count,
(double)h->stat.i_slice_size[i_slice] / i_count );
}
}
}
/* MB types used */
if( h->stat.i_slice_count[SLICE_TYPE_I] > 0 )
{
const int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_I];
const double i_count = h->stat.i_slice_count[SLICE_TYPE_I] * h->mb.i_mb_count / 100.0;
x264_log( h, X264_LOG_INFO,
"mb I I16..4: %4.1f%% %4.1f%% %4.1f%%\n",
i_mb_count[I_16x16]/ i_count,
i_mb_count[I_8x8] / i_count,
i_mb_count[I_4x4] / i_count );
}
if( h->stat.i_slice_count[SLICE_TYPE_P] > 0 )
{
const int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_P];
const int64_t *i_mb_size = h->stat.i_mb_count_size[SLICE_TYPE_P];
const double i_count = h->stat.i_slice_count[SLICE_TYPE_P] * h->mb.i_mb_count / 100.0;
x264_log( h, X264_LOG_INFO,
"mb P I16..4: %4.1f%% %4.1f%% %4.1f%% P16..4: %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% skip:%4.1f%%\n",
i_mb_count[I_16x16]/ i_count,
i_mb_count[I_8x8] / i_count,
i_mb_count[I_4x4] / i_count,
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_slice_count[SLICE_TYPE_B] > 0 )
{
const int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_B];
const int64_t *i_mb_size = h->stat.i_mb_count_size[SLICE_TYPE_B];
const double i_count = h->stat.i_slice_count[SLICE_TYPE_B] * h->mb.i_mb_count / 100.0;
x264_log( h, X264_LOG_INFO,
"mb B I16..4: %4.1f%% %4.1f%% %4.1f%% B16..8: %4.1f%% %4.1f%% %4.1f%% direct:%4.1f%% skip:%4.1f%%\n",
i_mb_count[I_16x16] / i_count,
i_mb_count[I_8x8] / i_count,
i_mb_count[I_4x4] / i_count,
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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -