学习
实践
活动
专区
工具
TVP
写文章
专栏首页晨光的Code直播秒开探索之路
原创

直播秒开探索之路

直播间打开速度是直播软件非常重要的性能指标,为了达到秒开直播间的目标,作者探索了多种方式,经过了多个版本的优化迭代,最终达到了较为满意的效果,在此分享给大家。

1. 效果展示

首先展示下最终的效果,在网络条件较好的情况下,页面打开而直播间已经开始正常播放,即所谓秒开。

image.png

通过逐帧播放可以看到,在直播间页面刚刚Push出20%左右的时候,播放器已经拉取到首帧画面,并展示在了直播间页面上,从点击到播放无缝衔接,达到了最好的直播体验(当然这是网络很好的时候才能达到的效果)。

实验室性能指标如下:

机型:iPhone 6sP,连接 Wi-Fi,打开直播间

打开次数

首帧显示时间(优化前)

首帧显示时间(优化后)

1

2.064155

0.331076

2

0.725348

0.229371

3

0.723510

0.191394

4

0.932670

0.212849

5

0.799369

0.237580

2. 具体优化过程

下面说下具体的优化过程。

2.1 分析直播间打开过程,制定优化思路

步骤

执行任务

消耗时间

1

点击事件

0

2

初始化直播间

300

3

初始化播放器SDK

100

4

拉取直播信息

150

5

设置直播参数

10

6

解析下载链接IP地址

5

7

拉取首帧数据

150

8

显示首帧画面

0

之前的直播间打开流程为串行,关键的任务会被前置任务所阻塞,比如其中初始化直播间过程中充满了多个耗时方法和UI控件的创建,会极大的阻碍首帧渲染上屏,甚至有时更新UI控件时会卡住主线程1秒以上(比较陈旧的版本);初始化播放器SDK也会消耗几十毫秒的时间;一次网络请求,在网络较好的情况下也要消耗一百多毫秒。根据直播间打开流程,主要的优化思路分为几个方面:

(1)优化任务队列,将串行任务改为并行执行,前置耗时任务

(2)优化耗时方法,使用效率更高的方法代替低效方法,能在子线程执行的方法放到子线程执行

(3)拆分UI更新的巨大函数,减少主线程的占用时间

2.2 任务队列的优化

首先分析下理想状态下播放器秒开的任务流程:点击->拉取数据->首帧上屏,因此问题转化为分析如何在拉取首帧数据时间无法缩短的前提下有效缩短从点击到真正开始拉取数据的时间。

(1)消除初始化直播间和拉取房间信息的时间

在直播列表的Cell中加入直播链接等播放基本信息,并设置五分钟强制刷新逻辑,点击Cell后立刻使用已有的播放链接进行播放,同时请求最新的房间信息后进行比较,若无差别则只刷新其他房间信息不重新初始化播放器,若不一致则使用最新播放链接进行播放。

(2)消除初始化SDK的时间

将播放SDK改为单例,并提前设置好直播间参数。

(3)消除DNS解析时间

使用HttpDNS独立获取推流服务器IP,并设置定时刷新缓存逻辑,获取播放链接后直接使用IP直联推流服务器。

如图所示,在改进的任务模型中,直播间首帧渲染任务会分为三个并行的队列执行。

(1)在APP启动后不依赖用户点击就初始化播放器SDK并设置播放参数,对直播Cell中的播放链接进行DNS解析,获取当前网络环境对应下响应最快推流服务器IP。

(2)用户点击后立刻将直播Cell中的播放链接配置到播放器SDK中,开始拉取首帧数据,并及时上屏显示。

(3)在播放器SDK拉取首帧数据时并行加载直播间UI,并拉取最新的播放链接等直播间播放信息,若最新的播放链接与Cell中缓存的播放链接一致,则继续播放,若不一致则立刻替换播放链接。

改进的直播间首帧渲染方案在用户点击后立刻执行了数据拉取和上屏任务,并通过直播列表定时刷新保证了缓存链接和最新链接的匹配率(90%以上)。

3. 典型耗时方法的优化

3.1 首次打开直播间耗时的元凶——imageNamed方法

通过TimeProfile可以看到,首次打开直播间仅仅是加载本地icon,就消耗了超过500ms,这是个可怕的数字,必须解决掉。经过分析,有三种情况可能出现这种异常耗时。

  1. 启动APP,首次进入直播间,耗时巨大
  2. 前后台切换后首次进入直播间,耗时巨大
  3. 横竖屏切换后可能会耗时增加

而问题的原因则是因为图片没有放在苹果推荐的assets中并且使用UIImage imageNamed:iconName来加载图片,具体为什么会造成这种异常耗时后续会有文章进行详细的分析,至于解决方案则是简单的移到assets中并替换相关图片地址即可。

3.2 不起眼的耗时累计

在早期版本的产品中,没有对上报进行统一的梳理和优化,各种技术和产品上报散落各个地方,有些直接在主线程进行了上报,一点点累计下来,上报也有了毫秒级的阻碍,通过将上报合并后放在子线程执行可解决上报造成的首帧延迟。

4. 拆分耗时函数

拆分秒级的巨大函数,将一个runloop拆分为多个runloop

在将串行队列改为并行队列后,发现体验上仍存在很多问题

(1)点击到直播间Push这段时间很长

分析后发现是在viewDidLoad中加载了过多的UI元素,很多UI如后四个Tab、等第一时间不会显示的UI控件也进行了加载,这是完全不必要的,因此将viewDidLoad方法进行了精简,只加载了界面主框架即播放器和Tab名称,不可见UI元素进行了延迟加载。

(2)直播间刚刚push出来的时候右滑返回也是无法响应的,查看了一下主线程的耗时,发现在拉取到直播间信息之后多个业务模块的更新写在了一个巨大的函数中,整个函数耗时超过了1秒,这是完全无法接受的,但各个模块累计下来的耗时不管怎么优化也不可能降低到1秒以下,因此在总耗时一定的情况减少持续卡住主线程的时间成为了我们的目标。

在这里通过监控iOS中Runloop的空闲状态实现了这个目标,通过将巨大耗时方法拆分为每个模块的小方法,并保存中Block队列中,在Runloop空闲时每次执行队列中的一个任务,这样Runloop的间隙中手势和上屏等操作都是可以及时响应的。

// 添加任务到Block队列中

- (QGRunloopTaskDistribution * (^)(RunloopTaskBlock runloopTask))addTask {
    __weak typeof(self) weakSelf = self;
    return ^(RunloopTaskBlock runloopTask) {
        [weakSelf.taskArray addObject:runloopTask];
        return weakSelf;
    };
}

// 检测Runloop空闲状态
- (void)addRunloopObserver:(QGRunloopTaskDistributionTaskPriority)runloopLevel {
    CFRunLoopRef runloop = CFRunLoopGetCurrent();
    CFRunLoopObserverRef observer;
    CFRunLoopObserverContext context = {
        0,
        (__bridge void *)(self),
        &CFRetain,
        &CFRelease,
        NULL,
    };

    observer = CFRunLoopObserverCreate(CFAllocatorGetDefault(),
                                       kCFRunLoopBeforeWaiting | kCFRunLoopExit,
                                       YES,
                                       0,
                                       &runLoopObserverCallBack, &context);

    CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes);
    CFRelease(observer);
}

// 空闲时执行队列中的任务
static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    QGRunloopTaskDistribution *runloop = (__bridge QGRunloopTaskDistribution *)info;
    if (runloop.taskArray.count != 0) {
        RunloopTaskBlock task = runloop.taskArray.firstObject;
        task();
        [runloop.taskArray removeFirstObject];
    }
}

原创声明,本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

登录 后参与评论
0 条评论

相关文章

  • 安卓Webview网页秒开策略探索

    webview初始化->DOM下载→DOM解析→CSS请求+下载→CSS解析→渲染→绘制→合成

    Rouse
  • app直播源码“助力”直播架构,走上探索之路

    对于直播app的开发来讲,app直播源码是一个非常重要的存在。直播架构在开发过程中也是一件非常重要的事情,如果架构的设立不能从根本上解决问题或防止问题的发生,那...

    肉2466131704
  • 直播半天打不开,你的秒开该优化了

    所谓的拉流秒开意思,就是当我们在播放器点击播放到看到画面出来这个延时时长,最近有很多客户在对接云直播的时候咨询了如何优化秒开,今天把问题原因和优化方案总结一下,...

    腾讯云音视频
  • 直播半天打不开,你的秒开该优化了

    所谓的拉流秒开意思,就是当我们在播放器点击播放到看到画面出来这个延时时长,最近有很多客户在对接云直播的时候咨询了如何优化秒开,今天把问题原因和优化方案总结一下,...

    陈超 - Danny
  • Webview秒开探索:让你的H5“快人一步”

    如今的前端技术层出不穷,无论是react、vue等框架还是跨端解决方案,为使用场景和开发效率做了不少的提升,但作为前端技术的重要衡量指标之一,首屏渲染效率无疑前...

    南山种子外卖跑手
  • 新内核EasyNVR平台配置的直播秒开未生效情况的解决办法

    直播秒开是指从视频播放开始到真正看到第一帧画面所消耗的时间要尽可能的短,不能让观众有明显的等待时间。EasyNVR也支持直播秒开功能,对于非按需、不间断的推流直...

    EasyNVR
  • 新内核EasyNVR平台配置的直播秒开未生效情况的解决办法

    直播秒开是指从视频播放开始到真正看到第一帧画面所消耗的时间要尽可能的短,不能让观众有明显的等待时间。EasyNVR也支持直播秒开功能,对于非按需、不间断的推流直...

    TSINGSEE青犀视频
  • 直播答题狂撒币,这些“AI开挂神器”如何在10秒内算出正确答案?

    镁客网
  • 移动视频变现遇西西弗斯魔咒?一下科技一鸡多吃开启新“钱”途

    不论是陌陌最新财报中营收、利润五六倍的增长,还是微博依托内容战略重返互联网中心舞台,都在传达一个再明显不过的信号:短视频和直播为主的内容形式已是推动互联网行业市...

    罗超频道
  • IPO前夕快手招销售卖广告,如何突破30亿美元的估值?

    近日,据自媒体“开柒”爆料,快手已基本确定在明年内上市,其已启动上市前大规模招聘,招聘广告销售加速变现步伐。今年初就有消息传出快手即将IPO,其一直按兵不动的原...

    罗超频道
  • 7月23日 | 第三届腾讯运维技术开放日,一起拥抱云原生

    你以为互联网人的极致是 996 吗?其实,有这么一批人是007! 7x24 小时全天超长“待机”,全年午休。因此,把7月24日定为他们的专属节日——这就是运维。...

    腾讯云原生
  • 腾讯云快直播——超低延迟直播技术方案及应用

    随着直播业务的发展,在线教育,连麦直播、赛事直播等高实时性直播场景的出现,用户对于直播流畅度、低延迟等性能的要求愈加严苛。腾讯云直播技术高级工程师陈华成 从5G...

    腾讯云音视频
  • 腾讯云直播服务评测

    2020年注定是魔幻的一年,疫情让我们更热爱生命,也让我们更珍视工作。今年的五一假期比往年多了两天,但在这个特殊的年份的特殊的劳动节中,工作和这个假期更配哦!小...

    视界音你而不同
  • 精选腾讯技术干货200+篇,云加社区全年沙龙PPT免费下载!

    “看一看”推荐模型揭秘!微信团队提出实时Look-alike算法,解决推荐系统多样性问题;

    风间琉璃
  • 七牛云技术分享:使用QUIC协议实现实时视频直播0卡顿!

    不做任何开发,就能实现弱网环境下实现实时视频直播零卡顿,听上去是不是天方夜谭?看完这篇文章你就知道,我们是如何做到的。

    JackJiang
  • 深开鸿新闻直播间首次开播:共同见证时代成长全历程

    2022年4月22日19:00,深圳开鸿数字产业发展有限公司(以下简称“深开鸿”)新闻直播间首次开播。 深开鸿总裁 周子翔先生首次开播寄语 作为深开鸿的新闻发...

    云头条

扫码关注腾讯云开发者

领取腾讯云代金券