解决x264 latency问题

 

最近,我在设计和开发一个基于 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(&params);

       //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(&params,"superfast");//将编码设置成superfast模式【相比其他模式,会有一些花屏】

       x264_param_apply_tune(&params,"zerolatency");//将延时设置成最短

      

       d->enc=x264_encoder_open(&params);

       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;

}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值