-
2015-01-15 09:42:15
名称
librtmp − RTMPDump Real-Time Messaging Protocol API
库
RTMPDump RTMP(librtmp, -lrtmp)
简介
#include<librtmp/rtmp.h>
描述
实时流协议(Real-TimeMessaging Protocol,RTMP)是用于互联网上传输视音频数据的网络协议。本API提供了支持RTMP, RTMPT,RTMPE, RTMP RTMPS以及以上几种协议的变种(RTMPTE, RTMPTS)协议所需的大部分客户端功能以及少量的服务器功能。尽管Adobe公司已经公布了RTMP协议规范(RTMP specification),但是本工程并不是通过Adobe的协议规范而是通过逆向工程的方式完成的。因此,它的运行方式可能和公布的协议规范有所偏离,但是一般情况下它和Adobe的客户端的运行方式是一模一样的。
RTMPDump 软件包含一个基本的客户端:rtmpdump,一些示例服务器和一个用来提供对RTMP协议进行支持的库(libRTMP)。本页面对libRTMP的函数进行一个概述。 这些函数可以在 -lrtmp 库中找到。其他还有很多函数,但是还没有为这些函数写文档。
基本的操作如下文所述。
RTMP_Alloc() :用于创建一个RTMP会话的句柄。
RTMP_Init():初始化句柄。
RTMP_SetupURL():设置会话的参数。
RTMP_Connect():建立RTMP链接中的网络连接(NetConnection)。
RTMP_ConnectStream():建立RTMP链接中的网络流(NetStream)。
RTMP_Read():读取RTMP流的内容。
客户端可以在调用RTMP_Connect()之前调用RTMP_EnableWrite(),然后在会话开始之后调用 RTMP_Write()。
RTMP_Pause():流播放的时候可以用于暂停和继续
RTMP_Seek():改变流播放的位置
当RTMP_Read()返回0 字节的时候,代表流已经读取完毕,而后可以调用RTMP_Close()
RTMP_Free():用于清理会话。
所有的数据都使用 FLV 格式进行传输。一个基本的会话需要一个RTMP URL。RTMP URL 格式如下所示:
rtmp[t][e|s]://hostname[:port][/app[/playpath]]
支持普通的,隧道的,以及加密的会话。
其他附加的选项可以在URL的后面添加以空格为间隔符的“key=value”形式的字符串。
选项
网络(Network)参数
这些选项定义了如何连接一个流媒体服务器。
socks=host:port
使用指定 SOCKS4代理。
连接(Connection)参数
这些选项定义了RTMP连接(Connect)请求消息的内容。如果没有提供正确的值,流媒体服务器会拒绝连接请求。
app=name
连接到RTMP的应用名,覆盖RTMP URL中的app。有时rtmpdumpURL 无法正确自动解析app名称。这时必须使用该选项。
tcUrl=url
目标流的URL。默认是 rtmp[t][e|s]://host[:port]/app.
pageUrl=url
流媒体所在的网页的URL。默认情况下没有被发送的价值。
swfUrl=url
流媒体使用的SWF播放器的的URL。默认情况下没有被发送的价值。
flashVer=version
swf播放器使用的Flash版本. 默认是"LNX 10,0,32,18"。
conn=type:data
任意AMF数据追加到connect,类型说明,
B 布尔型
N 数字
S 字符串
O 对象
Z 空
对于布尔型必须是0或1作为FALSE或TRUE,
对于对象数据必须以0或1分别作为结束和开始的标制,子对象中数据项前加前缀类型N,并指定值名称,例如:
-C B:1 -C S:authMe -C O:1 -C NN:code:1.23-C NS:flag:ok -C O:0
会话(Session)参数
这些选项在连接成功后生效。
playpath=path
覆盖RTMP URL解析的playpath,rtmpdump有时不能正确解析,通过该选项明确。
playlist=0|1
在play命令之前发生set_playlist命令。否则播放列表将会值包含playpath。
live=0|1
指定媒体是实时流。在实时流中没有恢复和搜索。
subscribe=path
订阅的实时流名称。默认playpath。
start=num
开始到流的秒数(num),实时流无效。
stop=num
停止到流的秒数(num)。
buffer=num
设置缓冲时间,单位毫秒。 默认值36000000。
timeout=num
num秒后没有收到任何数据会话超时,默认值120。
安全(Security)参数
这些选项处理额外的身份验证,来自服务器的请求。
token=key
输入安全令牌响应,如果服务器需要使用安全令牌验证。
jtv=JSON
JSON令牌用于传统Justin.tv服务器 ,调用NetStream.Authenticate.UsherToken。
swfVfy=0|1
swf播放器的URL,此选项将替换所以三个--swfUrl,--swfhash, and --swfsize选项。使用此选项时,swf播放器将从指定URL检索,并自动计算哈希和大小。此外信息缓存在一个swfinfo文件在用户主目录,所以它在每次rtmpdump运行时,并不需要检索和重新计算。swfinfo记录URL,生成时间,修改SWF文件时间,它的大小,它的哈希,默认情况下,缓冲信息用于30天,然后重新检测。
swfAge=days
指定使用缓存的swf信息天数,然后重新检查,使用0为经常检查,如果检查显示swf具有相同的修改时间戳,它不会被再次检索。
例子
RTMP_SetupURL()使用的一个例子字符串:
"rtmp://flashserver:1935/ondemand/thefile swfUrl=http://flashserver/player.swfswfVfy=1"
参见
作者
Andrej Stepanchuk, Howard Chu,The Flvstreamer Team
翻译的有的地方还不是很通顺,以后再改进
更多相关内容 -
在FFMPEG中使用libRTMP的经验
2018-11-18 03:20:41在FFMPEG中使用libRTMP的经验分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
FFMPEG在编译的时候可以选择支持RTMP的类库libRTMP。这样ffmpeg就可以支持rtmp://, rtmpt://, rtmpe://, rtmpte://,以及 rtmps://协议了。但是如何使用ffmpeg支持RTMP协议还是有一定的学问的。本文总结一下部分经验。
ffmpeg接受一个字符串的输入方式,比如:“rtmp://xxxx live=1 playpath=xxx ...”这种的输入形式,即第一个字符串是rtmp的url,然后加一个空格,然后再附加一些参数。附加的参数的格式形如“playpath=xxxx”这种形式。这个乍一看让人觉得有点不习惯。因为一般的输入只包含一个字符串,比如说一个流媒体的url或者是文件的路径,不会采用“url+空格+参数1+参数2+...”的形式。
例如,当需要打开一个直播流的时候,可以用如下字符串(这里连接的是中国教育电视台1频道(网络直播)):
rtmp://pub1.guoshi.com/live/newcetv1
当需要用ffmpeg保存RTMP直播流媒体的时候:
ffmpeg -i "rtmp://pub1.guoshi.com/live/newcetv1 live=1" -vcodec copy -acodec copy ttt.flv
当需要用ffplay播放RTMP直播流媒体的时候:
ffplay "rtmp://pub1.guoshi.com/live/newcetv1 live=1"
在使用FFMPEG类库进行编程的时候,也是一样的,只需要将字符串传递给avformat_open_input()就行了,形如(这里连接的是香港电视台频道(网络直播)):
char url[]="rtmp://live.hkstv.hk.lxdns.com/live/hks live=1";avformat_open_input(&pFormatCtx,url,NULL,&avdic)
注:librtmp支持的参数:http://rtmpdump.mplayerhq.hu/librtmp.3.html
给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
-
java使用opengl源码-oarplayer:AndroidRtmp播放器,基于MediaCodec与srs-librtmp,不依赖ffm
2021-06-05 16:00:20java使用opengl源码 Android Rtmp 播放器 oarplayer(only android rtmp player)是一款简单到毫无特色的纯rtmp播放器, ...支持设置缓存时长. 已知问题及优化计划 srs-librtmp库裁剪以及增加读超时时间配 -
libRTMP 整体说明
2021-06-29 14:54:33(libRTMP)的整体的函数调用结构图如下图所示: 二、基本流程 使用RTMP下载一个流媒体的大致流程是这样的: RTMP_Init();//初始化结构体 InitSockets();//初始化Socket RTMP_ParseURL();//解析输入URL RTMP_...一、函数结构
(libRTMP)的整体的函数调用结构图如下图所示:
二、基本流程
使用RTMP下载一个流媒体的大致流程是这样的:RTMP_Init();//初始化结构体 InitSockets();//初始化Socket RTMP_ParseURL();//解析输入URL RTMP_SetupStream();//一些设置 fopen();//打开文件,准备写入 RTMP_Connect();//建立NetConnection RTMP_ConnectStream()//建立NetStream Download();//下载函数 RTMP_Close();//关闭连接 fclose();//关闭文件 CleanupSockets();//清理Socket
-
librtmp库API介绍及其结构概述
2020-10-31 13:27:57文章目录librtmp库API介绍及其结构概述1、librtmp API的使用1.1 librtmp API的使用流程1.2 librtmp的实例1.3 librtmp API详解1.3.1 librtmp中的chunk和message1.3.2 RTMP基本API1.3.3 设置RTMP的属性1.3.4 连接...librtmp库API介绍及其结构概述
rtmp是常见的一种流媒体协议,它是由Adobe公司提出的一种应用层协议。rtmp传输的是flv格式的封装数据,flv中保存的一般是H.264视频流和AAC音频流。
librtmp库实现了rtmp协议的客户端功能,以及少数服务端功能,是学习rtmp的一个良好的工具。
本文针对librtmp的主要API做了介绍,并整理了librtmp的大致实现框架,但并没有详细深入到具体细节。本文并非入门类的文章,而是一个提纲挈领性的总结,希望对想要使用librtmp以及学历librtmp的人有所帮助。
在想要深入理解librtmp是如何工作之前,请先对FLV封装格式和rtmp协议做相关了解。
1、librtmp API的使用
1.1 librtmp API的使用流程
librtmp API的使用流程可以概括为如下几步:
-
分配并初始化一个RTMP实例
-
设置RTMP实例的参数
-
调用RTMP_Connect函数连接到服务器
-
调用RTMP_ConnectStream函数创建一个rtmp流
-
使用RTMP_Read或RTMP_Write进行读写,或者对rtmp流进行控制(如暂停、停止等)
-
读写完成后,关闭并释放RTMP
在librtmp中,使用结构体RTMP表示一个rtmp连接。
在第2步中根据自己的需要对rtmp连接做相应的设置,后续librtmp就会根据我们的设置做对应的操作。注意这里仅仅是设置了参数,这些参数尚未被使用。考察以下两个接口:
//设置缓冲的时长,单位:毫秒 void RTMP_SetBufferMS(RTMP *r, int size); //发送“设置缓冲时长”的控制包 void RTMP_UpdateBufferMS(RTMP *r);
前者仅是将size这个参数保存到实例r中,后者则是使用实例r中参数并起到实际的作用。
因此,要注意:一般我们仅在第2步进行参数设置操作,不建议在其他地方进行参数设置,这是因为设置参数和这个参数实际起到相关作用是两个概念。当然,如果你非常了解librtmp的工作方式,也可以在其他地方进行设置。
在连接到rtmp服务器,并建立一个rtmp流之后,我们就可以对这个流进行相关的操作。例如,可以进行暂停、停止等操作,也可以读取或者写入到rtmp流。
等相关操作完成之后,必须关闭并释放RTMP实例。
1.2 librtmp的实例
我们首先查看两个使用librtmp API的例子,了解一下其API以及使用流程。
首先,是读取rtmp流另存为flv文件的示例:
https://blog.csdn.net/leixiaohua1020/article/details/42104893
然后是将本地文件上传到rtmp服务器的示例:
https://blog.csdn.net/leixiaohua1020/article/details/42104945
在详细了解了上述两个例子后,就可以详细系统地学习librtmp的API。
1.3 librtmp API详解
通过上述的示例我们知道RTMP类型是librtmp中非常重要的一个类型,我们现在查看一下它的相关API。
先不必查看RTMP的具体组成,我们只需要知道它代表一个rtmp流就可以了。下面就是RTMP相关的最基本的API。
这些基本API包括有:分配,初始化,关闭rtmp流,释放。
1.3.1 librtmp中的chunk和message
首先,我们了解一下librtmp中chunk和Message相关的结构体,以及其相关的操作。
以下分别对应chunk和Mesage的结构体:
/* 表示一个 raw chunk,原始chunk c_header,c_headerSize:保存chunk header的数据和大小 c_chunk,c_chunkSize:保存chunk data的数据和大小 */ typedef struct RTMPChunk { int c_headerSize; int c_chunkSize; char *c_chunk; char c_header[RTMP_MAX_HEADER_SIZE]; } RTMPChunk; /* 表示一个Message m_headerType :表示m_chunk的类型,即chunk header中的basic header中的fmt m_packetType :表示Message Type ID m_hasAbsTimestamp :表示时间戳是绝对的还是相对的,即chunk type为0时为绝对时间戳,其他类型时为时间戳增量 m_nChannel :表示chunk Stream ID m_nTimeStamp :时间戳 m_nInfoField2 :chunk fmt为0时,header的最后四个字节,即Message Stream ID m_nBodySize :Message的body的尺寸 m_nBytesRead :已经读取到的body的字节数 m_chunk :如果不为NULL,表示用户想要获取chunk,那么在读取Message时,会填充这个字段 m_body :Message的body */ typedef struct RTMPPacket { uint8_t m_headerType; uint8_t m_packetType; uint8_t m_hasAbsTimestamp; /* timestamp absolute or relative? */ int m_nChannel; uint32_t m_nTimeStamp; /* timestamp */ int32_t m_nInfoField2; /* last 4 bytes in a long header */ uint32_t m_nBodySize; uint32_t m_nBytesRead; RTMPChunk *m_chunk; char *m_body; } RTMPPacket; //将全部字段置空(缓冲区仍在) void RTMPPacket_Reset(RTMPPacket *p); //打印packet void RTMPPacket_Dump(RTMPPacket *p); //为p分配缓冲区,其中包括固定大小的header,nSize大小的body int RTMPPacket_Alloc(RTMPPacket *p, int nSize); //释放缓冲区 void RTMPPacket_Free(RTMPPacket *p); //packet是否完备 #define RTMPPacket_IsReady(a) ((a)->m_nBytesRead == (a)->m_nBodySize)
注意以下几点:
- chunk仅有一个保存其原始内容的结构体,而没有详细的相关字段的结构体;
- message中的字段名有些似是而非,而且所包含的内容似乎和chunk的内容有所混淆,这是因为librtmp是逆向工程的产物,作者是根据实际rtmp的数据包猜测rtmp协议的内容,逆向解析rtmp协议,当时Adobe尚未公布rtmp协议的内容;
1.3.2 RTMP基本API
//分配一个RTMP //其操作仅仅是分配一块RTMP大小的内存而已,RTMP也可以在栈上分配 RTMP *RTMP_Alloc(void); //初始化RTMP,将RTMP各个字段设置为默认值 void RTMP_Init(RTMP *r); //关闭这个RTMP,如果当前处于连接状态,则会关闭连接;然后释放RTMP相关的内容 void RTMP_Close(RTMP *r); //释放RTMP的内存 void RTMP_Free(RTMP *r);
1.3.3 设置RTMP的属性
分配并初始化一个RTMP实例之后,就需要设置RTMP实例的属性,以下就是设置属性相关的API。
//解析RTMP地址 //url的格式为:protocol://host:port/app/playpath,将解析后的字段通过参数返回 int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, AVal *playpath, AVal *app); //从RTMP URL中解析playpath void RTMP_ParsePlaypath(AVal *in, AVal *out); //设置缓冲的时长,单位:毫秒 void RTMP_SetBufferMS(RTMP *r, int size); //设置RTMP的相关属性 //如果opt指定的属性不存在,那么会调用RTMP_OptUsage()打印出RTMP所有的属性。 int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg); //打印rtmp所有的属性 static void RTMP_OptUsage(); //设置url int RTMP_SetupURL(RTMP *r, char *url); //设置流 void RTMP_SetupStream(RTMP *r, int protocol, AVal *hostname, unsigned int port, AVal *sockshost, AVal *playpath, AVal *tcUrl, AVal *swfUrl, AVal *pageUrl, AVal *app, AVal *auth, AVal *swfSHA256Hash, uint32_t swfSize, AVal *flashVer, AVal *subscribepath, int dStart, int dStop, int bLiveStream, long int timeout); //设置RTMP Link添加写属性 //即要pulish一个流而不是play一个流 void RTMP_EnableWrite(RTMP *r);
首先,RTMP_ParseURL() 和 RTMP_ParsePlaypath() 是两个辅助函数,它们用于将形似protocol://host:port/app/playpath 的字符串,解析为对应的各个字段,然后再设置给RTMP示例。
后面5个函数才是设置属性的函数。其中,RTMP_SetBufferMS() 和 RTMP_EnableWrite() 只能设置单个相关的属性:前者设置“缓冲时长”,后者告诉librtmp我们要使用polish而非play,即我们要推流到服务器而不是从服务器拉流。
而剩下的三个函数在本质上是一样的,没有任何区别,只是为设置属性提供了不同形式的接口而已。RTMP_SetOpt() 会根据opt来设置不同的属性;RTMP_SetupURL() 则在底层会调用 RTMP_ParseURL() 函数,然后将解析出来的各个字段分别设置为RTMP实例的不同属性;RTMP_SetupStream() 则提供了一个方便的接口,让我们可以一次性设置全部的属性。
那么,RTMP具体可以设置哪些属性呢?我们不在这里赘述,请查看rtmpdump的介绍,其中详细介绍了RTMP的相关属性。
1.3.4 连接服务器
/* 客户端发起一个和服务器的TCP连接,并执行Connect 内部调用了RTMP_Connect0来完成TCP层面的连接 调用RTMP_Connect1完成了Connect */ int RTMP_Connect(RTMP *r, RTMPPacket *cp); struct sockaddr; //将host和port信息写入到sockaddr_in中 static int add_addr_info(struct sockaddr_in *service, AVal *host, int port); //连接到指定地址(服务器地址或代理地址),仅在TCP层 int RTMP_Connect0(RTMP *r, struct sockaddr *svc); //假定TCP层面的连接已经完成 //进行handshake以及发送Connect Message int RTMP_Connect1(RTMP *r, RTMPPacket *cp); //服务端处理handshake,成功返回值大于0 int RTMP_Serve(RTMP *r);
从用户的角度而言,这部分没什么内容,仅需知道 RTMP_Connect() 函数可以连接到rtmp服务器即可。
1.3.5 创建rtmp流
//连接到url指定的流,返回TRUE和FLASE int RTMP_ConnectStream(RTMP *r, int seekTime);
这一步也比较简单,仅需注意在调用它之前,设置足够的属性即可。尤其是如下两点:
- 设置正确的的url信息
- 如果是推流,即polish,那么调用 RTMP_EnableWrite() ,如果是播放一个流,即play,那么不需要额外设置,默认就是play操作。
1.3.6 对RTMP流的操作
rtmp流创建完成之后,就可以针对这个流做相关的操作。针对RTMP流的操作,可以分为三大类:一类是控制操作,如暂停、停止、恢复、重新连接、中断等等操作;第二类是查询类接口,返回rtmp流的当前状态;最后一类则是读写操作,用于读取或者写入rtmp流数据。
1.3.6.1 控制类API
//发送“设置缓冲时间”的控制包 void RTMP_UpdateBufferMS(RTMP *r); //暂停或者恢复流 int RTMP_ToggleStream(RTMP *r); //重新连接流,即delete Stream之后再次Connect Stream,且同步等待到流开始 int RTMP_ReconnectStream(RTMP *r, int seekTime); //停止流,或者删除流 void RTMP_DeleteStream(RTMP *r); //RTMP流程被打断 //本质为设置全局变量RTMP_ctrlC为true void RTMP_UserInterrupt(void); /* user typed Ctrl-C */
所谓控制类的API,就是会对当前rtmp流产生改变的API。从用户角度而言,一般就是对rtmp流进行暂停、恢复、停止等操作,而在rtmp协议层面,还会有其他的操作。在这里我们仅关注前者,无论是那种API,它们都是通过发送一个RTMP Msg来实现的。
1.3.6.2 查询类API
//RTMP是否处于连接状态 int RTMP_IsConnected(RTMP *r); //返回RTMP关联的套接字 int RTMP_Socket(RTMP *r); //RTMP是否中断 int RTMP_IsTimedout(RTMP *r); //获得RTMP当前流的长度 double RTMP_GetDuration(RTMP *r);
查看当前rtmp流的相关状态或者信息。
1.3.6.3 读写类API
//RTMP读取到一个packet,并不保证一定读取到完整的packet int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet); //使用RTMP发送packet,queue表示是否按照队列发送 int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue); //RTMP发送一个chunk int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk); //使用RTMP读取数据 int RTMP_Read(RTMP *r, char *buf, int size); //使用RTMP写入数据 int RTMP_Write(RTMP *r, const char *buf, int size);
librtmp中的读写的接口非常多,如果不了解的话,根本不知道应该调用哪些函数来完成我们的功能。
以上是我们最常用的5个读写API,先暂时记住,会使用即可。我们在下面会详细介绍librtmp的读写流程。
2. librtmp数据流的读写流程
我们只有全面了解了librtmp库的数据解析流程,才能对这个库有一个整体的把握,从而更合理的使用这个库。并通过这个过程印证学习RTMP协议,这才是最重要的。
我根据自己的理解,将数据解析的流程分为多个层次,下面我们按照从底到高的顺序一一了解其解析流程。
2.1 传输层
标准的rtmp协议在底层使用TCP协议传输数据,而有的一些变种rtmp协议则可能会使用HTTP协议来传输数据。无论使用那种协议,这部分都有且仅有数据传输的功能,因此我们将其称为传输层。
传输层对上提供了一组统一的接口,以封装其传输协议的不同,接口如下所示:
//读取N个字节,返回实际读取到的字节数 static int ReadN(RTMP *r, char *buffer, int n); //写入N个字节,返回实际写入的字节数 static int WriteN(RTMP *r, const char *buffer, int n);
而传输层则依赖更底层的TCP接口和HTTP接口。
2.1.1 TCP接口
TCP层相关的定义如下,较为简单:
/* RTMPSockBuf:RTMP的套接字缓存 表示一个TCP套接字连接,以及其读取缓存 sb_socket :Socket套接字 sb_size :buffer中未处理的字节数量,即缓冲数据的大小 sb_start :指向buffer中需要处理的字节,即指向缓冲数据 sb_buf :数据读取缓冲区 sb_timedout :套接字是否中断 sb_ssl :SSL相关数据 */ typedef struct RTMPSockBuf { int sb_socket; int sb_size; /* number of unprocessed bytes in buffer */ char *sb_start; /* pointer into sb_pBuffer of next byte to process */ char sb_buf[RTMP_BUFFER_CACHE_SIZE]; /* data read from socket */ int sb_timedout; void *sb_ssl; } RTMPSockBuf; //TCP层面的操作:读、写、关闭 int RTMPSockBuf_Fill(RTMPSockBuf *sb); int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len); int RTMPSockBuf_Close(RTMPSockBuf *sb);
2.1.2 HTTP层接口
HTTP层的接口也相对简单,如下所示:
//HTTP层面的操作:读,写 static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len); static int HTTP_read(RTMP *r, int fill);
2.2 Message读写层
这个层在传输层之上,它的作用是读写Message和Chunk。
这个层是非常单纯的读写的层,它直接解析从传输层读取到的数据,而不处理解析出来的Message和Chunk,它也不管要写入的数据的内容是什么,直接调用传输层接口写入相关数据。
特点:解析数据,但不处理数据的内容,而是交给更上层处理。
/* 作用:读取一个chunk,然后查看chunk是否能合成一个完整的Message 默认条件:函数调用前后,当前流的第一个字节为新的Chunk的开始字节 如果packet读取完毕,通过packet可以获取到相关的数据 如果packet尚未读取完毕,不能通过packet获取到相关的数据,但可以获取相关的情况 */ int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet); /* 将msg拆分为chunk后,写入chunk 1 分析msg所使用的chunk的type 2 拆分msg为chunk 3 当msg为command msg时,处理相关字段 底层调用WriteN()函数,而不是RTMP_SendPacket()函数 */ int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue); /* 直接写入chunk,但rtmp库中并没有使用这个函数,建议用户也不要使用 内容:仅仅是写入chunk 底层调用WriteN()函数 */ int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk)
2.3 业务层
在Message读写层之上,业务层对其进行了相关且必要的业务处理,具体包括:
- 对服务器发送的非media Message的处理
- 过滤非media Message
- 处理seek操作
- 处理resume操作
- 过滤尺寸过小的video和audio rtmp Message
这样,经过业务层后,返回的就是用户想要获取的媒体数据和元对象数据了。这里所谓的“用户想要获取”,包含了用户指定的seek和resume操作。
/* Read from the stream until we get a media packet. * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media * packets, 0 if ignorable error, >0 if there is a media packet * * 从流中读取数据,直到获取到一个媒体packet * 什么是媒体packet,请查看RTMP_GetNextMediaPacket()函数 * 返回值:表示当前RTMP流的状态,即RTMP_READ.status,如下: * 有可忽略的错误返回0,读取到了媒体packet返回正值 * * 作用:处理设置后的RTMP连接,并返回媒体RTMPPacket * * 1 处理seek * 2 处理resume * 3 过滤非media rtmp packet(通过调用 RTMP_GetNextMediaPacket() 完成) * 4 过滤尺寸太小的video audio rtmppacket */ static int Read_1_Packet(RTMP *r, char *buf, unsigned int buflen); /* 获取一个Media message 忽略不是Media Message的Message,直到获取media message。这个函数会调用RTMP_ReadPacket函数读取一个Message,然后调用RTMP_ClientPacket处理读取到的Message。 什么是media Message,详情查看RTMP_ClientPacket */ int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet) /* 客户端处理Message 返回值: 1表示packet为audio,video,metadata message(object msg中的一种),聚合 message 2表示packet为command message,且为Play.Complete或Play.Stop等表示流暂停或结束 0表示其他message 这个函数通过调用下面的handle message块,完成对各种类型Message的调用 当返回值大于0时,表示这个packet是一个media packet,即这个packet真的包含媒体数据,或者是一些表示媒体已经结束或暂停,暂时不可能获取到真的媒体数据,因此返回,防止逻辑卡死在这里。 */ int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
2.4 FLV读写层
rtmp流经过业务层处理后,就剩下媒体数据和元对象数据了,但这些数据仍然是以Message形式存在的,而有时,我们需要以字节流的形式,即flv格式的字节流,来保存媒体数据,因此就有了FLV读写层,其作用如下:
- Read时,将Message格式的媒体数据转化为为FLV TAG格式;Write时,相反
- Read时,补全FLV Header部分;Write时,跳过FLV Header部分
这也是为什么上述第一个rtmp示例,将rtmp流保存为flv文件,使用FLV读写层接口的原因;而且在第二个示例中,也有分别使用FLV读写层和Message读写层API的不同示例,其最大的不同就在于一个是FLV TAG形式的字节流形式,一个是RTMPPacket结构的Message形式。
/* 读取数据,FLV层级 返回的值为一个FLV数据流,正如RTMP_Write写入一个FLV数据流 1 完成 FLV TAG ==> RTMPPacket,RTMP_Write则相反 2 补全FLV数据流,如加入FLV Header 返回值: 0 表示已经完成读取RTMP流 -1 表示发生了错误 >0 表示实际读取的字节数 */ int RTMP_Read(RTMP *r, char *buf, int size) /* 依次写入FLV文件的一部分。注意:一般不能遗漏FLV文件的任何部分。当然,如果想要忽略一部分数据,那么 可以忽略【FLVHeader+第一个preTagSize】或者任意的【FLVTAG+preTagSize】 实际写入的部分为:FLV TAG,其他的部分会被忽略,其中TAGHeader会被解析到Msg Header,TAGBody为Msg Body。 RTMP_Write将传入的数据封装为RTMPPacket,然后调用RTMP_SendPacket()函数发送。 返回值:成功返回实际写入的字节数。失败返回-1。 */ int RTMP_Write(RTMP *r, const char *buf, int size)
2.5 其他:处理Message以及发送Message
在上面的业务层中,当读取到一个Message之后,会调用RTMP_ClientPacket()来处理读取到的Message,在这个函数内部,根据Message的类型会调用不同的处理函数,也就是下面形为 “Handle***()”的函数。
请注意,这里这些处理函数的命名方式,它的命名说明了这些函数都是框架内部的函数,而不是对外的接口。
如果对rtmp协议感兴趣,可以详细查看这些函数的内容,来印证学习相关的协议内容。
static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize); static int HandleMetadata(RTMP *r, char *body, unsigned int len); static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet); static void HandleAudio(RTMP *r, const RTMPPacket *packet); static void HandleVideo(RTMP *r, const RTMPPacket *packet); static void HandleCtrl(RTMP *r, const RTMPPacket *packet); static void HandleServerBW(RTMP *r, const RTMPPacket *packet); static void HandleClientBW(RTMP *r, const RTMPPacket *packet);
与上面相对应的,当我们想要对rtmp流做一定的修改时,就需要往对方发送Message数据包。具体发送数据包的接口如下,它们都是形如 “Send***()” 或者形如 “RTMP_Send***()” 的函数,当然在librtmp中,还有其他构筑在这些具体发送Message数据包的接口之上的其他接口,当我们遇到时,应该能改轻易分辨出来。
同上,如果对rtmp协议的具体内容感兴趣,可以取查看这些函数的细节。
static int SendConnectPacket(RTMP *r, RTMPPacket *cp); static int SendCheckBW(RTMP *r); static int SendCheckBWResult(RTMP *r, double txn); static int SendDeleteStream(RTMP *r, double dStreamId); static int SendReleaseStream(RTMP *r); static int SendFCPublish(RTMP *r); static int SendPublish(RTMP *r); static int SendFCUnpublish(RTMP *r); static int SendFCSubscribe(RTMP *r, AVal *subscribepath); static int SendPlay(RTMP *r); static int SendBytesReceived(RTMP *r); int RTMP_SendCreateStream(RTMP *r); int RTMP_SendPause(RTMP *r, int DoPause, int iTime) int RTMP_SendSeek(RTMP *r, int iTime); int RTMP_SendServerBW(RTMP *r); int RTMP_SendClientBW(RTMP *r); int RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime);
3.rtmpdump示例
这个示例全方位展示了如何使用librtmp作为客户端使用,如果不知道如何使用librtmp,可以参考这个示例。
4. 参考文章
本文仅是一个提纲类的文档,远远没有将librtmp的各个细节讲解清除,读者可以去参考其他人的相关文章,其中雷神的librtmp相关的系列文章非常详细,是不可多得的好资料,地址如下:https://blog.csdn.net/leixiaohua1020/article/details/15814587。
5. 注释代码
以下我注释的rtmp.h文件:
#ifndef __RTMP_H__ #define __RTMP_H__ /* * Copyright (C) 2005-2008 Team XBMC * http://www.xbmc.org * Copyright (C) 2008-2009 Andrej Stepanchuk * Copyright (C) 2009-2010 Howard Chu * * This file is part of librtmp. * * librtmp is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1, * or (at your option) any later version. * * librtmp is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with librtmp see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/lgpl.html */ #if !defined(NO_CRYPTO) && !defined(CRYPTO) #define CRYPTO #endif #include <errno.h> #include <stdint.h> #include <stddef.h> #include "amf.h" #ifdef __cplusplus extern "C" { #endif //这个库的版本号 #define RTMP_LIB_VERSION 0x020300 /* 2.3 */ //rtmp的特征 FEATURE #define RTMP_FEATURE_HTTP 0x01 #define RTMP_FEATURE_ENC 0x02 #define RTMP_FEATURE_SSL 0x04 #define RTMP_FEATURE_MFP 0x08 /* not yet supported */ #define RTMP_FEATURE_WRITE 0x10 /* publish, not play */ //推流而非播放 #define RTMP_FEATURE_HTTP2 0x20 /* server-side rtmpt */ //服务器端的rtmpt //rtmp及其变种的协议类型,本质为上述FEATURE的组合 #define RTMP_PROTOCOL_UNDEFINED -1 #define RTMP_PROTOCOL_RTMP 0 #define RTMP_PROTOCOL_RTMPE RTMP_FEATURE_ENC #define RTMP_PROTOCOL_RTMPT RTMP_FEATURE_HTTP #define RTMP_PROTOCOL_RTMPS RTMP_FEATURE_SSL #define RTMP_PROTOCOL_RTMPTE (RTMP_FEATURE_HTTP|RTMP_FEATURE_ENC) #define RTMP_PROTOCOL_RTMPTS (RTMP_FEATURE_HTTP|RTMP_FEATURE_SSL) #define RTMP_PROTOCOL_RTMFP RTMP_FEATURE_MFP //默认的max chunk size #define RTMP_DEFAULT_CHUNKSIZE 128 //SocketBuffer层面接收缓冲区的尺寸 /* needs to fit largest number of bytes recv() may return */ #define RTMP_BUFFER_CACHE_SIZE (16*1024) //chunk Stream id所能表达的最大值 #define RTMP_CHANNELS 65600 //rtmp及其变种的协议类型的字符串名称,小写 //还有一个对应的大写的版本,在rtmp.c中定义,不对用户开放 extern const char RTMPProtocolStringsLower[][7]; //默认的Flash版本号字符串描述 extern const AVal RTMP_DefaultFlashVer; //表示ctrl-c中断机制 extern int RTMP_ctrlC; //获取当前时间 uint32_t RTMP_GetTime(void); //Message Type ID #define RTMP_PACKET_TYPE_AUDIO 0x08 //audio message #define RTMP_PACKET_TYPE_VIDEO 0x09 //video message #define RTMP_PACKET_TYPE_INFO 0x12 //command message //chunk header由三部分组成,各个部分的尺寸均可变化 //其最大尺寸时各个部分的字节为:3+11+4 #define RTMP_MAX_HEADER_SIZE 18 //chunk header的第一部分basic header中的fmt取值 #define RTMP_PACKET_SIZE_LARGE 0 #define RTMP_PACKET_SIZE_MEDIUM 1 #define RTMP_PACKET_SIZE_SMALL 2 #define RTMP_PACKET_SIZE_MINIMUM 3 /* 表示一个 raw chunk,原始chunk c_header,c_headerSize:保存chunk header的数据和大小 c_chunk,c_chunkSize:保存chunk data的数据和大小 */ typedef struct RTMPChunk { int c_headerSize; int c_chunkSize; char *c_chunk; char c_header[RTMP_MAX_HEADER_SIZE]; } RTMPChunk; /* 表示一个Message m_headerType :表示m_chunk的类型,即chunk header中的basic header中的fmt m_packetType :表示Message Type ID m_hasAbsTimestamp :表示时间戳是绝对的还是相对的,即chunk type为0时为绝对时间戳,其他类型时为时间戳增量 m_nChannel :表示chunk Stream ID m_nTimeStamp :时间戳 m_nInfoField2 :chunk fmt为0时,header的最后四个字节,即Message Stream ID m_nBodySize :Message的body的尺寸 m_nBytesRead :已经读取到的body的字节数 m_chunk :如果不为NULL,表示用户想要获取chunk,那么在读取Message时,会填充这个字段 m_body :Message的body */ typedef struct RTMPPacket { uint8_t m_headerType; uint8_t m_packetType; uint8_t m_hasAbsTimestamp; /* timestamp absolute or relative? */ int m_nChannel; uint32_t m_nTimeStamp; /* timestamp */ int32_t m_nInfoField2; /* last 4 bytes in a long header */ uint32_t m_nBodySize; uint32_t m_nBytesRead; RTMPChunk *m_chunk; char *m_body; } RTMPPacket; /* RTMPSockBuf:RTMP的传输层的套接字及其缓存 表示一个TCP套接字连接,以及其读取缓存 sb_socket :Socket套接字 sb_size :buffer中未处理的字节数量,即缓冲数据的大小 sb_start :指向buffer中需要处理的字节,即指向缓冲数据 sb_buf :数据读取缓冲区 sb_timedout :套接字是否中断 sb_ssl :SSL相关数据 */ typedef struct RTMPSockBuf { int sb_socket; int sb_size; /* number of unprocessed bytes in buffer */ char *sb_start; /* pointer into sb_pBuffer of next byte to process */ char sb_buf[RTMP_BUFFER_CACHE_SIZE]; /* data read from socket */ int sb_timedout; void *sb_ssl; } RTMPSockBuf; //将全部字段置空(缓冲区仍在) void RTMPPacket_Reset(RTMPPacket *p); //打印packet void RTMPPacket_Dump(RTMPPacket *p); //为p分配缓冲区,其中包括固定大小的header,nSize大小的body int RTMPPacket_Alloc(RTMPPacket *p, int nSize); //释放缓冲区 void RTMPPacket_Free(RTMPPacket *p); //packet是否完备 #define RTMPPacket_IsReady(a) ((a)->m_nBytesRead == (a)->m_nBodySize) /* RTMP的连接参数,即要建立RTMP连接所需的参数集 注意:这是由客户端的用户提供的 这个结构体里的字段的含义和rtmpdump中的选项联系紧密。可以查看rtmpdump中选项的含义来帮助我们理解它们。 */ typedef struct RTMP_LNK { AVal hostname; //要连接的服务器的主机名 AVal sockshost; //代理主机名称 /* parsed from URL */ AVal playpath0; //从URL解析出来的playpath /* passed in explicitly */ AVal playpath; //显式指定的playpath AVal tcUrl; //要连接的目标流的URL。默认值为:rtmp[e]://host[:port]/app/playpath ,由解析出的各个字段值拼接而成。 AVal swfUrl; //媒体的SWF播放器的URL,默认不设置任何值 AVal pageUrl; //嵌入网页的媒体的URL,默认不设置任何值 AVal app; //要连接的服务器上的应用程序 AVal auth; //验证字符串,它会追加到Connect Message的末尾。使用这个选项, //实际上将会追加一个布尔值TRUE然后才是这个验证字符串。只有某些特殊的服务器需要,而且已经被废弃。 AVal flashVer; //用于运行SWF播放器的Flash插件的版本。默认为“LUX 10,0,32,18" AVal subscribepath; //要访问的流的名称 AVal token; //SecureToken Response中要使用的key。当服务器需要一个SecureToken验证时使用 AMFObject extras; int edepth; int seekTime; //访问媒体时的偏移时间 int stopTime; //访问媒体的停止时间 #define RTMP_LF_AUTH 0x0001 /* using auth param */ //是否使用验证参数 #define RTMP_LF_LIVE 0x0002 /* stream is live */ //请求的流是否为实时流 #define RTMP_LF_SWFV 0x0004 /* do SWF verification */ //是否要执行SWF验证 #define RTMP_LF_PLST 0x0008 /* send playlist before play */ //是否在发送play之间发送playlist #define RTMP_LF_BUFX 0x0010 /* toggle stream on BufferEmpty msg */ //是否在BufferEmpty msg时toggle stream #define RTMP_LF_FTCU 0x0020 /* free tcUrl on close */ //close时是否释放tcUrl int lFlags; //复合标识 int swfAge; //指定缓存的SWF信息的有效天数,超过这个天数后,将重新检查 int protocol; //服务器的rtmp协议类型 /* connection timeout in seconds */ int timeout; //连接timeout的时间值 unsigned short socksport; //代理主机的端口 unsigned short port; //服务器的端口 //加密相关的字段 #ifdef CRYPTO #define RTMP_SWF_HASHLEN 32 void *dh; /* for encryption */ void *rc4keyIn; void *rc4keyOut; uint32_t SWFSize; uint8_t SWFHash[RTMP_SWF_HASHLEN]; char SWFVerificationResponse[RTMP_SWF_HASHLEN+10]; #endif } RTMP_LNK; //RTMP业务层,即建立rtmp流之后对rtmp流做必要操作所需的参数 //必要操作如:seek操作,resume操作 /* state for read() wrapper */ typedef struct RTMP_READ { char *buf; //指向读取缓冲区 char *bufpos; //指向未处理数据的指针 unsigned int buflen; //未处理数据的大小 uint32_t timestamp; //RTMP流的当前时间戳 uint8_t dataType; //RTMP流的数据类型,即是否包含音频数据和视频数据 0x04为音频 0x01为视频,使用的是flv的表示法 uint8_t flags; //解析flag,包含以下几个值 #define RTMP_READ_HEADER 0x01 //表示是否在当前rtmp流的开头中插入flv header,默认不会设置这个状态,实际开始读取时插入对应的flv header,然后设置它,表示已添加flv header #define RTMP_READ_RESUME 0x02 //表示是否要进行resume #define RTMP_READ_NO_IGNORE 0x04 // #define RTMP_READ_GOTKF 0x08 //表示是否完成了resume #define RTMP_READ_GOTFLVK 0x10 // #define RTMP_READ_SEEKING 0x20 //表示是否要执行seek操作 int8_t status; //读取的当前状态,表示当前的流的分析结果,为以下四个取值,为0表示正常 #define RTMP_READ_COMPLETE -3 //Close或者Stop状态,表示读取完成 #define RTMP_READ_ERROR -2 //致命错误 #define RTMP_READ_EOF -1 //EOF #define RTMP_READ_IGNORE 0 //可忽略错误 /* if bResume == TRUE */ //resume时需要指定的字段,用于帮助流定义resume的位置 uint8_t initialFrameType; //定位的帧的类型,即是视频帧还是音频帧 uint32_t nResumeTS; //定位的帧的时间戳 char *metaHeader; //要resume的流的metedata数据 char *initialFrame; //定位的帧的data uint32_t nMetaHeaderSize; //要resume的流的metadata数据的尺寸 uint32_t nInitialFrameSize; //定位的帧的data length uint32_t nIgnoredFrameCounter; uint32_t nIgnoredFlvFrameCounter; } RTMP_READ; //method:方法 //表示RTMP的方法或函数 typedef struct RTMP_METHOD { AVal name; int num; } RTMP_METHOD; //表示一个RTMP流,用于保存这个RTMP流的相关参数 typedef struct RTMP { int m_inChunkSize; //接收方向的max chunk size int m_outChunkSize; int m_nBWCheckCounter; int m_nBytesIn; //接受到的字节的总数量 int m_nBytesInSent; //发送的字节的总数量 int m_nBufferMS; int m_stream_id; /* returned in _result from createStream */ //Message Stream ID int m_mediaChannel; //当前media使用的chunk Stream id uint32_t m_mediaStamp; //当前media的时间戳 uint32_t m_pauseStamp; int m_pausing; int m_nServerBW; //window size int m_nClientBW; //Set Peer Bandwidth Message中的window size uint8_t m_nClientBW2; //Set Peer Bandwidth Message中的limit type uint8_t m_bPlaying; //当前是否play uint8_t m_bSendEncoding; uint8_t m_bSendCounter; int m_numInvokes; //记录RTMP发起的invoke的数量 int m_numCalls; //m_methodCalls中的数量 /* remote method calls queue */ RTMP_METHOD *m_methodCalls; //request列表 RTMPPacket *m_vecChannelsIn[RTMP_CHANNELS]; //输入的chunk Stream对应的最后一个packet RTMPPacket *m_vecChannelsOut[RTMP_CHANNELS]; //输出的chunk stream对应的最后一个packet /* abs timestamp of last packet */ int m_channelTimestamp[RTMP_CHANNELS]; //最后一个packet对应的绝对时间戳 /* audioCodecs for the connect packet */ double m_fAudioCodecs; //Connect msg中的音频编解码 /* videoCodecs for the connect packet */ double m_fVideoCodecs; //Connect msg中的视频编解码 /* AMF0 or AMF3 */ double m_fEncoding; //使用AMF0还是AMF3 /* duration of stream in seconds */ double m_fDuration; //当前流的长度,单位秒 /* RTMPT stuff */ //以下是RTMPT相关的成员变量: int m_msgCounter; // int m_polling; // int m_resplen; //HTTP Response的body长度,表示是否读取到了HTTP Response,但数据保存在SB中 int m_unackd; //表示未应答的HTTP request数量(一般,没一个request必有一个response) AVal m_clientID; //底层为HTTP时,用于表示客户端ID RTMP_READ m_read; //RTMP层面的读 RTMPPacket m_write; //RTMP层面write时的临时msg对象 RTMPSockBuf m_sb; //套接字层面的读写 RTMP_LNK Link; //RTMP连接的参数 } RTMP; //解析RTMP地址 int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, AVal *playpath, AVal *app); //从RTMP URL中解析playpath void RTMP_ParsePlaypath(AVal *in, AVal *out); //设置缓冲的时长,单位:毫秒 void RTMP_SetBufferMS(RTMP *r, int size); //发送“设置缓冲时长”的控制包 void RTMP_UpdateBufferMS(RTMP *r); //设置RTMP的相关属性 int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg); //设置url int RTMP_SetupURL(RTMP *r, char *url); //设置流 void RTMP_SetupStream(RTMP *r, int protocol, //协议 AVal *hostname, //hostname unsigned int port, //port AVal *sockshost, AVal *playpath, AVal *tcUrl, AVal *swfUrl, AVal *pageUrl, AVal *app, AVal *auth, AVal *swfSHA256Hash, uint32_t swfSize, AVal *flashVer, AVal *subscribepath, int dStart, int dStop, int bLiveStream, long int timeout); //客户端与服务器建立连接,并进行Connect int RTMP_Connect(RTMP *r, RTMPPacket *cp); struct sockaddr; int RTMP_Connect0(RTMP *r, struct sockaddr *svc); int RTMP_Connect1(RTMP *r, RTMPPacket *cp); //服务端处理handshake,成功返回值大于0 int RTMP_Serve(RTMP *r); //RTMP读取到一个packet,并不保证一定读取到完整的packet int RTMP_ReadPacket(RTMP *r, RTMPPacket *packet); //使用RTMP发送packet,queue表示是否按照队列发送 int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue); //RTMP发送一个chunk int RTMP_SendChunk(RTMP *r, RTMPChunk *chunk); //RTMP是否处于连接状态 int RTMP_IsConnected(RTMP *r); //返回RTMP关联的套接字 int RTMP_Socket(RTMP *r); //RTMP是否中断 int RTMP_IsTimedout(RTMP *r); //获得RTMP当前流的长度 double RTMP_GetDuration(RTMP *r); //暂停或者恢复流 int RTMP_ToggleStream(RTMP *r); //连接到url指定的流,返回TRUE和FLASE int RTMP_ConnectStream(RTMP *r, int seekTime); //重新连接流,即delete Stream之后再次Connect Stream,且同步等待到流开始 int RTMP_ReconnectStream(RTMP *r, int seekTime); //停止流,或者删除流 void RTMP_DeleteStream(RTMP *r); //获取一个媒体packet,即音频帧或者视频帧(在RTMP_ReadPacket函数之上实现) int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet); //客户端处理packet int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet); //初始化RTMP,将RTMP各个字段设置为默认值 void RTMP_Init(RTMP *r); //关闭这个RTMP,如果当前处于连接状态,则会关闭连接;然后释放RTMP相关的内容 void RTMP_Close(RTMP *r); //分配一个RTMP //其操作仅仅是分配一块RTMP大小的内存而已,RTMP也可以在栈上分配 RTMP *RTMP_Alloc(void); //释放这块RTMP大小的内存 void RTMP_Free(RTMP *r); //为RTMP Link添加写属性 void RTMP_EnableWrite(RTMP *r); //返回RTMP库的版本号 int RTMP_LibVersion(void); //RTMP流程被打断 //本质为设置全局变量RTMP_ctrlC为true void RTMP_UserInterrupt(void); /* user typed Ctrl-C */ int RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime); /* caller probably doesn't know current timestamp, should * just use RTMP_Pause instead */ int RTMP_SendPause(RTMP *r, int DoPause, int dTime); int RTMP_Pause(RTMP *r, int DoPause); int RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, AMFObjectProperty * p); //TCP层面的操作:读、写、关闭 //在TCP层面读取,返回读取到的字节数 int RTMPSockBuf_Fill(RTMPSockBuf *sb); //在TCP层面写入,返回写入的返回值 int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len); //关闭套接字,返回关闭的返回值 int RTMPSockBuf_Close(RTMPSockBuf *sb); // int RTMP_SendCreateStream(RTMP *r); int RTMP_SendSeek(RTMP *r, int dTime); int RTMP_SendServerBW(RTMP *r); int RTMP_SendClientBW(RTMP *r); //丢弃第i个request //freeit表示是否释放这个request void RTMP_DropRequest(RTMP *r, int i, int freeit); //FLV层面 int RTMP_Read(RTMP *r, char *buf, int size); int RTMP_Write(RTMP *r, const char *buf, int size); /* hashswf.c */ int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age); #ifdef __cplusplus }; #endif #endif
-
-
编译Android平台libRTMP库
2021-03-22 11:38:00操作系统: Mac OSXNDK: android-ndk-r10e-darwin-x86_64编译目标: librtmp.a librtmp.so简介Android 官方提供了三种编译方式,分别是 prebuild 工具,standalone toolchain 工具,ndk-build 工具。prebuild 工具,是... -
使用RTMPdump(libRTMP)直播来自v4l2的摄像头数据
2018-04-24 11:15:03RTMP是Real Time Messaging Protocol(实时消息传输协议),...关于RTMPdump的使用,可以参考博客 linux系统RTMPdump(libRTMP) 通过RTMP 发布H264数据 linux系统RTMPdump(libRTMP) 通过RTMP 发布FLV数据在进行R... -
LibRtmp编译并导入Android Studio
2021-05-16 12:32:33title: LibRTMP_Demodate: 2017-06-13 15:40:15tags: 学习categories: android[TOC]LibRtmp编译并导入Android Studio简介做了好久的推流项目,但是没有接触过底层知识,所以只是相当于SDK的使用者。在工作不忙的时候... -
VS2022编译librtmp制作rtmp.lib用于安装windows版本的python-librtmp 0.3.0
2022-04-12 20:10:00python librtmp是一个RTMP客户端库。它使用实现 由librtmp通过cffi提供。 如果你想在你的python环境安装python-librtmp 0.3.0,可以参考此博文。 依赖性 Python,至少2.6或3.3版。 一个c编译器,能够生成Python... -
librtmp分析(发送数据包处理)
2021-05-09 20:57:04rtmp协议中的message的发送涉及有message 分chunk、base header长度的变化、message header长度的变化,只查看文档比较难理解,分析一下librtmp库中的int RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue)... -
【Android音视频开发】【027】Linux下编译librtmp
2021-08-08 18:52:21什么是librtmp 下载源码 安装依赖库 编写编译脚本 编译静态库 编译动态库 -
向ffmpeg中添加librtmp库支持
2022-03-24 18:58:341. 下载ffmpeg-checkout-2010-04-14, rtmpdump-2.2c; openssl-0.9.8k, 2. 编译过程注意看rtmpdump中的README文件,里边包括了如何编译... require librtmp librtmp/rtmp.h RTMP_Init -lrtmp 修改为:enabled librtmp -
使用librtmp进行H264与AAC直播
2021-05-05 06:49:24一般情况双声道 44100 采样下,该值是 0x1210 3.librtmp 的使用 /*分配与初始化*/ rtmp = RTMP_Alloc(); RTMP_Init(rtmp); /*设置URL*/ if (RTMP_SetupURL(rtmp,rtmp_url) == FALSE) { log(LOG_ERR,"RTMP_SetupURL... -
linux下基于libRTMP的接收流媒体的程序
2021-05-17 11:34:04使用librtmp接收RTMP流的函数执行流程图如下图: 流程图中关键函数的作用如下所列:InitSockets():初始化SocketRTMP_Alloc():为结构体“RTMP”分配内存。RTMP_Init():初始化结构体“RTMP”中的成员变量。RTMP_... -
流媒体之RTMP——librtmp推流测试
2019-10-09 16:38:50文章目录一:LibRTMP推流测试二:时间控制三:FFMPEG从MP4文件解析出H264四:LibRTMP的使用4.1 发送Metadata4.2 发送视频4.2.1 发送视频信息包4.2.2 发送视频数据包4.3 发送音频4.3.1 发送音频信息包4.3.2 发送音频... -
流媒体-RTMP协议-librtmp库学习(二)
2021-01-19 11:30:10文章目录librtmp 库相关结构体RTMP 结构体RTMP_LNK 结构体RTMPPacket 结构体:描述实时消息协议的分块AMF(Action Message Format): 动作消息格式AVal结构体:自定义字符串推流InitSockets() 初始化SocketRTMP_Alloc... -
Android移植librtmp
2017-01-12 15:30:48一、前言 为了让android能够使用librtmp,我们需要下载它的源码并使用交叉编译工具编译成可以供android使用的库...1、从ndk中提出一个交叉编译工具链,并设置环境变量,供我们编译使用。 2、因为librtmp需要依赖ssl -
rtmp推流超时时间不起作用 linux srs_librtmp srs_rtmp_set_timeout setsockopt 设置超时时间 失败 返回...
2021-11-04 16:26:59最近在调试rtmp推流 用的是srs_librtmp.cpp这个开源库 调试过程中发现 如果正常推流过程中,突然rtmp服务器ping不通的话 会导致 程序卡死在 srs_h264_write_raw_frames 这个函数中 ,跟踪到最后发现是 在这个函数 ... -
使用Librtmp进行的简单推流
2020-12-31 17:25:39Librtmp推流的流程概括、时间戳处理和一些代码总结 -
Android使用libRtmp直播推流
2021-06-04 13:07:58初始化rtmp//分配空间RTMP *rtmp = ...//设置推流URLRTMP_SetupURL(rtmp, url);//设置可写状态RTMP_EnableWrite(rtmp);//链接服务器RTMP_Connect(rtmp, NULL);//链接流RTMP_ConnectStream(rtmp, 0);//循环推流(AAC... -
使用librtmp推h264、aac实时流
2022-03-05 23:49:40librtmp可以用于推rtmp流,有时候我们需要将采集的摄像头或桌面的视频数据以及麦克风的音频数据推流出去,这时候就需要使用librtmp的推流功能了,其推流流程比较简单,只是一些细节需要注意即可。 -
使用librtmp接收数据时要注意的问题
2019-10-28 11:34:14(这篇博文的完整代码在我的另一篇博文《使用Librtmp接收H264 + AAC》) librtmp是一个RTMP的开源库,很多地方用它来做推流、拉流。它是RTMPDump开源软件里的一部分,librtmp的下载地址:... -
librtmp发送flv tag扩展时间戳
2017-11-30 20:46:55一 librtmp 存在一个bug当时间戳大于0xffffff也就是4.64小时的时候,会和FMS掉连接,至于修复方法网上比较多,我就不多说了。可以参考这个:http://blog.csdn.net/jiang_shikun/article/details/46047417 二 ... -
使用librtmp推流/拉流
2018-01-22 11:08:36#include "librtmp/rtmp_sys.h" #include "librtmp/log.h" #pragma comment(lib, "librtmp.lib") #pragma comment(lib, "WS2_32.lib") WORD version; WSADATA wsaData; version = MAKEWORD(1, 1); WSAStar -
使用librtmp实现本地推流
2019-08-13 15:48:07并通过librtmp进行测试。 1.0 背景 客户需要我们提供rtmp推流的源代码,然后他们DVR的供应商会负责移植到盒子中。这个demo演示了如何用c实现rtmp推流。 2.0 安装配置流服务器 下面详细介绍如何在ubuntu14.04上安装... -
流媒体之RTMP——librtmp2.4编译
2019-10-09 16:27:46librtmp版本:librtmp2.4; 编译步骤: 新建VS静态库项目; 将librtmp的源码加入工程; 增预处理加宏定义来忽略一些废弃函数导致的错误报告:_CRT_SECURE_NO_WARNINGS; _WINSOCK_DEPRECATED_NO_WARNI... -
编译librtmp
2018-09-13 11:45:46将第一步和第二步中的.lib文件复制到\Librtmp\Librtmp\lib文件夹中。 d.设置库引用, 库名称 最终项目样子 编译完成!! ex: 1、修改rtmp_sys.h... -
librtmp发送阻塞
2018-03-20 09:56:55librtmp发送阻塞 我的解决方法是:直接用RTMP_IsConnected()在推流之前检测网络是否断开,流是否断开,如果发现断开,马上启动重连RTMP。这样可以避免在路由器不稳定的情况下,出现阻塞现象。 上面的解决方法... -
基于librtmp,进行网络推流(264和flv)
2020-01-19 11:53:00librtmp 这个开源库本身就是基于flv格式的数据进行传输,所以flv 上传会比较简单, 相关介绍可以看这个链接 https://blog.csdn.net/leixiaohua1020/article/details/14229543 2、rtmp 传输h.264视频的相关知识 ... -
libRTMP文档
2018-07-31 15:46:00原文地址:http://rtmpdump.mplayerhq.hu/librtmp.3.html git clone git://git.ffmpeg.org/rtmpdump 名称 ...librtmp − RTMPDump Real-Time Messaging Protocol API 库 RT...