用Red5、librtmp和ffmpeg搭建网络直播系统

来源:互联网 发布:虎嗅网 知乎 编辑:程序博客网 时间:2024/05/29 03:15

客户需要做一个实时性非常好的网络会议系统,要求在高速局域网内的音视频延时在几百毫秒这个量级,同时需要可以扩展到安卓和IOS上。之前完全没有接触过流媒体,开始想自己写协议,后来了解了一下,完全没有必要......选来选去,觉得rtmp协议最合适。一方面实时性非常好,另一方面,PC端有免费的服务器(Red5)以及现成的客户端(Flash),极大的节约了成本,同时,也便于向移动终端扩展。从头到尾做了三周左右,终于完成了。在局域网内的延时可以控制在300ms以内。期间经历了完全不懂到略有所得,也绕了不少路,现在略加总结。

一、RTMP协议

RTMP(Real Time Messaging Protocol)实时消息传送协议是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输 开发的开放协议。
它有三种变种:
1)工作在TCP之上的明文协议,使用端口1935;
2)RTMPT封装在HTTP请求之中,可穿越防火墙;
3)RTMPS类似RTMPT,但使用的是HTTPS连接。

具体的协议详情,可以参看Adobe的协议说明文档。不过一般人也就不用看了,写的也不明白,我们工程实现也不需要过于关注底层。
RTMP最初的目的就是为了实现Web端的实时通信,服务器端有Adobe的FMS,客户端就是Adobe的Flash Player。通信内容并不存在限制,当然,最常见的还是音视频。音视频产生也有Adobe的FMLE。这就可以看出来,Adobe目的也是想通过自身Flash Player的巨大市场优势,结合RTMP来抢占流媒体市场。
其实,通过FMS+FMLE+Flash Player,就能够搭建一个实时性非常好的网络会议系统。但是 FMS是收费的,而且价格不菲。FMLE吧,毕竟不是专门做会议用的,无法当做产品使用。因此,在这两端必须做出修改。最终选择的方案是Red5 + librtmp + ffmpeg。

二、Red5

Red5的主要功能和Macromedia公司的FMS类似,提供基于Flash的流媒体服务的一款基于Java的开源流媒体服务器。它由Java语言编写,使用RTMP作为流媒体传输协议,这与FMS完全兼容。它具有流化FLV、MP3文件,实时录制客户端流为FLV文件,共享对象,实时视频播放、Remoting等功能。用Red5替换FMS后,客户端不用更改可正常运行。
最关键的是:它完全免费!
它的官网:http://www.red5.org/
最新Release版本是1.0。基本的安装我就不说了,直接百度。
需要注意两点:
1. 安装时填IP注意一定要填0.0.0.0。 
2. 1.0版本中已经用默认安装的live替代了oflaDemo来实现流媒体发布。所以不要再劳什子找oflaDemo了。

最后介绍一下作者:
Red 5成立于2005年,由一批前暴雪核心员工组建,由RED5工作室制作的第一人称免费射击网游火瀑》凭借出色的作品内容等设计,赢得了国内外玩家的高度赞誉!一直致力于一款基于Offsite引擎的网游。凭借优异的技术水准,该游戏在2008年得到了Intel的支持,并且被列为当时Intel下一代Larrabee图形处理器首款专属网游,遗憾的是Intel Larrabee图形处理器不久后没了消息并最终夭折,该作的开发也受到影响。2009年底到2010年初有消息称,Red 5陷入绝境,裁员50%。2010年3月,中国网游公司第九城市携2000万美金向Red 5伸出了橄榄枝并获其大部分股权,Red 5向外媒证实,该作仍在在开发中,不会停滞或延期,并且将采用Offset引擎的全面升级版本。朱骏之前在采访中曾透露,这款网游将在9月面市。
向追逐梦想的人致敬!

三、librtmp

有了作为发布服务器的Red5,还必须要把音视频数据封装成RTMP协议包传递给Red5才行。靠着Adobe写的鬼说明,估计想实现协议的封装很够呛!当然,互联网上总不缺乐于分享的大牛。Andrej Stepanchuk 凭借着对Adobe产品数据包的分析,愣是自己实现了协议的封装。
librtmp的源代码到http://rtmpdump.mplayerhq.hu/下载,编译的方法网上也可以搜到。如果只是应用的话,直接下载别人编译好的lib和dll也行。最新版本是2.4。
librtmp的使用非常简单,就几个主要的函数。不过为了方便集成,我把它封装了一下,主要实现了几个接口:
class CRtmpStreamer{        public:CRtmpStreamer(void);~CRtmpStreamer(void);RTMPDatatype stream_type;bool Init();bool UnInit();bool Connect(char * url);bool Disconnect();bool IsConnected();bool QueueAAC(byte * data, unsigned int size, unsigned int timestamp);bool QueueH264(byte * data, unsigned int size, unsigned int timestamp, bool isKeyframe);bool SetMeta(LPRTMPMetadata lpMetaData);RTMPMetadata GetMeta();        private:RTMP * rtmp;char rtmp_server_url[255];CWinThread * pThread;vector<RTMPPacket *> video_queue;vector<RTMPPacket *> audio_queue;RTMPPacket * Pack(unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp);int  SendPacket(unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp);bool SendMetadata(LPRTMPMetadata lpMetaData);void ResetQueue();static UINT ThreadStreaming( LPVOID pParam );};

这样用起来就方便多了。直接传进来H264和AAC的裸流,CRtmpStreamer负责把他们封装成rtmp能识别的数据包。
通过CRtmpStreamer向Red5发送H264和AAC的裸流,就能实现直播了。这里H264和AAC的编码,我用的是ffmpeg来实现。当然,你也可以轻量级一点,用x264和libaac来实现也行。

四、H264和AAC的rtmp封装

关于用FFMpeg如何进行H264和AAC编码,相信大家很容易找到相关资料,这里重点讲一讲如何把ffmpeg编码后的h264和AAC数据封装成rtmp能识别的数据包。
为了使服务器和播放器能够正确解码你的数据。 你发送的第一帧视频帧和第一帧音频帧,都应该是你音视频信息的一个说明,然后后面才能发送真正的数据。这两帧叫做AVC sequence header和AAC sequence header。

AVC sequence header就是AVCDecoderConfigurationRecord结构,该结构在标准文档“ISO-14496-15 AVC file format”中有详细说明。

    

  AAC sequence header存放的是AudioSpecificConfig结构,该结构则在“ISO-14496-3 Audio”中描述。

    

  这里提醒几点:

1. 这些数据ffmpeg其实都有提供;

2.发送的时候时间戳很关键,如果一旦时间戳不对,很可能无法播放。CRtmpStreamer类提供了一定的辅助排序功能,但是每帧的时间戳一定要正确赋值。


永祺视觉-----专注于机器视觉与人工智能

QQ:908392132



0 0
原创粉丝点击