• RTMP直播应用与延时分析


    直播应用中,RTMP和HLS基本上可以覆盖所有客户端观看,
    HLS主要是延时比较大,RTMP主要优势在于延时低。

    一、应用场景

    低延时应用场景包括:
      .  互动式直播:譬如2013年大行其道的美女主播,游戏直播等等
         各种主播,流媒体分发给用户观看。用户可以文字聊天和主播互动。
      .  视频会议:我们要是有同事出差在外地,就用视频会议开内部会议。
         其实会议1秒延时无所谓,因为人家讲完话后,其他人需要思考,
         思考的延时也会在1秒左右。当然如果用视频会议吵架就不行。
      .  其他:监控,直播也有些地方需要对延迟有要求,
         互联网上RTMP协议的延迟基本上能够满足要求。


    二、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秒数据。


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

    映客 LFLiveKit 推流

    一、直播现状简介

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

    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 帧会花屏)

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

    帧.2

    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播放






     

  • 相关阅读:
    常见排序算法(上)
    二.CSS的伪类
    ASP.NET_编码模型
    一.CSS工作原理
    如何拦截来电,并检测到某些特定号码时自动挂断电话
    如何获取短信内容
    Android导入项目时出现红色感叹号
    如何接收广播;如何发送广播
    设置Activity显示和关闭时的动画效果
    将Activity设置成半透明的对话框
  • 原文地址:https://www.cnblogs.com/tangyuanby2/p/9288234.html
Copyright © 2020-2023  润新知