RTMP直播应用与延时分析

直播应用中,RTMP和HLS基本上可以覆盖所有客户端观看,

HLS主要是延时比较大,RTMP主要优势在于延时低。

一、应用场景

低延时应用场景包括:

. 互动式直播:譬如2013年大行其道的美女主播,游戏直播等等各种主播,流媒体分发给用户观看。用户可以文字聊天和主播互动。

. 视频会议:我们要是有同事出差在外地,就用视频会议开内部会议。其实会议1秒延时无所谓,因为人家讲完话后,其他人需要思考,思考的延时也会在1秒左右。当然如果用视频会议吵架就不行。
. 其他:监控,直播也有些地方需要对延迟有要求,互联网上RTMP协议的延迟基本上能够满足要求。

本文福利, 免费领取C++音视频学习资料包+学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

二、RTMP和延时

1. RTMP的特点如下:

1) Adobe支持得很好:

RTMP实际上是现在编码器输出的工业标准协议,基本上所有的编码器(摄像头之类)都支持RTMP输出。原因在于PC市场巨大,PC主要是Windows,Windows的浏览器基本上都支持flash,Flash又支持RTMP支持得非常好。

2) 适合长时间播放:
因为RTMP支持的很完善,所以能做到flash播放RTMP流长时间不断流,当时测试是100万秒,即10天多可以连续播放。对于商用流媒体应用,客户端的稳定性当然也是必须的,否则最终用户看不了还怎么玩?我就知道有个教育客户,最初使用播放器播放http流,需要播放不同的文件,结果就总出问题,如果换成服务器端将不同的文件转换成RTMP流,客户端就可以一直播放;该客户走RTMP方案后,经过CDN分发,没听说客户端出问题了。

3)延迟较低:
比起YY的那种UDP私有协议,RTMP算延迟大的(延迟在1-3秒),比起HTTP流的延时(一般在10秒以上)RTMP算低延时。一般的直播应用,只要不是电话类对话的那种要求,RTMP延迟是可以接受的。在一般的视频会议应用中,RTMP延时也能接受,原因是别人在说话的时候我们一般在听,实际上1秒延时没有关系,我们也要思考(话说有些人的CPU处理速度还没有这么快)。

4) 有累积延迟:

技术一定要知道弱点,RTMP有个弱点就是累积误差,原因是RTMP基于TCP不会丢包。所以当网络状态差时,服务器会将包缓存起来,导致累积的延迟;待网络状况好了,就一起发给客户端。这个的对策就是,当客户端的缓冲区很大,就断开重连。

2. HLS低延时

主要有人老是问这个问题,如何降低HLS延迟。

HLS解决延时,就像是爬到枫树上去捉鱼,奇怪的是还有人喊,看那,有鱼。

你说是怎么回事?

3. RTMP延迟的测量

如何测量延时,是个很难的问题,

不过有个行之有效的方法,就是用秒表,可以比较精确的对比延时。

经过测量发现,在网络状况良好时:
. RTMP延时可以做到0.8秒左右。
. 多级边缘节点不会影响延迟(和SRS同源的某CDN的边缘服务器可以做到)
. Nginx-Rtmp延迟有点大,估计是缓存的处理,多进程通信导致?
. GOP是个硬指标,不过SRS可以关闭GOP的cache来避免这个影响.
. 服务器性能太低,也会导致延迟变大,服务器来不及发送数据。
. 客户端的缓冲区长度也影响延迟。

譬如flash客户端的NetStream.bufferTime设置为10秒,那么延迟至少10秒以上。

4. GOP-Cache

什么是GOP?就是视频流中两个I帧的时间距离。

GOP有什么影响?

Flash(解码器)只有拿到GOP才能开始解码播放。

也就是说,服务器一般先给一个I帧给Flash。

可惜问题来了,假设GOP是10秒,也就是每隔10秒才有关键帧,如果用户在第5秒时开始播放,会怎么样?

第一种方案:等待下一个I帧,也就是说,再等5秒才开始给客户端数据。这样延迟就很低了,总是实时的流。

问题是:等待的这5秒,会黑屏,现象就是播放器卡在那里,什么也没有,有些用户可能以为死掉了,就会刷新页面。

总之,某些客户会认为等待关键帧是个不可饶恕的错误,延时有什么关系?我就希望能快速启动和播放视频,最好打开就能放!

第二种方案:马上开始放,放什么呢?

你肯定知道了,放前一个I帧。

也就是说,服务器需要总是cache一个gop,这样客户端上来就从前一个I帧开始播放,就可以快速启动了。

问题是:延迟自然就大了。

有没有好的方案?

有!至少有两种:

编码器调低GOP,譬如0.5秒一个GOP,这样延迟也很低,也不用等待。

坏处是编码器压缩率会降低,图像质量没有那么好。

5. 累积延迟

除了GOP-Cache,还有一个有关系,就是累积延迟。

服务器可以配置直播队列的长度,服务器会将数据放在直播队列中,如果超过这个长度就清空到最后一个I帧:

当然这个不能配置太小,譬如GOP是1秒,queue_length是1秒,这样会导致有1秒数据就清空,会导致跳跃。

有更好的方法?有的。
延迟基本上就等于客户端的缓冲区长度,因为延迟大多由于网络带宽低,服务器缓存后一起发给客户端,现象就是客户端的缓冲区变大了,譬如NetStream.BufferLength=5秒,那么说明缓冲区中至少有5秒数据。

处理累积延迟的最好方法,是客户端检测到缓冲区有很多数据了,如果可以的话,就重连服务器。

当然如果网络一直不好,那就没有办法了。

直播现状简介

想做一套直播系统?

1.技术实现层面:

技术相对都比较成熟,设备也都支持硬编码。IOS还提供现成的 Video ToolBox框架,可以对摄像头和流媒体数据结构进行处理,但Video ToolBox框架只兼容8.0以上版本,8.0以下就需要用x264的库软编了。

github上有现成的开源实现,推流、美颜、水印、弹幕、点赞动画、滤镜、播放都有。技术其实不是很难,而且现在很多云厂商都提供SDK,七牛云、金山云、乐视云、腾讯云、百度云、斗鱼直播伴侣推流端,功能几乎都是一样的,没啥亮点,不同的是整个直播平台服务差异和接入的简易性。后端现在 RTMP/HTTP-FLV 清一色,App挂个源站直接接入云厂商或CDN就OK。

2.直播优化层面

其实最难的难点是提高首播时间、服务质量即Qos(Quality of Service,服务质量),如何在丢包率20%的情况下还能保障稳定、流畅的直播体验,需要考虑以下方案:

1.为加快首播时间,收流服务器主动推送 GOP :(Group of Pictures:策略影响编码质量)所谓GOP,意思是画面组,一个GOP就是一组连续的画面至边缘节点,边缘节点缓存 GOP,播放端则可以快速加载,减少回源延迟

GOP.1

2.GOP丢帧,为解决延时,为什么会有延时,网络抖动、网络拥塞导致的数据发送不出去,丢完之后所有的时间戳都要修改,切记,要不客户端就会卡一个 GOP的时间,是由于 PTS(Presentation Time Stamp,PTS主要用于度量解码后的视频帧什么时候被显示出来) 和 DTS 的原因,或者播放器修正 DTS 和 PTS 也行(推流端丢GOD更复杂,丢 p 帧之前的 i 帧会花屏)

3.纯音频丢帧,要解决音视频不同步的问题,要让视频的 delta增量到你丢掉音频的delta之后,再发音频,要不就会音视频不同步

4.源站主备切换和断线重连

5.根据TCP拥塞窗口做智能调度,当拥塞窗口过大说明节点服务质量不佳,需要切换节点和故障排查

6.增加上行、下行带宽探测接口,当带宽不满足时降低视频质量,即降低码率

7.定时获取最优的推流、拉流链路IP,尽可能保证提供最好的服务

8.监控必须要,监控各个节点的Qos状态,来做整个平台的资源配置优化和调度

直播过程.3

9.如果产品从推流端、CDN、播放器都是自家的,保障 Qos 优势非常大

10.当直播量非常大时,要加入集群管理和调度,保障 Qos

11.播放端通过增加延时来减少网络抖动,通过快播来减少延时

3.运营成本和客户体验

根据网上的数据,斗鱼 TV 为 3 亿人民币,战旗 TV 为 1.5 亿人民币,龙珠为 1.2 亿人民币,虎牙为 3000 万 + 人民币。

运营和推广:这个就比较烧钱了,一些做移动直播、游戏直播、秀场直播的A轮至少得上千万。

用户体验:流畅、不卡顿、不花屏、断线重连、丢包策略、首画加载速度、丰富的礼物系统,为了提高用户体验,可以在后台加载其他页面数据,但要在用户体验和内存优化方面找到平衡点。

流媒体传输

1.TCP:TCP为点对点的协议,虽然能保证了数据传输的可靠性,但是对服务器资源耗费较大,在数据流大的场合难以保证数据流传输的实时性。

2.UDP:UDP为不可靠传输协议,不需要维护连接状态,也不认为每个数据包都必须到达接受端,因此网络负荷比TCP小,传输速度也要比TCP快;但在网络越拥挤时,越有更多的数据包丢失。

3.RTMP:RTMP一个专门为高效传输视频,音频和数据而设计的协议。它通过建立一个二进制TCP连接或者连接HTTP隧道实现实时的视频和声音传输。

4.FFmpeg:FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案

协议差异.4

项目搭建:采集端

1.目前比较知名的有VideoCore

目前国内很多知名的推流框架都是对VideoCore的二次开发。这个框架主要使用C++写的,支持RTMP推流,但对于iOS开发者来说有点晦涩难懂(精通C++的除外)。想开源和免费的可以选择现在的几个知名项目VideoCore + GPUImage+基于GPU的美颜滤镜 ,播放用IJKPlayer自己修改。

2.国内比较火的LiveVideoCoreSDK

框架提供IOS苹果手机的RTMP推流填写RTMP服务地址,直接就可以进行推流,SDK下载后简单的工程配置后能直接运行,实现了美颜直播和滤镜功能,基于OpenGL,前后摄像头随时切换,提供RTMP连接状态的回调。

这个框架是国内比较早的一款推流框架有不少在使用这个SDK,功能非常齐全,作者也比较牛,用来学习推流采集相关内容非常好,但是集成到工程中有些困难(对于我来说)。总的来说这是一款非常厉害的推流SDK,几乎全部使用C++写的,编译效率非常好,如果有实力的话推荐使用这个框架来做自己项目的推流端。

3.可读性比较好的推流LFLiveKit

框架支持RTMP(Real Time Messaging Protocol ):实时消息传输协议,Adobe公司的。

HlS (HTTP Live Streaming) :苹果自家的动态码率自适应技术。主要用于PC和Apple终端的音视频服务。包括一个m3u(8)的索引文件,TS媒体分片文件和key加密串文件。

推荐这个框架第一是因为它主要使用OC写的,剩下的用C语言写的,框架文件十分清晰,这对不精通C++的初学者提供了很大的便利,并且拓展性非常强,支持动态切换码率功能,支持美颜功能。

4.美颜功能

美颜的话一般都是使用的GPUImage基于OpenGl开发,纯OC语言,这个框架十分强大,可以做出各种不同滤镜,可拓展性高。如果对美颜没有具体思路可以直接用BeautifyFace,可以加入到项目中,很方便的实现美颜效果。

项目具体搭建

1.如何实现美颜?

美颜功能使用的是BeautifyFace,它可以很快速的实现美颜功能,效果不错,它的底层还是基于的GPUImage,对GPUImage十分喜爱的Developer,可以参照BeautifyFace,写出一个属于自己的美颜功能,并且添加各种滤镜。

2.悬浮TabBar的实现

这个TabBar看着像是用自定义TabBar做的,但事实上它还是用的系统的TabBar,给系统的tabBar.backgroundImage设置一张设计好的背景图片。

想做一套像映客的直播系统?

TabBar.8

添加后会发现顶部有一条阴影线,并且TabBar的高度也不够。阴影线与上图绿色线条之间变成了透明颜色,实现下面方法隐藏阴影线,并且调高TabBar的高度。

TabBar.9

//隐藏阴影线

[[UITabBar appearance] setShadowImage:[UIImage new]];

- (void)setupTabBarBackgroundImage { UIImage *image = [UIImage imageNamed:@"tab_bg"]; CGFloat top = 40; // 顶端盖高度

CGFloat bottom = 40 ; // 底端盖高度

CGFloat left = 100; // 左端盖宽度

CGFloat right = 100; // 右端盖宽度

UIEdgeInsets insets = UIEdgeInsetsMake(top, left, bottom, right); // 指定为拉伸模式,伸缩后重新赋值

UIImage *TabBgImage = [image resizableImageWithCapInsets:insets resizingMode:UIImageResizingModeStretch]; self.tabBar.backgroundImage = TabBgImage;

[[UITabBar appearance] setShadowImage:[UIImage new]];

[[UITabBar appearance] setBackgroundImage:[[UIImage alloc]init]];

}//自定义TabBar高度- (void)viewWillLayoutSubviews { CGRect tabFrame = self.tabBar.frame;

tabFrame.size.height = 60;

tabFrame.origin.y = self.view.frame.size.height - 60; self.tabBar.frame = tabFrame;

}

3.播放端的实现

播放端用的针对RTMP优化过的ijkplayer(),ijkplayer是基于FFmpeg的跨平台播放器,这个开源项目已经被多个 App 使用,其中映客、美拍和斗鱼使用了 ijkplayer(5700+⭐️) 。在本文的末未提供了,已经打包好的ijkplayer,直接拖入项目就可以使用。省去了编译的过程(编译十分麻烦,并且容易出错)。

- (void)goPlaying { //获取url

self.url = [NSURL URLWithString:_liveUrl];

_player = [[IJKFFMoviePlayerController alloc] initWithContentURL:self.url withOptions:nil]; UIView *playerview = [self.player view]; UIView *displayView = [[UIView alloc] initWithFrame:self.view.bounds]; self.PlayerView = displayView;

[self.view addSubview:self.PlayerView]; // 自动调整自己的宽度和高度

playerview.frame = self.PlayerView.bounds;

playerview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

[self.PlayerView insertSubview:playerview atIndex:1];

[_player setScalingMode:IJKMPMovieScalingModeAspectFill];

}

4.推送端的实现

使用的是LFLiveKit,推流端可以选择很多GitHub上的开源项目替代LFLiveKit,比如上面所提到的VideoCore,和LiveVideoCoreSDK。商用的话可以选择各大厂商的SDK,网易直播云、七牛、腾讯、百度、新浪、其中金山直播云本人用过。使用直播云的好处就是能快速上线App,功能十分齐全,可以播放器和推流端,服务器一套下来,有专业客服人员帮助集成到工程中,缺点就是流量费太贵了。

- (UIButton*)startLiveButton{ if(!_startLiveButton){

_startLiveButton = [UIButton new]; //位置

_startLiveButton.frame = CGRectMake((XJScreenW - 200) * 0.5, XJScreenH - 100, 200, 40);

_startLiveButton.layer.cornerRadius = _startLiveButton.frame.size.height * 0.5;

[_startLiveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

[_startLiveButton.titleLabel setFont:[UIFont systemFontOfSize:16]];

[_startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];

[_startLiveButton setBackgroundColor:[UIColor grayColor]];

_startLiveButton.exclusiveTouch = YES;

__weak typeof(self) _self = self;

[_startLiveButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {

_self.startLiveButton.selected = !_self.startLiveButton.selected; if(_self.startLiveButton.selected){

[_self.startLiveButton setTitle:@"结束直播" forState:UIControlStateNormal];

LFLiveStreamInfo *stream = [LFLiveStreamInfo new];

stream.url = @"rtmp://daniulive.com:1935/live/stream238";

[_self.session startLive:stream];

}else{

[_self.startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];

[_self.session stopLive];

}

}];

} return _startLiveButton;

}

stream.url是服务器的地址,推流完成后使用VLC播放

本文福利, 免费领取C++音视频学习资料包+学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

你可能感兴趣的:(音视频开发,ffmpeg,音视频,音视频开发,C++音视频,音视频编解码,RTSP,RTMP)