pjsip内存优化及提升视频呼叫并发数

pjsip内存优化及提升视频呼叫并发数

    工作上的一个上层调度台应用(Windows 7),业务功能上有并发调取多个视频的需求,发现调取30左右路D1视频后会导致崩溃,日志提示:except.c  !!!FATAL: unhandled exception PJLIB/No memory!,内存不足,在开发环境下验证发现内存占用已经达到2G以上(32位程序默认最高给2G内存,通过配置能达到3G),所以确实发生系统内存分配失败的问题,开始着手检查内存消耗的点。

之前为了某个项目能解码3.5K视频,把解码能力提升到了4K(4096*2160@60),profile-level-id增加到"428034"

    一个视频呼叫过程中,大块内存分配的位置有(编码分辨率1280*720,最大解码分辨率4096*2160):

1、video_port 解码渲染buf,YUV420P 4:2:0,直接按照最大解码size,分配4096*2160*1.5 = 13271040,13M

2、video_port 采集buf,YUY2 4:2:2,按照编码size,1280*720*2 = 1843200,1.8M

3、video_port 采集转换buf,YUY2->YUV420P,编码分辨率size,1280*720*1.5 = 1382400,1.3M

4、video_port 本地预览buf,YUV420P,按照编码size,1280*720*1.5 = 1382400,1.3M

5、vid_stream 编码通道buf,按照编码size,1280*720*4+12(RTP头) = 3686412,3M

6、vid_stream 解码帧buf,按照最大解码size,4096*2160*4 = 35389400,35M

7、ffmpeg 编码buf,YUV420P,按照编码size,1280*720 = 1382400 ,1.3M

8、ffmpeg 解码buf,YUV420P,按照最大解码size,4096*2160*1.5 = 13271040,13M

9、语音编解码及其他,忽略

合计:13271040+1843200+1382400+1382400+3686412+35389400+1382400+13271040=71608292,71M

30路则大约2.1G内存开销,已经达到默认32位进程上限,验证了结果(第二路以上视频呼叫时采集buf、采集转换buf、本地预览buf已经不会再次分配了)。

分析及思路:编码方向因为是按需设置分辨率,除非调整架构,很多地方没办法动,重点是解码方向,为了兼容最大解码分辨率,每次都分配足够4KYUV视频的空间是有点不必要的,毕竟4K视频仅仅是偶尔出现,绝大多数分辨率仍然覆盖在是720P~VGA之间,所以完全可以将解码分辨率降低到VGA(profile-level-id仍然设置最大值),相关buf不足时重新分配即可。

具体改动:ffmpeg解码buf已经有了Realloc的逻辑

1、vid_stream编码buf,由

stream->frame_size = vfd_enc->size.w * vfd_enc->size.h * 4;

改为

stream->frame_size = vfd_enc->size.w * vfd_enc->size.h * 1.5;

2、vid_stream解码帧buf,由

stream->dec_max_size = vfd_dec->size.w * vfd_dec->size.h * 4;

改为

stream->dec_max_size = vfd_dec->size.w * vfd_dec->size.h * 1.5;

3、vid_stream成功解码后收到PJMEDIA_EVENT_FMT_CHANGED,在get_frame方法中增加解码帧buf大小的判定逻辑

        //to realloc stream dec frame buf and size
        pj_int32_t new_size = fmt_chg_data->new_fmt.det.vid.size.h*fmt_chg_data->new_fmt.det.vid.size.w*1.5;
        if (stream->dec_max_size < new_size)
        {
            PJ_LOG(5, (THIS_FILE, "Reallocating vid_stream dec_buffer %u --> %u",
                (unsigned)stream->dec_max_size,
                (unsigned)new_size));
            pj_mutex_lock(stream->jb_mutex);

            stream->dec_max_size = new_size;
            stream->dec_frame.buf = pj_pool_alloc(stream->own_pool, stream->dec_max_size);
            pj_mutex_unlock(stream->jb_mutex);
        }

4、同样在vid_port 解码渲染buf,client_port_event_cb方法中增加判断buf大小的逻辑

// realloc mem
        int new_size = vp->conv.conv_param.dst.det.vid.size.h*vp->conv.conv_param.dst.det.vid.size.w*1.5;
        PJ_LOG(5, (THIS_FILE, "Reallocating vid_port frm_buffer %u --> %u",
            (unsigned)vp->frm_buf_size,
            (unsigned)new_size));
        if (vp->frm_buf_size < new_size)
        {
            vp->frm_buf_size = new_size;
            vp->frm_buf->buf = pj_pool_alloc(vp->pool, new_size);
            vp->frm_buf->size = vp->frm_buf_size;
        }

由此显著降低并发视频呼叫情况下的内存占用过多问题,另外64路并发呼叫的宏定义可以这样:

#define PJSIP_MAX_TSX_COUNT         1023    //默认
#define PJSIP_MAX_DIALOG_COUNT         511    //默认
#define PJSUA_MAX_CALLS            64
#define PJSUA_MAX_VID_WINS        64
#define PJ_IOQUEUE_MAX_HANDLES 512    //默认值16,最大呼叫数量15,
#define PJSIP_TPMGR_HTABLE_SIZE 512


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
pjsip是一个开源的SIP协议栈,可以用于实现基于SIP协议的电话呼叫。以下是一个简单的pjsip电话呼叫的示例代码: ```c #include <pjsua-lib/pjsua.h> int main() { pj_status_t status; pj_caching_pool cp; pj_pool_t *pool; pjsua_config cfg; pjsua_logging_config log_cfg; pjmedia_transport_config media_cfg; pjmedia_transport *media_transport; pjsua_acc_id acc_id; pjsua_call_id call_id; pj_str_t uri = pj_str("sip:username@domain.com"); // Initialize pjsua status = pj_init(); pj_caching_pool_init(&cp, NULL, 0); pool = pj_pool_create(&cp.factory, "pjsua", 4000, 4000, NULL); pjsua_config_default(&cfg); cfg.cb.on_incoming_call = NULL; cfg.cb.on_call_media_state = NULL; cfg.cb.on_call_state = NULL; cfg.cb.on_reg_state = NULL; pjsua_logging_config_default(&log_cfg); log_cfg.console_level = 4; log_cfg.level = 4; status = pjsua_init(&cfg, &log_cfg, NULL); pjsua_transport_config cfg_transport; pjsua_transport_config_default(&cfg_transport); cfg_transport.port = 5060; status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg_transport, NULL); pjsua_start(); // Register with SIP server pjsua_acc_config acc_cfg; pjsua_acc_config_default(&acc_cfg); acc_cfg.id = pj_str("sip:username@domain.com"); acc_cfg.reg_uri = pj_str("sip:domain.com"); acc_cfg.cred_count = 1; acc_cfg.cred_info[0].realm = pj_str("domain.com"); acc_cfg.cred_info[0].scheme = pj_str("digest"); acc_cfg.cred_info[0].username = pj_str("username"); acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; acc_cfg.cred_info[0].data = pj_str("password"); status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &acc_id); // Make outgoing call pjsua_call_setting call_setting; pjsua_call_setting_default(&call_setting); status = pjsua_call_make_call(acc_id, &uri, &call_setting, NULL, NULL, &call_id); // Destroy pjsua pjsua_destroy(); pj_pool_release(pool); pj_caching_pool_destroy(&cp); return 0; } ``` 这段代码首先初始化了pjsua,然后注册到SIP服务器,最后发起一个呼叫。具体的调用过程可以参考pjsip官方文档。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值