当前位置: 首页 > news >正文

librtmp优化

      librtmp是一个RTMP的开源库,很多地方用它来做推流、拉流。它是RTMPDump开源软件里的一部分,librtmp的下载地址:RTMPDump,目前最新版是V2.3。本文重点介绍librtmp优化。

1、调整网络输出块大小。

RTMP_Connect0函数中LibRTMP是关闭了Nagle算法这个TCP选项的,为了实时性这样做是好的,但是要注意到LibRTMP的结构体RTMP的成员是有m_outChunkSize,并且在RTMP_Init函数中被初始化了默认值128,然后整个LibRTMP代码没有改变m_outChunkSize的接口函数,内部也没有改变m_outChunkSize的实现逻辑,也没有发送改变块大小的消息给流媒体服务器的代码逻辑,关闭Nagle加如此小的块大小会导致很多小包,而以太网的MTU是1500,这样如果用在播放客户端由于主要是接收媒体流到也没有什么,但是如果用在发布媒体流的推流客户端网络效率就太低了,并且IP小包太多还会引起流媒体的服务器软中断升高,导致内核占用的CPU过高。m_outChunkSize在发送给流媒体服务器消息会用于分块,所以从这个方面来说LibRTMP还是部分支持改变块大小的,这部分逻辑实现不需要任何改变。

调整输出块大小的函数

static int
ChangeChunkSize(RTMP *r,int outChunkSize)
{
RTMPPacket packet;
char pbuf[RTMP_MAX_HEADER_SIZE + 4];packet.m_nBytesRead = 0;
packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;packet.m_packetType = RTMP_PACKET_TYPE_CHUNK_SIZE;
packet.m_nChannel = 0x04; 
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
packet.m_nTimeStamp = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
packet.m_nBodySize = 4;
r->m_outChunkSize = outChunkSize;r->m_outChunkSize = htonl(r->m_outChunkSize);memcpy(packet.m_body, &r->m_outChunkSize, 4);r->m_outChunkSize = ntohl(r->m_outChunkSize);return RTMP_SendPacket(r, &packet, TRUE);
}

注1:RTMP协议的消息类型01(RTMP_PACKET_TYPE_CHUNK_SIZE宏的值)就是用于改变输出块大小的消息类型,结合MTU

注2:outChunkSize大小可以选择1500-20(IP头)-20(TCP头)=1460,考虑到IP头、TCP头有扩展选项,加之PPPoE,为保证起见可选为1360,也可以设为大于MTU的其它值,不过这样的话就会出现IP分片了,也不是好习惯。

注3:每当调用本函数后就顺便修改了RTMP的成员变量m_outChunkSize,以保持与服务器收到的一致。

调整网络输出块大小的函数的时机

随时可以调整,只不过在调用ChangeChunkSize函数后,要注意到这个函数内部已经改变了RTMP的成员变量m_outChunkSize,这样在调用这个函数之后的所有发给流媒体服务器的消息要以这个块大小来分块,由于TCP的有序性,服务器在收到该改变块大小的消息后也会以此块大小来解析后序的所有消息,由于播放客户端主要是拉流,播放端需要传给服务器的数据不多,可以不修改,基于此可以在收到connect的响应后的处理逻辑中调用ChangeChunkSize函数,具体如下(HandleInvoke函数中部分代码):

if (r->Link.protocol & RTMP_FEATURE_WRITE)
{
ChangeChunkSize(r, 1360);//若不改拉流时的输出块大小在这里调用ChangeChunkSize
SendReleaseStream(r);
SendFCPublish(r);
}
else
{
RTMP_SendServerBW(r);
RTMP_SendCtrl(r, 3, 0, 300);
}

2、AMF_GetProp函数bug

librtmp\amf.c文件里有个函数(大概是1124行):

AMFObjectProperty *
AMF_GetProp(AMFObject *obj, const AVal *name, int nIndex)
{if (nIndex >= 0){if (nIndex <= obj->o_num) //这里有问题return &obj->o_props[nIndex];}else{int n;for (n = 0; n < obj->o_num; n++){if (AVMATCH(&obj->o_props[n].p_name, name))return &obj->o_props[n];}}return (AMFObjectProperty *)&AMFProp_Invalid;
}

3、librtmp发送阻塞

在librtmp的RTMP_Connect0( )中加入了send超时设置。

/* set timeout */
{struct timeval timeout;timeout.tv_sec = 5;timeout.tv_usec = 0;SET_RCVTIMEO(tv, r->Link.timeout);if (setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))){RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!", __FUNCTION__, r->Link.timeout);}if(setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) == -1){RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!", __FUNCTION__, timeout.tv_sec);}else{RTMP_Log(RTMP_LOGDEBUG, "%s, Setting socket timeout to %ds success!", __FUNCTION__, timeout.tv_sec);}
}

4、librtmp 推流网络断开导致整个应用程序crash的错误,崩溃堆栈出现在WriteN函数中。
解决方法,修改rtmp.c文件中WriteN函数:

static int
WriteN(RTMP *r, const char *buffer, int n)
{const char *ptr = buffer;
#ifdef CRYPTOchar *encrypted = 0;char buf[RTMP_BUFFER_CACHE_SIZE];if (r->Link.rc4keyOut){if (n > sizeof(buf))encrypted = (char *)malloc(n);elseencrypted = (char *)buf;ptr = encrypted;RC4_encrypt2(r->Link.rc4keyOut, n, buffer, ptr);}
#endifwhile (n > 0){int nBytes;if (r->Link.protocol & RTMP_FEATURE_HTTP)nBytes = HTTP_Post(r, RTMPT_SEND, ptr, n);elsenBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n);/*RTMP_Log(RTMP_LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes); */if (nBytes < 0){int sockerr = GetSockError();RTMP_Log(RTMP_LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__,sockerr, n);if (sockerr == EINTR && !RTMP_ctrlC)continue;if(WSAECONNABORTED  == sockerr || WSAECONNRESET  == sockerr){//连接被对方断开RTMP_CloseNoSendAnyData(r);}else{RTMP_Close(r);}n = 1;break;}if (nBytes == 0)break;n -= nBytes;ptr += nBytes;}#ifdef CRYPTOif (encrypted && encrypted != buf)free(encrypted);
#endifreturn n == 0;
}

//新增RTMP_CloseNoSendAnyData函数

void
RTMP_CloseNoSendAnyData(RTMP *r)
{int i;if (RTMP_IsConnected(r)){if (r->m_stream_id > 0){if (r->m_clientID.av_val){HTTP_Post(r, RTMPT_CLOSE, "", 1);free(r->m_clientID.av_val);r->m_clientID.av_val = NULL;r->m_clientID.av_len = 0;}RTMPSockBuf_Close(&r->m_sb);}r->m_stream_id = -1;r->m_sb.sb_socket = -1;r->m_nBWCheckCounter = 0;r->m_nBytesIn = 0;r->m_nBytesInSent = 0;if (r->m_read.flags & RTMP_READ_HEADER) {free(r->m_read.buf);r->m_read.buf = NULL;}r->m_read.dataType = 0;r->m_read.flags = 0;r->m_read.status = 0;r->m_read.nResumeTS = 0;r->m_read.nIgnoredFrameCounter = 0;r->m_read.nIgnoredFlvFrameCounter = 0;r->m_write.m_nBytesRead = 0;RTMPPacket_Free(&r->m_write);for (i = 0; i < RTMP_CHANNELS; i++){if (r->m_vecChannelsIn[i]){RTMPPacket_Free(r->m_vecChannelsIn[i]);free(r->m_vecChannelsIn[i]);r->m_vecChannelsIn[i] = NULL;}if (r->m_vecChannelsOut[i]){free(r->m_vecChannelsOut[i]);r->m_vecChannelsOut[i] = NULL;}}AV_clear(r->m_methodCalls, r->m_numCalls);r->m_methodCalls = NULL;r->m_numCalls = 0;r->m_numInvokes = 0;r->m_bPlaying = FALSE;r->m_sb.sb_size = 0;r->m_msgCounter = 0;r->m_resplen = 0;r->m_unackd = 0;free(r->Link.playpath0.av_val);r->Link.playpath0.av_val = NULL;if (r->Link.lFlags & RTMP_LF_FTCU){free(r->Link.tcUrl.av_val);r->Link.tcUrl.av_val = NULL;r->Link.lFlags ^= RTMP_LF_FTCU;}#ifdef CRYPTOif (r->Link.dh){MDH_free(r->Link.dh);r->Link.dh = NULL;}if (r->Link.rc4keyIn){RC4_free(r->Link.rc4keyIn);r->Link.rc4keyIn = NULL;}if (r->Link.rc4keyOut){RC4_free(r->Link.rc4keyOut);r->Link.rc4keyOut = NULL;}
#endif
}

相关文章:

librtmp优化

librtmp是一个RTMP的开源库&#xff0c;很多地方用它来做推流、拉流。它是RTMPDump开源软件里的一部分&#xff0c;librtmp的下载地址&#xff1a;RTMPDump&#xff0c;目前最新版是V2.3。本文重点介绍librtmp优化。 1、调整网络输出块大小。 RTMP_Connect0函数中LibRTMP是关…...

数据结构与算法(二):线性表

上一篇《数据结构与算法&#xff08;一&#xff09;&#xff1a;概述》中介绍了数据结构的一些基本概念&#xff0c;并分别举例说明了算法的时间复杂度和空间复杂度的求解方法。这一篇主要介绍线性表。 一、基本概念 线性表是具有零个或多个数据元素的有限序列。线性表中数据…...

IOS安全区域适配

对于 iPhone 8 和以往的 iPhone&#xff0c;由于屏幕规规整整的矩形&#xff0c;安全区就是整块屏幕。但自从苹果手机 iphoneX 发布之后&#xff0c;前端人员在开发移动端Web页面时&#xff0c;得多注意一个对 IOS 所谓安全区域范围的适配。这其实说白了就是 iphoneX 之后的苹果…...

在Java 中 利用Milo通信库,实现OPCUA客户端,并生成证书

程序结构&#xff1a; 配置文件resources&#xff1a; opcua.properties 西门子PLC端口号为4840&#xff0c;kepserver为49320 #opcua服务端配置参数 #opcua.server.endpoint.urlopc.tcp://192.168.2.102:49320 opcua.server.endpoint.urlopc.tcp://192.168.2.11:4840 opcu…...

三分钟学会用Vim

Vim知识点 目录Vim知识点一&#xff1a;什么是vim二&#xff1a;vim常用的三种模式三&#xff1a;vim的基本操作一&#xff1a;什么是vim vim最小集 vim是一款多模式的编辑器—各种模式—每种模式的用法有差别—每种模式之间可以互相切换 但是我们最常用的就是3~5个模式 vi…...

编译链接实战(8)认识elf文件格式

&#x1f380; 关于博主&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f947; 作者简介&#xff1a; 热衷于知识探索和分享的技术博主。 &#x1f482; csdn主页:&#xff1a;【奇妙之二进制】 ✍️ 微信公众号&#xff1a;【Linux …...

新手小白如何入门黑客技术?

你是否对黑客技术感兴趣呢&#xff1f;感觉成为黑客是一件很酷的事。那么作为新手小白&#xff0c;我们该如何入门黑客技术&#xff0c;黑客技术又是学什么呢&#xff1f; 其实不管你想在哪个新的领域里有所收获&#xff0c;你需要考虑以下几个问题&#xff1a; 首先&#xff…...

【java】Spring Boot --深入SpringBoot注解原理及使用

步骤一 首先&#xff0c;先看SpringBoot的主配置类&#xff1a; SpringBootApplication public class StartEurekaApplication {public static void main(String[] args){SpringApplication.run(StartEurekaApplication.class, args);} }步骤二 点进SpringBootApplication来…...

一文掌握如何对项目进行诊断?【步骤方法和工具】

作为项目经理和PMO&#xff0c;面对错综复杂的项目&#xff0c;需要对组织的项目运作情况进行精确的分析和诊断&#xff0c;找出组织项目管理中和项目运行中存在的问题和潜在隐患&#xff0c;分析其原因&#xff0c;预防风险&#xff0c;并且形成科学合理的决策建议和解决方案&…...

系统分析师真题2020试卷相关概念二

结构化设计相关内容: 结构化设计是一种面向数据流的系统设计方法,它以数据流图和数据字典等文档为基础。数据流图从数据传递和加工的角度,以图形化方式来表达系统的逻辑功能、数据在系统内部的逻辑流向和逻辑变换过程,是结构化系统分析方法的主要表达工具及用于表示软件模…...

<<Java开发环境配置>>5-MySQL安装教程(绿色版)

一.MySQL绿色版安装: 1.直接解压下载的ZIP文件到对应的目录下(切记安装目录不要有中文); 如图:我的安装目录:D:Program Files 2.创建配置文件: 在MySQL安装目录下&#xff0c;创建一个my.ini配置文件&#xff0c;然后在里面添加以下内容&#xff08;别忘了MySQL安装目录要改成…...

空间复杂度与时间复杂度

1、时间复杂度和空间复杂度 &#xff08;1&#xff09;时间复杂度、空间复杂度是什么&#xff1f; 算法效率分析分为两种&#xff1a;第一种是时间效率&#xff0c;第二种是空间效率。时间效率被称为时间复杂度&#xff0c;空间效率被称作空间复杂度时间复杂度主要衡量的是一…...

javaEE 初阶 — 延迟应答与捎带应答

文章目录1. 延迟应答2. 捎带应答TCP 工作机制&#xff1a;确认应答机制 超时重传机制 连接管理机制 滑动窗口 流量控制与拥塞控制 1. 延迟应答 延时应答 也是提升效率的机制&#xff0c;也是在滑动窗口基础上搞点事情。 滑动窗口的关键是让窗口大小大一点&#xff0c;传输…...

Twitter账号老被封?一文教会你怎么养号

昨天龙哥给大家科普完要怎么批量注册Twitter账号&#xff0c;立刻有朋友来私信龙哥说里面提到的这个养号和防关联具体是个怎么样的做法。由于Twitter检测机制还是比较敏感的&#xff0c;账号很容易被冻结&#xff0c;所以养号是非常重要的步骤。其实要养好Twitter账号其实并不难…...

当遇到国外客户的问题,你解决不了的时候怎么办

对我来说&#xff0c;今年的这个春节假期有点长&#xff0c;差不多休了一个月。复工之后&#xff0c;截止目前做到了60万RMB的业绩&#xff0c;但是相较于往年&#xff0c;整体状态还是差了些。往年的春节&#xff0c;我都是随时待命的状态&#xff0c;整个春节天天坐于电脑前&…...

算法刷题打卡第93天: 最大的以 1 为边界的正方形

最大的以 1 为边界的正方形 难度&#xff1a;中等 给你一个由若干 0 和 1 组成的二维网格 grid&#xff0c;请你找出边界全部由 1 组成的最大 正方形 子网格&#xff0c;并返回该子网格中的元素数量。如果不存在&#xff0c;则返回 0。 示例 1&#xff1a; 输入&#xff1a…...

python语言基础(最详细版)

文章目录一、程序的格式框架缩进1、定义2、这里就简单的举几个例子注释二、语法元素的名称三、数据类型四、数值运算符五、关系运算六、逻辑运算七、运算符的结合性八、字符串一、程序的格式框架 缩进 1、定义 &#xff08;1&#xff09;python中通常用缩进来表示代码包含和…...

Java小技能:字符串

文章目录 引言I 预备知识1.1 Object类1.2 重写的规则1.3 hashCode方法II String2.1 String的特性2.2 字符串和正则2.3 StringBuilder,StringBuffer引言 String,StringBuffer,StringBuilder,char[],用来表示字符串。 ​ I 预备知识 1.1 Object类 是所有类的根类 toString…...

2023美赛D题:可持续发展目标

以下内容全部来自人工翻译&#xff0c;仅供参考。 文章目录背景要求术语表文献服务背景 联合国制定了17个可持续发展目标&#xff08;SDGs&#xff09;。实现这些目标最终将改善世界上许多人的生活。这些目标并不相互独立&#xff0c;因此&#xff0c;一些目标的积极进展常常…...

openwrt开发板与ubuntu nfs挂载

1.ubuntu需要安装nfs服务 sudo apt-get install nfs-common nfs-kernel-server2.修改 /etc/exports文件&#xff1a; /home/test *(rw,nohide,insecure,no_subtree_check,async,no_root_squash) 前面是挂载的目录&#xff0c;后边是相应权限 rw&#xff1a;读写 insecure&am…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)

第一篇&#xff1a;Liunx环境下搭建PaddlePaddle 3.0基础环境&#xff08;Liunx Centos8.5安装Python3.10pip3.10&#xff09; 一&#xff1a;前言二&#xff1a;安装编译依赖二&#xff1a;安装Python3.10三&#xff1a;安装PIP3.10四&#xff1a;安装Paddlepaddle基础框架4.1…...

如何在Windows本机安装Python并确保与Python.NET兼容

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...