概述
最近,我在设计和开发一个基于 Linux 平台的 SIP 接入终端,包括语音视频,会议及 PSIM 的功能。 SIP 终端支持 xvid(mpege4), x264(h264/avc) 等视频 CODEC ,要求支持 30FPS,720P ,软编软解。 对于 xvid 我们很快就达到了上述要求,实时性很好,然而,对于 x264 ,我们发现始终有 5 , 6 秒的延时。经过仔细研究,我们终于解决问题,现在将经验分享给大家。
我们使用和参考了 ffmpeg, xvidcore, x264/msx264 , linphone 等开源代码。 X264 提供了对 h264 的编码功能, msx264 针对 linphone/mediamanager2 提供了 x264 的一个 filter plugin. 通过修改 msx264.c 这个文件,调整 x264 encoding/decoding parameter ,我们解决了 x264 latency 的问题。
感谢党,感谢国家,感谢 google ,感谢开源。
//msx264.c 文件
//我们唯一要做的事修改filter的预处理函数,修改x264的参数设置。以下被红色标志的就是修改代码。非常少的修改。
static void enc_preprocess(MSFilter *f){
EncData *d=(EncData*)f->data;
x264_param_t params;
rfc3984_init(&d->packer);
rfc3984_set_mode(&d->packer,d->mode);
rfc3984_enable_stap_a(&d->packer,FALSE);
x264_param_default(¶ms);
//params.i_threads=1;//如何你使用的是多核,建议你删除这一行,运行264使用多线程同时对多帧编码。
params.i_sync_lookahead=0;
params.i_width=d->vsize.width;
params.i_height=d->vsize.height;
params.i_fps_num=(int)d->fps;
params.i_fps_den=1;
params.i_slice_max_size=ms_get_payload_max_size()-100; /*-100 security margin*/
params.i_level_idc=31;
params.rc.i_rc_method = X264_RC_ABR;
params.rc.i_bitrate=(int)( ( ((float)d->bitrate)*0.8)/1000.0);
params.rc.f_rate_tolerance=0.1;
params.rc.i_vbv_max_bitrate=(int) (((float)d->bitrate)*0.9/1000.0);
params.rc.i_vbv_buffer_size=params.rc.i_vbv_max_bitrate;
params.rc.f_vbv_buffer_init=0.5;
params.rc.i_lookahead=0;
/*enable this by config ?*/
/*
params.i_keyint_max = (int)d->fps*d->keyframe_int;
params.i_keyint_min = (int)d->fps;
*/
params.b_repeat_headers=1;
params.b_annexb=0;
//these parameters must be set so that our stream is baseline
params.analyse.b_transform_8x8 = 0;
params.b_cabac = 0;
params.i_cqm_preset = X264_CQM_FLAT;
params.i_bframe = 0;
params.analyse.i_weighted_pred = X264_WEIGHTP_NONE;
x264_param_apply_preset(¶ms,"superfast");//将编码设置成superfast模式【相比其他模式,会有一些花屏】
x264_param_apply_tune(¶ms,"zerolatency");//将延时设置成最短
d->enc=x264_encoder_open(¶ms);
if (d->enc==NULL) ms_error("Fail to create x264 encoder.");
d->framenum=0;
}
// x264_param_apply_preset及 x264_param_apply_tune 实际上是从x264库里面提取的函数。我基本上不做修改,直接引用这个函数。
//具体的x264 parameters的详细解释,可以参考 http://mewiki.project357.com/wiki/X264_Settings
static int x264_param_apply_preset( x264_param_t *param, const char *preset )
{
if( !strcasecmp( preset, "ultrafast" ) )
{
param->i_frame_reference = 1;
param->i_scenecut_threshold = 0;
param->b_deblocking_filter = 0;
param->b_cabac = 0;
param->i_bframe = 0;
param->analyse.intra = 0;
param->analyse.inter = 0;
param->analyse.b_transform_8x8 = 0;
param->analyse.i_me_method = X264_ME_DIA;
param->analyse.i_subpel_refine = 0;
param->rc.i_aq_mode = 0;
param->analyse.b_mixed_references = 0;
param->analyse.i_trellis = 0;
param->i_bframe_adaptive = X264_B_ADAPT_NONE;
param->rc.b_mb_tree = 0;
param->analyse.i_weighted_pred = X264_WEIGHTP_NONE;
param->analyse.b_weighted_bipred = 0;
param->rc.i_lookahead = 0;
}
else if( !strcasecmp( preset, "superfast" ) )
{
param->analyse.inter = X264_ANALYSE_I8x8|X264_ANALYSE_I4x4;
param->analyse.i_me_method = X264_ME_DIA;
param->analyse.i_subpel_refine = 1;
param->i_frame_reference = 1;
param->analyse.b_mixed_references = 0;
param->analyse.i_trellis = 0;
param->rc.b_mb_tree = 0;
param->analyse.i_weighted_pred = X264_WEIGHTP_NONE;
param->rc.i_lookahead = 0;
}
else if( !strcasecmp( preset, "veryfast" ) )
{
param->analyse.i_me_method = X264_ME_HEX;
param->analyse.i_subpel_refine = 2;
param->i_frame_reference = 1;
param->analyse.b_mixed_references = 0;
param->analyse.i_trellis = 0;
param->analyse.i_weighted_pred = X264_WEIGHTP_NONE;
param->rc.i_lookahead = 10;
}
else if( !strcasecmp( preset, "faster" ) )
{
param->analyse.b_mixed_references = 0;
param->i_frame_reference = 2;
param->analyse.i_subpel_refine = 4;
param->analyse.i_weighted_pred = X264_WEIGHTP_BLIND;
param->rc.i_lookahead = 20;
}
else if( !strcasecmp( preset, "fast" ) )
{
param->i_frame_reference = 2;
param->analyse.i_subpel_refine = 6;
param->rc.i_lookahead = 30;
}
else if( !strcasecmp( preset, "medium" ) )
{
/* Default is medium */
}
else if( !strcasecmp( preset, "slow" ) )
{
param->analyse.i_me_method = X264_ME_UMH;
param->analyse.i_subpel_refine = 8;
param->i_frame_reference = 5;
param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;
param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO;
param->rc.i_lookahead = 50;
}
else if( !strcasecmp( preset, "slower" ) )
{
param->analyse.i_me_method = X264_ME_UMH;
param->analyse.i_subpel_refine = 9;
param->i_frame_reference = 8;
param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;
param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO;
param->analyse.inter |= X264_ANALYSE_PSUB8x8;
param->analyse.i_trellis = 2;
param->rc.i_lookahead = 60;
}
else if( !strcasecmp( preset, "veryslow" ) )
{
param->analyse.i_me_method = X264_ME_UMH;
param->analyse.i_subpel_refine = 10;
param->analyse.i_me_range = 24;
param->i_frame_reference = 16;
param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;
param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO;
param->analyse.inter |= X264_ANALYSE_PSUB8x8;
param->analyse.i_trellis = 2;
param->i_bframe = 8;
param->rc.i_lookahead = 60;
}
else if( !strcasecmp( preset, "placebo" ) )
{
param->analyse.i_me_method = X264_ME_TESA;
param->analyse.i_subpel_refine = 10;
param->analyse.i_me_range = 24;
param->i_frame_reference = 16;
param->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;
param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO;
param->analyse.inter |= X264_ANALYSE_PSUB8x8;
param->analyse.b_fast_pskip = 0;
param->analyse.i_trellis = 2;
param->i_bframe = 16;
param->rc.i_lookahead = 60;
}
else
{
return -1;
}
return 0;
}
static int x264_param_apply_tune( x264_param_t *param, const char *tune )
{
if( !strncasecmp( tune, "film", 4 ) )
{
param->i_deblocking_filter_alphac0 = -1;
param->i_deblocking_filter_beta = -1;
param->analyse.f_psy_trellis = 0.15;
}
else if( !strncasecmp( tune, "animation", 9 ) )
{
param->i_frame_reference = param->i_frame_reference > 1 ? param->i_frame_reference*2 : 1;
param->i_deblocking_filter_alphac0 = 1;
param->i_deblocking_filter_beta = 1;
param->analyse.f_psy_rd = 0.4;
param->rc.f_aq_strength = 0.6;
param->i_bframe += 2;
}
else if( !strncasecmp( tune, "grain", 5 ) )
{
param->i_deblocking_filter_alphac0 = -2;
param->i_deblocking_filter_beta = -2;
param->analyse.f_psy_trellis = 0.25;
param->analyse.b_dct_decimate = 0;
param->rc.f_pb_factor = 1.1;
param->rc.f_ip_factor = 1.1;
param->rc.f_aq_strength = 0.5;
param->analyse.i_luma_deadzone[0] = 6;
param->analyse.i_luma_deadzone[1] = 6;
param->rc.f_qcompress = 0.8;
}
else if( !strncasecmp( tune, "stillimage", 5 ) )
{
param->i_deblocking_filter_alphac0 = -3;
param->i_deblocking_filter_beta = -3;
param->analyse.f_psy_rd = 2.0;
param->analyse.f_psy_trellis = 0.7;
param->rc.f_aq_strength = 1.2;
}
else if( !strncasecmp( tune, "psnr", 4 ) )
{
param->rc.i_aq_mode = X264_AQ_NONE;
param->analyse.b_psy = 0;
}
else if( !strncasecmp( tune, "ssim", 4 ) )
{
param->rc.i_aq_mode = X264_AQ_AUTOVARIANCE;
param->analyse.b_psy = 0;
}
else if( !strncasecmp( tune, "fastdecode", 10 ) )
{
param->b_deblocking_filter = 0;
param->b_cabac = 0;
param->analyse.b_weighted_bipred = 0;
param->analyse.i_weighted_pred = X264_WEIGHTP_NONE;
}
else if( !strncasecmp( tune, "zerolatency", 11 ) )
{
param->rc.i_lookahead = 0;
param->i_sync_lookahead = 0;
param->i_bframe = 0;
param->b_sliced_threads = 1;
param->b_vfr_input = 0;
param->rc.b_mb_tree = 0;
}
else if( !strncasecmp( tune, "touhou", 6 ) )
{
param->i_frame_reference = param->i_frame_reference > 1 ? param->i_frame_reference*2 : 1;
param->i_deblocking_filter_alphac0 = -1;
param->i_deblocking_filter_beta = -1;
param->analyse.f_psy_trellis = 0.2;
param->rc.f_aq_strength = 1.3;
if( param->analyse.inter & X264_ANALYSE_PSUB16x16 )
param->analyse.inter |= X264_ANALYSE_PSUB8x8;
}
else
{
return -1;
}
return 0;
}
最后
以上就是典雅日记本为你收集整理的解决x264 latency问题的全部内容,希望文章能够帮你解决解决x264 latency问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复