首页 > 系统相关 >pjsip内存优化及提升视频呼叫并发数

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

时间:2023-10-24 17:15:31浏览次数:32  
标签:vid stream 解码 pjsip 并发 内存 dec buf size

    工作上的一个上层调度台应用(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

标签:vid,stream,解码,pjsip,并发,内存,dec,buf,size
From: https://www.cnblogs.com/kn-zheng/p/17785248.html

相关文章

  • 查看mysql的cpu及内存占用情况
    命令:psaux可查看服务器下所有进程的cpu和内存  查看单独某个进程的cpu和内存,需要加grep进行搜索,如下:命令:psaux|grepmysql可查看mysql的CPU和内存占用情况,如图cup占用0.6  内存占用14.3 ......
  • 探秘磁盘的奥秘:物理结构、缓存和虚拟内存的作用
    引言在我们之前的讲解中,我们已经详细介绍了CPU和内存的物理结构,这是计算机系统中至关重要的组成部分。然而,除了CPU和内存之外,磁盘也扮演着非常重要的角色,它在数据存储方面起着至关重要的作用。因此,我们将继续向大家介绍磁盘的物理结构,以便更全面地了解计算机系统的工作原理。通过......
  • 升讯威在线客服系统的并发高性能数据处理技术:为多线程处理同步数据
    我在业余时间开发维护了一款免费开源的升讯威在线客服系统,也收获了许多用户。对我来说,只要能获得用户的认可,就是我最大的动力。最近客服系统成功经受住了客户现场组织的压力测试,获得了客户的认可。客户组织多名客服上线后,所有员工同一时间打开访客页面疯狂不停的给在线客服发消......
  • 使用三方摄像头,实现pjsip的视频通话功能
    提要:近期一直在做视频通话功能,主要基于pjsip来实现的,将这些过程记录下来,可能对做同类型工作的同学有所帮助!实现思路,参考pjsip原来设备采集视频、编码并rtp组包发送的思路,再在原有流程中做修改!主要关键点:1、摄像头采集完成后已经是已编码的H264/H265的流,不需要再开启pjsip的编......
  • 一步一图带你深入理解 Linux 物理内存管理
    https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg2MzU3Mjc3Ng==&action=getalbum&album_id=2559805446807928833&scene=173&from_msgid=2247486879&from_itemidx=1&count=3&nolastread=1#wechat_redirect......
  • 一天吃透Java并发面试八股文
    内容摘自我的学习网站:topjavaer.cn分享50道Java并发高频面试题。线程池线程池:一个管理线程的池子。为什么平时都是使用线程池创建线程,直接new一个线程不好吗?嗯,手动创建线程有两个缺点不受控风险频繁创建开销大为什么不受控?系统资源有限,每个人针对不同业务都可以手动......
  • 释放内存(4种方式)
    一、定义delete运算符:用于释放使用new运算符动态分配单个对象的内存。free函数:用于释放使用malloc、calloc或realloc函数动态分配的内存,其语法为free(ptr),其中ptr是指向待释放内存的指针。使用智能指针:C++11引入了智能指针的概念,可以避免手动管理内存,常用的......
  • IO流,对象流,将对象序列化到文件中,将对象反序列化到内存中
    一一一、序列化!!一、首先创建一个对象类,实现Serializable标记接口 对象中,实现了接口,三个私有属性,并且创建了无参有参构造,get和set方法和toString方法 (一个标准的对象模型)二、序列化到外部文件 结果: 也是一堆乱码,还是因为用字节输出的原因。 二二二、反序列化! 结......
  • go并发的取消操作
    Go的并发模式:使用Context进行资源管理原创 lincyang lincyang新自媒体 2023-10-2310:00 发表于河北收录于合集#GO进阶16个大家好!我是[lincyang]。今天我们要一起探讨Go语言中的一个核心话题:使用Context进行资源管理。什么是Context?Context,即上下文,是Go语言中用于......
  • 内存中的消息队列-disruptor
    一、介绍工作中遇到项目使用Disruptor做消息队列,对你没看错,不是Kafka,也不是rabbitmq;Disruptor有个最大的优点就是快,还有一点它是开源的。Disruptor是英国外汇交易公司LMAX开发的一个高性能队列。Disruptor是一个开源的Java框架,它被设计用于在生产者—消费者(producer-cons......