一, RMTP协议的命令的

1, handshake

客户端与服务器的RTMP握手的的流程

①, 客户端发送 C0+C1 规则是

消息头一共是9个字节分别是:

cid 标志是什么命令(一个字节) 时间戳timestamp(四个字节) 扩展字节(四个字节)
一个字节标志是什么游戏 0X03 表示发送C0+C1 四个字节时间戳 ::time(NULL) 四个字节的 0X00

后面在加1537个字节的随机数

代码

 // [1+1536]char* c0c1;// [1+1536+1536]char* s0s1s2;// [1536]char* c2;c0c1 = new char[1537];srs_random_generate(c0c1, 1537);// plain text required.SrsStream stream;if ((ret = stream.initialize(c0c1, 9)) != ERROR_SUCCESS) {return ret;}stream.write_1bytes(0x03);stream.write_4bytes((int32_t)::time(NULL));stream.write_4bytes(0x00);

举例

03 61 50 b0 a8 00 00 00 00 75 da 5b 1b 46 d4 74 .aP......u.[.F.t
......
1e 55 4e 8c c2 7b 12 b8 ce 33 4e 75 be 96 36 88 .UN..{...3Nu..6.
eb                                              .

②,服务器端先回复 S0+S1+S2一个字节cid =0X03字段

一共是3073个字节

1 + 1536+1536 = 3073

其中1536 是随机数

③, 客户端发送C2标志

客户端发送C2完成就完成RTMP的握手流程

C2规则发送

cid标志位(1byte) 时间戳(4byte) S0+S1+S2+时间戳(4byte)
标志什么消息 客户端的时间戳

代码

 int create_c2(){int ret = ERROR_SUCCESS;if (c2) {return ret;}c2 = new char[1536];srs_random_generate(c2, 1536);// timeSrsStream stream;if ((ret = stream.initialize(c2, 8)) != ERROR_SUCCESS) {return ret;}stream.write_4bytes((int32_t)::time(NULL));// c2 time2 copy from s1  这边就是把S0+S1+S2的时间戳赋值过来的的4byteif (s0s1s2) {stream.write_bytes(s0s1s2 + 1, 4);}return ret;}

例子


00 00 00 00 00 00 00 00 36 72 72 32 6f 77 70 2d ........6rr2owp-
....
6e 73 2d 73 73 6c 32 72 36 65 65 69 6c 65 65 73 ns-ssl2r6eeilees

下载RTMP握手流程完成了 下面就要创建流推流

2,RTMP推流命令

typedef struct RTMPChunk {int c_headerSize;int c_chunkSize;char *c_chunk;char c_header[RTMP_MAX_HEADER_SIZE];
} RTMPChunk;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;

RTMP header 计算


int
RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue) {const RTMPPacket *prevPacket;uint32_t last = 0;int nSize;int hSize, cSize;char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;uint32_t t;char *buffer, *tbuf = NULL, *toff = NULL;int nChunkSize;int tlen;if (packet->m_nChannel >= r->m_channelsAllocatedOut) {int n = packet->m_nChannel + 10;RTMPPacket **packets = realloc(r->m_vecChannelsOut, sizeof(RTMPPacket *) * n);if (!packets) {free(r->m_vecChannelsOut);r->m_vecChannelsOut = NULL;r->m_channelsAllocatedOut = 0;return FALSE;}r->m_vecChannelsOut = packets;memset(r->m_vecChannelsOut + r->m_channelsAllocatedOut, 0,sizeof(RTMPPacket *) * (n - r->m_channelsAllocatedOut));r->m_channelsAllocatedOut = n;}prevPacket = r->m_vecChannelsOut[packet->m_nChannel];if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE){/* compress a bit by using the prev packet's attributes */if (prevPacket->m_nBodySize == packet->m_nBodySize && prevPacket->m_packetType == packet->m_packetType && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM){packet->m_headerType = RTMP_PACKET_SIZE_SMALL;}if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp && packet->m_headerType == RTMP_PACKET_SIZE_SMALL){packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;}last = prevPacket->m_nTimeStamp;}// headerType --> 1 4 6if (packet->m_headerType > 3)    /* sanity */{RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",(unsigned char) packet->m_headerType);return FALSE;}nSize = packetSize[packet->m_headerType];hSize = nSize;cSize = 0;t = packet->m_nTimeStamp - last;if (packet->m_body) {header = packet->m_body - nSize;hend = packet->m_body;} else {header = hbuf + 6;hend = hbuf + sizeof(hbuf);}if (packet->m_nChannel > 319){cSize = 2;}else if (packet->m_nChannel > 63){cSize = 1;}if (cSize){header -= cSize;hSize += cSize;}if (t >= 0xffffff) {header -= 4;hSize += 4;RTMP_Log(RTMP_LOGWARNING, "Larger timestamp than 24-bit: 0x%x", t);}hptr = header;c = packet->m_headerType << 6;switch (cSize) {case 0:c |= packet->m_nChannel;break;case 1:break;case 2:c |= 1;break;}*hptr++ = c;if (cSize) {int tmp = packet->m_nChannel - 64;*hptr++ = tmp & 0xff;if (cSize == 2)*hptr++ = tmp >> 8;}//时间戳if (nSize > 1){hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);}if (nSize > 4){hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);*hptr++ = packet->m_packetType;}if (nSize > 8)hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);if (t >= 0xffffff)hptr = AMF_EncodeInt32(hptr, hend, t);nSize = packet->m_nBodySize;buffer = packet->m_body;nChunkSize = r->m_outChunkSize;RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,nSize);/* send all chunks in one HTTP request */if (r->Link.protocol & RTMP_FEATURE_HTTP) {int chunks = (nSize + nChunkSize - 1) / nChunkSize;if (chunks > 1) {tlen = chunks * (cSize + 1) + nSize + hSize;tbuf = malloc(tlen);if (!tbuf)return FALSE;toff = tbuf;}}while (nSize + hSize) {int wrote;if (nSize < nChunkSize)nChunkSize = nSize;RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *) header, hSize);RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *) buffer, nChunkSize);if (tbuf) {memcpy(toff, header, nChunkSize + hSize);toff += nChunkSize + hSize;} else {wrote = WriteN(r, header, nChunkSize + hSize);if (!wrote)return FALSE;}nSize -= nChunkSize;buffer += nChunkSize;hSize = 0;if (nSize > 0) {header = buffer - 1;hSize = 1;if (cSize) {header -= cSize;hSize += cSize;}if (t >= 0xffffff) {header -= 4;hSize += 4;}*header = (0xc0 | c);if (cSize) {int tmp = packet->m_nChannel - 64;header[1] = tmp & 0xff;if (cSize == 2)header[2] = tmp >> 8;}if (t >= 0xffffff) {char *extendedTimestamp = header + 1 + cSize;AMF_EncodeInt32(extendedTimestamp, extendedTimestamp + 4, t);}}}if (tbuf) {int wrote = WriteN(r, tbuf, toff - tbuf);free(tbuf);tbuf = NULL;if (!wrote)return FALSE;}/* we invoked a remote method */if (packet->m_packetType == RTMP_PACKET_TYPE_INVOKE) {AVal method;char *ptr;ptr = packet->m_body + 1;AMF_DecodeString(ptr, &method);RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);/* keep it in call queue till result arrives */if (queue){int txn;ptr += 3 + method.av_len;txn = (int) AMF_DecodeNumber(ptr);AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);}}if (!r->m_vecChannelsOut[packet->m_nChannel])r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));return TRUE;
}

messgeheader

m_headerType:代表头节点数据有多大了 {1btye}
channel :有可能1byte和2byte
时间戳:3byte也有可能是6byte

①, connect(‘流的名称’)

协议 CID 0X03

|cid(1byte)|timestamp一般4byte有可能8字节|||

参数

app flashVer swfUrl tcUrl fpad capabilities audioCodecs videoCodecs videoFunction pageUrl objectEncoding
string string string string bool int int int int string int
流的名称 版本 rtmp:/ip/live/app

②, Window Acknowledgemnt Size (滑动窗口的大小)

③,Set Chunk Size (设置RTMP的Chunk最大值)

④,releaseStream(‘流的名称’)

⑤,FCPublish(‘流的名称’)

⑥, createStream()

⑦,publish(‘test’)

⑧,Video Data

⑨,Audio Data

3, RTMP哪流命令

①, connect(‘live’) C->S

②, onBWDone() S->C

③,_checkbw() C->S

④, _result() S->C

⑤, getStreamLength() C->S

⑥, play(‘test’) C->S

⑦,Set buffer Length 1, 3000ms C->S

⑧,Stream Begin 1 S->C

⑨,|RtmpSampleAccess() S->C

⑩, onStatus(‘NetStream.Data.Start’)

⑪, Video Data

RTMP协议命令的流程详解相关推荐

  1. 域名注册、域名实名认证、域名解析流程详解

    1.域名注册流程详解 首先登陆阿里云网站 www.aliyun.com 点击产品,选择域名注册(左下角蓝色字体) 然后来到此页面 在输入框中填入你想要注册的域名产看是否已经被注册 如:shiyansh ...

  2. MySQL系列---架构与SQL执行流程详解

    文章目录 1. 背景 2. 架构体系 2.1 架构图 2.2 模块详解 2.3 架构分层 3. 查询SQL语句执行流程 3.1 连接 3.1.1 MySQL支持的通信协议 3.1.2 通信方式 3.2 ...

  3. IP协议相关技术终极详解

    IP协议相关技术终极详解 DNS域名解析协议 概述 域名的层级关系 域名的解析流程 ARP地址解析协议 概述 为什么需要ARP协议? ARP协议是属于哪一层呢? ARP协议和DNS协议的区别 ARP协 ...

  4. jenkins插件调用job_Jenkins迁移job插件Job Import Plugin流程详解

    Jenkins迁移job插件Job Import Plugin流程详解 由于又开了新机器所以又要重新布置Jenkins从老项目拷贝过来,发现Job Import Plugin 这个插件更新了,和以前的 ...

  5. ARP协议及ARP欺骗详解

    ARP协议及ARP欺骗详解 地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议.主机发送信息时将包含目标IP地址的ARP ...

  6. U-Boot启动流程详解

    参考:U-Boot顶层目录链接脚本文件(u-boot.lds)介绍 作者:一只青木呀 发布时间: 2020-10-23 13:52:23 网址:https://blog.csdn.net/weixin ...

  7. 推荐系统整体架构及算法流程详解

    省时查报告-专业.及时.全面的行研报告库 省时查方案-专业.及时.全面的营销策划方案库 知识图谱在美团推荐场景中的应用实践 搜索场景下的智能实体推荐 机器学习在B站推荐系统中的应用实践 小红书推荐系统 ...

  8. Linux 下 TC 命令原理及详解<一>

    文章目录 1 前言 2 相关概念 3 使用TC 4 创建HTB队列 5 为根队列创建相应的类别 6 为各个类别设置过滤器 7 复杂的实例 Linux 下 TC 命令原理及详解<一> Lin ...

  9. Springboot启动流程详解

    SpringMVC请求流程详解 SpringMVC框架是一个基于请求驱动的Web框架,并且使用了'前端控制器'模型来进行设计,再根据'请求映射规则'分发给相应的页面控制器进行处理. (一)整体流程 每 ...

最新文章

  1. RunLoop 浅析
  2. Servlet其实是单例多线程
  3. Gym 102798A(思维) acm寒假集训日记21/12/31or22/1/1
  4. 拓端tecdat|R语言用于线性回归的稳健方差估计
  5. python采集数据搭建小说网站_Python制作爬虫采集小说
  6. python持久层框架_python网络爬虫——scrapy框架持久化存储
  7. C++ Primer 5th Edition(英文版)kindle.mobi
  8. qt界面之comboBox控件的三种基本用法
  9. Rust语言教程(2) - 从熟悉的部分开始
  10. swiper设置autoplay不起作用
  11. 模电笔记 差分放大器1
  12. 微软VS硬伤 - 未能起用约束集
  13. DTOJ 4745. 进制转换
  14. 湖仓一体(Lakehouse)是什么?
  15. windows+MAC系统使用-快捷键
  16. 读书有多重要--即可以朝九晚五,又可以浪迹天涯
  17. java/php/net/pythont员工管理系统设计与实现设计
  18. VS2003 R6025 RUNTIME ERROR 问题
  19. vue element-ui导出表格的功能,csv文件格式
  20. executeBatch报语法错误,分析是inert into的语句后面加了;

热门文章

  1. OpenCV学习笔记~VS code1.25.0.0环境中配置opencv
  2. linux kylin使用手册,优麒麟Ubuntu Kylin 18.10中的生物识别管理工具,附使用方法
  3. 爱尔兰博士后招聘|利默里克大学-广告学
  4. 话说当下朱仝对众人 水浒
  5. 通过jar文件运行软件
  6. 信用卡PK信用贷款,那个更划算?
  7. arduino yun 京东_收购域名、注册商标,京东的“云布局”终于铺开了!
  8. 如何从 Power BI 示例中获取数据以供练习
  9. 交通交警行业相关名词解释说明,主要包含人、车、路三大块的内容
  10. Python奇妙之旅-出发吧