C++ rtmp livestream 流媒体

海阔天空 张翼飞翔

我的学习笔记。--我喜欢这里,因为这里安静,无广告骚扰。
随笔 - 82, 文章 - 2, 评论 - 126, 引用 - 0
数据加载中……

RTMP协议分析 一、RTMP包头

原创
RTMP协议 封包 参考Red5
RTMP协议封包 由一个包头和一个包体组成,包头可以是4种长度的任意一种:12, 8, 4,  1 byte(s).完整的RTMP包头应该是12bytes,包含了时间戳,Head_Type,AMFSize,AMFType,StreamID信息, 8字节的包头只纪录了时间戳,Head_Type,AMFSize,AMFType, 4个字节的包头记录了时间戳,Head_Type。1个字节的包头只记录了Head_Type 。包体最大长度默认为128字节,通过chunkSize可改变包体最大长度,通常当一段AFM数据超过128字节后,超过128的部分就放到了其他的RTMP封包中,包头为一个字节.
完整的RTMP包头有12字节,由下面5个部分组成:
用途大小(Byte)含义
Head_Type1包头
TIMER3时间戳
AMFSize3数据大小
AMFType1数据类型
StreamID4流ID

一、Head_Type - 包头类型
Head_Type占用RTMP包的第一个字节,这个字节里面记录了包的类型和包的ChannelID。Head_Type字节的前两个Bit决定了包头的长度.它可以用掩码0xC0进行"与"计算:
Head_Type的前两个Bit和长度对应关系:
Bits Header Length
00 12 bytes
01 8 bytes
10 4 bytes
11 1 byte

Head_Type的后面6个Bit和StreamID决定了ChannelID。  StreamID和ChannelID对应关系:StreamID=(ChannelID-4)/5+1 参考red5
ChannelID用途
02Ping 和ByteRead通道
03Invoke通道 我们的connect() publish()和自字写的NetConnection.Call() 数据都是在这个通道的
04Audio和Vidio通道
05 06 07服务器保留,经观察FMS2用这些Channel也用来发送音频或视频数据

例如在rtmp包的数据中里面,发现被插入了一个0xC2,这个就是一字节的包头,并且channelID=2.

二、TiMMER - 时间戳

时间戳占用RTMP包头的第2、3、4 三个字节。RTMP时间戳可分为绝对时间戳和相对时间戳,纪录的是音视频的时间信息。相对时间戳指的是二个RTMP包之间的时间间隔,单位毫秒。而绝对时间戳指的是当前封包发送的时刻,单位也是毫秒。对于音视频的播放,时间戳非常关键,因为音视频的播放同步是由时间戳来控制的,如果你的视频出现卡顿,音视频不同步,延时越来越大,很可能就是你的时间戳不准导致的。
fms对于同一个流,发布(publish)的时间戳和播放(play)的时间戳是有区别的
publish时间戳,采用相对时间戳,时间戳值等于当前媒体包的绝对时间戳与上个媒体包的绝对时间戳之间的差距,也就是说音视频时间戳在一个时间轴上面.单位毫秒。
play时间戳,也是相对时间戳,时间戳值等于当前媒体包的绝对时间戳与上个同类型媒体包的绝对时间戳之间的差距, 注意这里跟上面不同的是强调“同类型的媒体包”。也就是说音视频时间戳分别采用单独的时间轴,单位毫秒。
flv格式文件时间戳,绝对时间戳,时间戳长度3个字节。超过0xFFFFFF后时间戳值等于TimeStamp & 0xFFFFFF。
flv格式文件影片总时间长度保存在onMetaData的duration属性里面,长度为8个字节,是一个double类型。


三、AMFSize - 数据大小
AMFSize占三个字节,这个长度是AMF长度,可超过RTMP包的最大长度128字节。如果超过了128字节,那么由多个后续RTMP封包组合,每个后续RTMP封包的头只占一个字节。一般就是以0xC?开头。1个字节的包头表示这个包的时间戳、数据大小、数据类型、流ID都和上一个相同ChannelID的RTMP包完全一样。

四、AMFType - 数据类型
AMFType是RTMP包里面的数据的类型,占用1个字节。例如音频包的类型为8,视频包的类型为9。下面列出的是常用的数据类型:

0×01 Chunk Size changes the chunk size for packets
0×02 Unknown
0×03 Bytes Read send every x bytes read by both sides
0×04 Ping ping is a stream control message, has subtypes
0×05 Server BW the servers downstream bw
0×06 Client BW the clients upstream bw
0×07 Unknown
0×08 Audio Data packet containing audio
0×09 Video Data packet containing video data
0x0A-0x0EUnknown  
0x0FFLEX_STREAM_SENDTYPE_FLEX_STREAM_SEND
0x10FLEX_SHARED_OBJECT TYPE_FLEX_SHARED_OBJECT
0x11FLEX_MESSAGE  TYPE_FLEX_MESSAGE 
0×12 Notify an invoke which does not expect a reply
0×13 Shared Object has subtypes
0×14 Invoke like remoting call, used for stream actions too.
0×16 StreamData 这是FMS3出来后新增的数据类型,这种类型数据中包含AudioData和VideoData


五、StreamID - 流ID
占用RTMP包头的最后4个字节,是一个big-endian的int型数据。我们x86 计算机内存中数据存放都是小尾数模式:little-endian,而网络数据流一般都是大尾数模式:big-endian。 StreamID是音视频流的唯一ID, 一路流如果既有音频包又有视频包,那么这路流音频包的StreamID和他视频包的StreamID相同,但ChannelID不同。
ChannelID 和StreamID之间的计算公式:StreamID=(ChannelID-4)/5+1  参考red5。如果这个封包既不是音频包,也不是视频包,那么他的StreamID=0.
例如当音视频包ChannelID为2、3、4时StreamID都为1 当音视频包ChannelID为9的时候StreamID为2

六、封包分析
例如有一个RTMP封包的数据0300 00 00 00 01 02 1400 00 00 00 0200 07 63 6F 6E 6E 65 63 74 003F F0 00 00 00 00 00 00 08 ,,,
数据依次解析的含义
03表示12字节头,channelid=3
000000表示时间戳 Timer=0
000102表示AMFSize=18
14表示AMFType=Invoke 方法调用
 00 00 00 00 表示StreamID = 0
//到此,12字节RTMP头结束下面的是AMF数据分析,具体的AMF0数据格式请参考 RTMP协议 二、AMF数据
02表示String
0007表示String长度7
63 6F 6E 6E 65 63 74 是String的Ascall值"connect"
00表示Double
3F F0 00 00 00 00 00 00 表示double的0.0
08表示Map数据开始
下面是我用c++实现的完整的rtmp客户端程序下载
RTMP协议分析 二、AMF数据http://www.cnweblog.com/fly2700/archive/2008/04/09/281432.html
程序下载http://www.cnweblog.com/fly2700/archive/2008/04/02/280641.html

posted on 2008-04-09 15:16 ZhangEF 阅读(24019) 评论(25)  编辑  收藏 所属分类: rtmp

评论

# re: RTMP协议封包分析 参考red5  回复  更多评论   

你好 ,我现在也在学习red5 rtmp协议处理。

我用C/C++模拟了 RTMP协议的播放过程,不过,当数据帧很大的时候,player就会关闭连接,能够和你交流RTMP协议的学习?

我的QQ是2151636,一起交流下吧。谢谢。
2008-05-17 14:37 | guhan

# re: RTMP协议封包分析 参考red5  回复  更多评论   

当数据帧很大的时候,可以将帧分割成多个rtmp包发送.我用fms3做测试,对每路直播流的流量可达到20Mbit/s,发送流量可达到80Mbit/s,100M网卡都占满了.一般视频流的码率不会超过2Mbit/s,所以码率再大都不怕.而且还可以通过fms3配制文件调节的.
2008-12-04 10:24 | ZhangEF

# re: RTMP协议封包分析 参考red5  回复  更多评论   

配制文件调节的
2008-12-29 10:00 | 北京时间

# re: RTMP协议封包分析 参考red5  回复  更多评论   

StreamID和ChannelID中,StreamID不是这样算出来的吧
ChannelID是算出来的,还有点可信
2009-01-07 14:03 | ricardo

# re: RTMP协议封包分析 参考red5[未登录]  回复  更多评论   

StreamID是算出来的 参考Red5 源代码RTMPConnect.java 498行
/**
* Return stream id for given channel id
*
* @param channelId
* Channel id
* @return ID of stream that channel belongs to
*/
public int getStreamIdForChannel(int channelId) {
if (channelId < 4) {
return 0;
}
return ((channelId - 4) / 5) + 1;
}
2009-02-02 15:11 | ZhangEF

# re: RTMP协议封包分析 参考red5  回复  更多评论   

00表示Double
3F F0 00 00 00 00 00 00 表示double的0.0


请问一下这个是怎么算出来的?
2009-05-23 08:10 | 80334

# re: RTMP协议封包分析 参考red5  回复  更多评论   

3F F0 00 00 00 00 00 00 表示double的0.0
double类型在计算机内存里面占8个字节, 这8字节在rtmp协议里面的排列循序和内存里面排列循序一致.
2009-06-02 14:40 | ZhangEF

# re: RTMP协议封包分析 参考red5  回复  更多评论   

我用etheral抓包发现音频和视频的ChinnalID都是0x04, streamID 都是 0x00000001只有Type不一样,一个08一个09。如果这样的话,请问:
当包较大,需要分包的时候,rtmp包头怎么确定? 还是一个字节0xC4???
那么怎么确定哪个是音频流哪个是视频流?
2009-07-11 11:58 | aurora001

# re: RTMP协议封包分析 参考red5[未登录]  回复  更多评论   

type为08的是音频,09的是视频
包头内容和包头长度根据上一个包确定,
2009-07-15 16:22 | ZhangEF

# re: RTMP协议封包分析 参考red5[未登录]  回复  更多评论   

>> 例如当ChannelID为2、3、4时StreamID都为1 当ChannelID为9的时候StreamID为2

那为什么在封包分析时,ChannelID为3时,StreamID等于0。

是否是因为这句:如果AMFType!=0x08 或!=0x09那么 StreamID为0。

只有在AMFType == 0x08 || AMFType == 0x09时,

StreamID=(ChannelID-4)/5+1

这条公式才会起效果
2009-11-14 19:02 | 白开水

# re: RTMP协议封包分析 参考red5  回复  更多评论   

公司很需要这个,可以深入合作吗?请联系Email:yi.sun@ema.com.cn
QQ:56023707
2010-01-20 11:55 | 孙毅

# re: RTMP协议封包分析 参考red5  回复  更多评论   

请问如果时间戳值大于等于0xffffff(16777215),扩展时间戳字节怎么排放呢?

我实现的RTMP时间戳一大于0xffffff, flash player 就断开连接了。
假如时间戳为0x12345678,那3字节时间戳:0xff 0xff 0xff, 4字节扩展时间戳:0x12 0x34 0x 56 0x78,其它字段没变化。这样设置对不?

在时间戳值大于等于0xffffff(16777215)的情况下,还有什么需要修改的么?
2010-07-03 10:23 | shelley

# re: RTMP协议封包分析 参考red5  回复  更多评论   

@shelley
你的扩展时间戳设置是正确的。如果连接断了应该是其他方面的原因。你可以用相对时间戳试试,这样3个字节的时间戳永远不会溢出。
2010-08-11 16:02 | ZhangEF

# re: RTMP协议封包分析 参考red5  回复  更多评论   

你好~请问下服务端在发送RTMP视频包时(MPEG4视频),每个信息头和视频数据中间会插入几个字节,请问下这几个字节是怎么构造的~谢谢!
2010-08-13 14:17 | ALEX QU

# re: RTMP协议封包分析 参考red5  回复  更多评论   

谢谢你的回答,我现在视频播放可以了,但是在I帧P帧都存在的情况下会前后抖动,比如一个人往前走,会看到人退回去再向前走。在全I帧的情况下是好的,服务器发的数据顺序是正确的,经过网络传输在flash中播放就不对了。是不是应该在视频传输数据中增加什么控制信息呢?RED5中应该参考哪一部分呢?我没看到发streaming的代码,参考的是发送mp4的部分
2010-08-18 10:32 | shelley

# re: RTMP协议封包分析 参考red5  回复  更多评论   

最近做了c++的客户端来和RED5服务器通信,flash里面的connect通常只有一个参数,但也可以为了标示清楚设多个参数,比如connect("rtmp://124.16.134.53/myChat","1234")这样RED5服务器端的appConnect(IConnection conn, Object[] params)可以直接识别,params[0]即为1234。但请问 怎么在c++中将后面的那个"1234"传送到服务器端呢,能不能给个大概思路,谢谢了!!!
2010-08-26 14:37 | spooky

# re: RTMP协议封包分析 参考red5[未登录]  回复  更多评论   

你用flex写个程序发送connect命令带参数到服务器的时候,会发送一个rtmp包。抓这个包分析格式,看他的参数是怎么写的,然后你用c++模仿发送这个包就可以了。
其实就是在不带参数的connect包的后面加了个几个数据,0x02 (字符串类型) 0x04 (字符串长度) 然后就是你的字符串"1234"
2010-08-27 11:40 | ZhangEF

# re: RTMP协议封包分析 参考red5[未登录]  回复  更多评论   

我想问一下 如果我的采集卡不是支持 directshow的 但有单独的api 那么 但是不是可以先用 厂商的驱动获取视频 再作为directshow的输入 然后再输出?还是直接写成虚拟设备的形式?
2011-03-11 10:55 |

# re: RTMP协议 一、RTMP包头  回复  更多评论   

为什么我的数据总是堵到客户端不播,要等7,8秒才播,包也抓了,时间戳也改几次了,我是用c++模拟的客户端往red5发音视频数据的,快疯了都
2011-11-30 19:50 | dluf

# re: RTMP协议分析 一、RTMP包头  回复  更多评论   

我是用flash做的,不会c++。
2012-03-20 16:01 | VINI

# re: RTMP协议分析 一、RTMP包头  回复  更多评论   

我的情况 跟上面以为一样:AMF time 时间设置大于或等于0xffffff,加上ext timestamp 4个字节,flash player 就会断。不知道什么原因,采用相对时间戳,我的视频中有B帧,所以相对时间会出现负数。不知道怎么解决。
2012-09-14 14:41 | RedGG

# re: RTMP协议分析 一、RTMP包头  回复  更多评论   

想问一下 我想向Crtmpserver推送H264视频 但是我的数据包封包 不知道怎么封 看文档不是很明白 比如视频包吧
现在有一包数据 数据指针lpbuf 长度len
从网上看了一份代码说要在数据包前加 17或者27(此帧为关键帧时用17非关键帧用27) 01 00 00 42
现象是数据发到服务器了,用vlc也可以得到数据但是不解码。麻烦帮么看看。下面是我组视频包的代码。
包头:
rtmp_pakt.m_packetType = RTMP_PACKET_TYPE_VIDEO;
rtmp_pakt.m_nBodySize = len+5;
rtmp_pakt.m_nTimeStamp = 0;
rtmp_pakt.m_nChannel = 4;
rtmp_pakt.m_headerType = RTMP_PACKET_SIZE_LARGE;
rtmp_pakt.m_nInfoField2 = rtmp_->m_stream_id;
包体:
memset(g_szBodyFrameBuffer,0,1024*32);
frametype =(*(lpBuf + 8))&0x0F;
if(frametype == 7)
{
printf("**********Is the
IDR!**********\n");
g_szBodyFrameBuffer[0]=0x17;
}
else
{
g_szBodyFrameBuffer[0]=0x27;
}
g_szBodyFrameBuffer[ 1]=0x01;
g_szBodyFrameBuffer[ 2]=0x00;
g_szBodyFrameBuffer[ 3]=0x00;
g_szBodyFrameBuffer[ 4]=0x42;

memcpy(g_szBodyFrameBuffer+5, lpBuf, len);
memcpy(rtmp_pakt.m_body, g_szBodyFrameBuffer, len+5);
RTMP_SendPacket(rtmp_,&rtmp_pakt,0);
2013-01-08 11:56 | duan

# re: RTMP协议分析 一、RTMP包头  回复  更多评论   

@shelley
你那个在I帧P帧都存在的情况下会前后抖动的问题解决了吗?我也遇到了这个问题
2013-01-15 21:13 | hyb

# re: RTMP协议分析 一、RTMP包头  回复  更多评论   

请问谁有rtmp编译好的库和使用例程,email:398630341@qq.com,等重谢!
2013-04-03 15:27 | lengyuye10

# re: RTMP协议分析 一、RTMP包头  回复  更多评论   

StreamID是音视频流的唯一ID, 一路流如果既有音频包又有视频包,那么这路流音频包的StreamID和他视频包的StreamID相同,但ChannelID不同。

如果是channelID不同,那音频的channelID是什么值,视频的channelID是什么值??? channelID 0x04不是同时代表audio和video么?有人帮忙解释一下么?





2013-12-21 19:50 | s985507995