搭建RTMFP服务器以实现P2P直播


注意:

本文使用了过时的 Flash技术来实现,请尽量关注并使用最新的 HTML5 DASH + WebRTC技术来实现具体应用。

首先在一台 Linux 服务器上下载 AMS ,点此下载。

➜  AMS  ./installAMSDo you agree with the license agreement? (y/n): y

Please enter your Adobe Media Server 5 serial number: #不推荐使用盗版,当然搜一下就能搜到 2333# 之后一路回车就好,如果不需要 HTTP Fallback 的话可以把 80 端口去掉

service ams start

安装并启动之后,如果端口监听正常,就不需要什么配置

然后打开 tools/multicast/configurator/configurator.html

Multicast 类型选择 Peer to Peer ,服务器输入 rtmfp://SERVER_IP/multicast ,password 随便输入一个,点击生成然后选择 Show GroupSpecs

Groupspec With Auth 就是直播用的,Groupspec Without Auth 是观看用的,两个都记下来。

接下来,使用直播大师进行推流,直播大师配置界面如下:

QQ图片20170113140919.png

然后,在【直播大师】的主控面板中点击“开始编码”按钮。

其实,编码开始后就可以观看了,但是由于播放器并没有加入 P2P Netgroup , 还需要对播放器动手脚,我们拿 Video.JS 的 SWF 版开刀,先下载源代码

git clone https://github.com/videojs/video-js-swfnpm install

用文本编辑器打开,定位到 src/com/videojs/providers/RTMPVideoProvider.as 修改几处内容

// 第 26 行加入private var _ng:NetGroup;private var groupSpec:String = "你的 GropSpecWithoutAuth";//  422 行左右private function initNetStream():void{    if(_ns != null){
        _ns.removeEventListener(NetStatusEvent.NET_STATUS, onNetStreamStatus);
        _ns = null;
    }
    _ns = new NetStream(_nc,groupSpec);
    _ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStreamStatus);
    _ns.client = this;
    _ns.bufferTime = 1;
    _ns.play(_src.streamURL);
    _videoReference.attachNetStream(_ns);
    _model.broadcastEventExternally(ExternalEventName.ON_LOAD_START);
    _model.broadcastEvent(new VideoPlaybackEvent(VideoPlaybackEvent.ON_STREAM_READY, {ns:_ns}));
}// 469 行 左右private function onNetConnectionStatus(e:NetStatusEvent):void{    switch(e.info.code){        case "NetConnection.Connect.Success": // 连接成功
            _model.broadcastEventExternally(ExternalEventName.ON_RTMP_CONNECT_SUCCESS);            if(_src.connectionURL.indexOf("rtmfp") == 0){ // 如果是 RTMFP 链接
                _ng = new NetGroup(_nc,groupSpec); // 创建 NetGroup
                _ng.addEventListener(NetStatusEvent.NET_STATUS,onNetConnectionStatus);
                _model.broadcastEventExternally("P2P.waitforconf"); // 等待用户选择允许或拒绝 
                // 不知道那几个国产流氓视频网站是怎么跳过这个是否开启 P2P 的提示
            }else{
                _ns = new NetStream(_nc);
                _ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStreamStatus);
                _ns.client = this;
                _ns.bufferTime = 1;
                _ns.play(_src.streamURL);
                _videoReference.attachNetStream(_ns);
                _model.broadcastEventExternally(ExternalEventName.ON_LOAD_START);
                _model.broadcastEvent(new VideoPlaybackEvent(VideoPlaybackEvent.ON_STREAM_READY, {ns:_ns}));
            }                    
            break;        case "NetConnection.Connect.Failed":            if(_ncRTMPCurrentRetry < _ncRTMPRetryThreshold){
                _ncRTMPCurrentRetry++;
                _model.broadcastErrorEventExternally(ExternalErrorEventName.RTMP_CONNECT_FAILURE);
                _rtmpRetryTimer.start();
                _model.broadcastEventExternally(ExternalEventName.ON_RTMP_RETRY);
            }            break;        case "NetGroup.Connect.Success": // 用户选择了允许 P2P ,开始播放
           initNetStream();           break;        case "NetGroup.Connect.Rejected": // 用户选择了拒绝 P2P ,重新连接,不带 netgroup
            _ns = new NetStream(_nc);
            _ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStreamStatus);
            _ns.client = this;
            _ns.bufferTime = 1;
            _ns.play(_src.streamURL);
            _videoReference.attachNetStream(_ns);
            _model.broadcastEventExternally(ExternalEventName.ON_LOAD_START);
            _model.broadcastEvent(new VideoPlaybackEvent(VideoPlaybackEvent.ON_STREAM_READY, {ns:_ns}));           break;        default:            if(e.info.level == "error"){
                _model.broadcastErrorEventExternally(e.info.code);
                _model.broadcastErrorEventExternally(e.info.description);
            }            break;
    }
    _model.broadcastEvent(new VideoPlaybackEvent(VideoPlaybackEvent.ON_NETCONNECTION_STATUS, {info:e.info}));
}// 608 行左右,default 之前加入case "NetStream.Video.DimensionChange": // P2P 的视频会比音频后到一会,收到此事件代表真正开始播放
    _model.broadcastEvent(new VideoPlaybackEvent(VideoPlaybackEvent.ON_VIDEO_DIMENSION_UPDATE, {videoWidth: _videoReference.videoWidth, videoHeight: _videoReference.videoHeight}));    if(_model.metadata && _videoReference) // 修正视频分辨率,使其充满屏幕
    {
        _model.metadata.width = _videoReference.videoWidth;
        _model.metadata.height = _videoReference.videoHeight;
    }
    _model.broadcastEventExternally("videoplaying"); // 给 JS 广播一个视频已开始播放的信号
    break;

至此代码修改完成,编译

grunt dist

运行之后即可在 dist 得到新的 swf 文件,替换掉 vjs 自带的 swf ,然后通过以下 JS 代码加载视频流

SWFElement.vjs_setProperty("rtmpConnection","rtmfp://SERVER_IP/multicast");
SWFElement.vjs_setProperty("rtmpStream","流名称");

打开两台电脑测试,就可以看到彼此的上行流量,说明P2P直播已经正常工作。当然,如果有更多的客户端加入,P2P的加速效果就会更加明显,这正是P2P的技术优势所在。



0 条评论

切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册