播放器秒开优化

开篇

先说结论:

字节跳动就曾给出过一份数据:对一部分型号的 Android 手机,播放首帧时长从平均 170ms 优化到 100ms,带来了 0.6% 左右的用户播放时长提升。

衡量指标:

  • 播放秒开率,指的是播放器开始初始化到视频第一帧画面渲染出来的时间不超过 1s 的次数在总的播放次数中的比例。
  • 播放平均首帧时长,指的是播放器开始初始化到视频第一帧画面渲染出来的平均耗时。

回归探讨,首先要搞明白从数据到播放器都经历了什么,再逐个讨论优化点。

我们大致可以分为下面几个阶段:

  • 业务侧结合优化
  • DNS 解析
  • TCP 连接
  • HTTP 响应
  • 音视频探测
  • 音视频解码
  • 缓冲和起播策略
  • 渲染

业务侧结合优化

首先要看客户端上进入直播间的业务场景是什么样的?一般而言,都是从一个直播列表页面,点击某一个直播卡片(Cell)即进入直播间。

优化点:

1. 提前获取直播流地址
2. 结合 HTTPDNS 选择最佳 CDN 节点
3. 使用 URL 替代 VID
   - 将视频 URL 直接封装在 Model 中,避免多一次请求 URL 的时间开销。
4. 上下滑短视频提前加载播放器:
5. 封面图清晰度降级:
   - 当预加载、预渲染等优化做的较好时,封面图可以适当降低清晰度,节省带宽和流量。
   - 可以优先做预加载预渲染,在必要时才加载封面图。

DNS 解析

获取到直播流地址,需要进行dns解析得到www.ip+port/资源路径。这步优化就是构建dns缓存池,避免去运营商解析这个过程。DNS解析可以在几十毫秒到几百毫秒内完成,本地的话可以保证稳定再几十毫秒。

1. 优化 DNS 解析过程:
           -统计 DNS 解析耗时。没有缓存命中时,DNS 解析通常需要 300ms 以上的时间。有缓存命中则耗时很短。 DNS 解析耗时较长的原因是需要递归到根域名服务器查询。

//libavformat/tcp.c 文件中的 tcp_open
int64_t start = av_gettime();
if (!hostname[0])ret = getaddrinfo(NULL, portstr, &hints, &ai);
elseret = getaddrinfo(hostname, portstr, &hints, &ai);
int64_t end = av_gettime();

        - 没采用ipv6地址,需要设置只查询ipv4。

hints.ai_family = AF_INET;

        - 采用 HTTPDNS 和 LocalDNS 结合的方式可以提升 DNS 解析速度和准确率。在 App 启动时预解析热门域名,缓存在本地。
2. 实现 HTTPDNS:
     - 方案一是 IP 直连,将域名解析到的 IP 直接嵌入到 URL 中。(建议使用nginx作为中间层即可避免。)但存在两个问题:
     1. 如果服务端采用 302/307 跳转,客户端依然IP 直连,造成客户端没正确使用跳转ip导致url资源定向错误。
     2. 使用 HTTPS 时,证书验证会失败。

AVDictionary **dict = ffplayer_get_opt_dict(ffplayer, opt_category);
av_dict_set(dict, "headers", "Host: www.example.com", 0);

         - 方案二是替换 FFmpeg 的 DNS 实现,自行实现 HTTPDNS 解析逻辑。常见的做法是做一层播控服务,客户端请求播控服务获取到实际的播放地址以及各种其他的信息,然后再走 IP 直连就没问题。

//tcp.c 中 getaddreinfo
if (my_getaddreinfo) {ret = my_getaddreinfo(hostname, portstr, &hints, &ai);
} else {ret = getaddrinfo(hostname, portstr, &hints, &ai);}


3. 提升 HTTPDNS 的有效率:
   - 在网络切换、滑动场景、内部刷新操作时,之前缓存的 HTTPDNS IP 可能会失效。
   - 可以实现一个轮询机制,定期更新 HTTPDNS IP 的缓存,保证 IP 的有效性。
   - 同时要处理各种网络切换或内部刷新时更新 IP 缓存的情况。

        DNS 优化是网络优化的重点,通过 HTTPDNS 和 LocalDNS 结合使用,可以大幅降低 DNS 解析耗时,从而优化首屏时间。

TCP 连接

1. 优化 TCP 建连耗时:
   - TCP 建连耗时反映了客户端到 CDN 服务器节点的点对点延时情况。
   - 它主要受限于三个因素:用户网络条件、用户到 CDN 边缘节点链路、CDN 边缘节点的稳定性。
   - 可以结合用户所在城市、运营商情况, 优化 CDN 调度, 使用 HTTPDNS 给用户分配更优的连接链路, 从而优化建连耗时。

2. 通过 TCP Fast Open (TFO) 优化 TCP 建连时长:
   - TFO 是对 TCP 三次握手的简化, 可在握手过程中交换数据, 减少一次 RTT。
   - TFO 流程包括:首次请求获取 Cookie, 后续连接携带 Cookie 进行验证和快速建连。
   - TFO 可减少 15% 的 HTTP 传输延迟, 全页面下载时间平均节省 10%, 最高可达 40%。

3. 通过 TCP 预连接和连接复用优化建连时长:
   - 缓存 IP 对应的 Socket 连接, 提供预连接接口给业务层使用。
   - 业务层可对下一个直播间提前做预连接, 真正拉流时复用这个连接。
   - 可对高频域名持续预连接, 提高预连接命中率。需注意网络切换时刷新缓存。

4. 避免首帧网络带宽争抢:
   - 在实现第三点基础上,且短视频上下滑场景, 快速滑动时可能会导致预加载的视频数据未被使用, 反而占用了后续视频的首帧带宽。
   - 可检测到快速滑动时, 及时中断预连接的 Socket, 避免带宽争抢。

HTTP 响应

优化 HTTP 响应耗时:

  • 如果请求有缓存命中, 响应时间一般在 50-200ms 左右。

提升 CDN 边缘节点命中率:

  • 避免在 URL 参数中带有随机值, 否则会降低缓存命中率。

  • 服务端可对热门内容进行预热, 提高边缘节点的缓存命中率。

优化短视频第一次 Get 请求:

  • 设置 HTTP 请求的 Range =文件长度 来省去第一次 Get 请求, 优化首帧时长。

音视频探测

5.1 优化音视频流探测耗时

- 直播业务中,视频流格式通常是固定的,无需复杂的探测过程:
  - 可以在播放器中直接读取固定的信息,开始播放,无需经过耗时的 avformat_find_stream_info() 函数。
- 针对 avformat_find_stream_info() 函数的优化:
  - 在外部设置较小的 probesize 和 analyzeduration 参数,这两参数决定控制该avformat_find_stream_info 读取的数据量大小和分析时长,频率越高,延时越低。

av_dict_set_int(&ffp->format_opts, "fpsprobesize", 0, 0);


  - 服务端标准化转码,确定视频格式,计算出最小的 probesize 和 analyzeduration。
  - 直接修改 avformat_find_stream_info() 的实现逻辑,针对固定格式进行优化。
  - 尝试去掉 avformat_find_stream_info() 步骤,自定义初始化解码环境。

5.2 短视频前置 moov box

- 在网络点播场景下,如果 MP4 视频的 moov box 在文件尾部,会导致播放器需要下载完整个文件才能开始播放。

- 可以在服务端使用 FFmpeg 将 moov box 移动到文件头部,优化播放体验:

 ffmpeg -i bad.mp4 -movflags faststart good.mp4

5.3 提前创建解码器
- 对于直播场景尤其有效,因为视频格式比较固定

音视频解码

6.1、提前创建解码器

播放器可以创建一个解码器复用池,当解码参数一致时,可以复用解码器。这样一来,业务也可以透传给播放器码流相关的信息,让播放器提前创建解码器来降低播放器首帧渲染时间。

解码器需要的信息通常包括:SPS、PPS、VPS(H.265)。

6.2、优化解码器刷新操作

IJKPlayer 播放器在完成音视频探测后,开始进行解码时,如果使用硬解,解码器会在开始做一次刷新解码器的操作,这个操作其实没有必要,但是会有一定的耗时,影响首包到渲染时长。去除这一次刷新操作,首帧时长收益 10-20ms。

缓冲区和起播策略

7.1 优化 Buffer 填充耗时

ffmpeg优化参数:BUFFERING_CHECK_PER_MILLISECONDS 减少检查缓冲区填充情况的时间间隔,从 500ms 降低到 50ms,可以减少 200ms 左右的缓冲耗时

MIN_MIN_FRAMES 最小帧处理。从 10 帧降低到 5 帧,首屏时间可减少 300ms 左右,且卡顿率只上升 2%。

7.2 流媒体服务器侧 GOP 缓存

具体gop指标,可参考下列文章设置。

基于 http-flv 的端到端延迟优化-CSDN博客

7.3 服务端快速下发策略

- CDN 服务端可以配置快速启动模式,在拉取直播流时以 5 倍于平时的带宽速度下发前 1 秒的数据,优化首屏秒开速度。速度提升 100ms 左右

7.4 提升 HLS 的播放秒开

- 直接开播:播放器策略影响大,如 iOS AVPlayer 需要 3 个 ts 切片才开始播放,IJKPlayer 使用水位线策略更快。
- 开播 Seek:IJKPlayer 支持 seek-at-start 能力,可直接下载目标位置数据而不需从头加载;服务端可以根据内容打点切成多个 m3u8,优化 Seek 响应速度。
- 解决 HLS Seek 黑屏问题:stream 的 first_timestamp 未正确初始化,导致无法找到 Seek 位置;IJKPlayer 需要解决跨断层 ts Seek 问题。

7.5  IJKPlayer 优化 

设置 Surface 时重置解码器的等待时长

- 在没有设置 Surface 时,让解码器线程直接等待,而不进入加锁的取 buffer 操作,避免后续设置 Surface 时因等待锁而造成的延迟。

7.6 视频预加载

- 提前下载一部分视频数据,达到快速起播的目的。但需要结合业务场景,调试出最合适的预加载策略。

7.7 视频本地缓存

- 将视频数据缓存到本地,下次播放时可直接从本地请求,节省带宽,提升首帧秒开速度。
- 需要考虑视频数据分片管理和缓存清理策略。

综合运用上述优化手段,可以大幅提升播放器的首帧渲染和秒开性能。

渲染

8.1 播放器预渲染

  • 在拿到视频 URL 后就开始进行 prepare 操作,进行解封装、解码和渲染,待首帧渲染完成后即可等待 play 指令播放。

  • 预渲染可以优化掉解封装、解码和渲染的耗时,但会给 CPU 和 GPU 带来额外消耗,需要根据机型性能选择性开启。

  • 如果同时开启了预加载,还需要进行策略优化,协调好预加载和预渲染的时机和流程。

8.2 预渲染首帧代替封面图

  • 使用播放器预渲染的首帧来代替传统的封面图,可以节省封面图下载的流量,降低下载封面图导致的带宽争抢。

  • 但需要有一个兜底策略,比如当预渲染未完成时,再选择加载封面图。

总结

结合公司实力进行优化,优先考虑缓存提速比如dns http这类连接耗时,tcp改进为fast open,cdn gop缓存机制这个较为重要。其次ijkplay源码,流媒体更改为格式固定版本,去除协议探测耗时。其次考虑源码参数,比如播放器缓存队列启动大小,引入池化技术。

参考文献

播放器秒开优化丨音视频工业实战-腾讯云开发者社区-腾讯云

学习资料分享

0voice · GitHub

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/889125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker nginx 部署vue 实例

1.安装docker https://blog.csdn.net/apgk1/article/details/144354588 2. 安装nginx docker 安装 nginx-CSDN博客 3. 复制 nginx-test 实例的一些文件到宿主机中,目前已 /home/jznh/路径演示 3.1 在/home/jznh/ 创建 conf html logs 三个文件夹,…

技术人员需要成为的八边形战士

那天偶然看到一个标题:脾气好,技术佳,哪个程序员这么宝藏?我没有点进去看内容,但是心里在琢磨一件事:10年前这种宝藏程序员很难得,现在的市场,恐怕不够。恐怕市场在找的都是下面技能…

VLDB 2024 | 时空数据(Spatial-temporal)论文总结

VLDB 2024于2024年8月26号-8月30号在中国广州举行。 本文总结了VLDB 2024有关时空数据(time series data)的相关论文,主要包含如有疏漏,欢迎大家补充。 🌟【紧跟前沿】“时空探索之旅”与你一起探索时空奥秘&#xf…

【推荐算法】单目标精排模型——FiBiNET

key word: 学术论文 Motivation: 传统的Embedding&MLP算法是通过内积和Hadamard product实现特征交互的,这篇文章的作者提出了采用SENET实现动态学习特征的重要性;作者认为简单的内积和Hadamard product无法有效对稀疏特征进行特征交互&a…

Windows中将springboot项目运行到docker的容器中

0,先打包好项目,再启动docker 1,在Java项目根目录下创建一个名为Dockerfile的文件(没有扩展名),并添加以下内容。 # 使用OpenJDK的基础镜像 FROM openjdk:8-jdk-alpine# 设置工作目录 WORKDIR /app# 将项…

GB28181系列一:GB28181协议介绍

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、GB28181协议介绍 二、GB28181交互流程 1、注册 2、观看视频 3、控制 4、SDP 5、媒体保活: 6、RTP 7、SIP URL 一、GB28181协议介绍 GB28181使用SIP协议,SIP协议参考我的SIP系列&a…

【C++指南】类和对象(七):友元

💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《C指南》 期待您的关注 目录 引言 🍃友元的介绍 🍃友元函数 🍃友元类 🍃相关…

【leetcode】替换后的最长重复字符、将字符串翻转到单调递增

1.替换后的最长重复字符 示例如下: 下面我们来分析一下一个例子,其中K 2 暴力枚举 这里的字符串s是仅由大写字母组成,首先我们尝试用暴力解法的思路来想一下这道题,通过从第一个字符开始进行枚举,如果出现了条件判断…

广州大学acm新生赛

#include <iostream> #include <unordered_map> #include <unordered_set> #include <map> #include <string> #include <vector> #include <algorithm> using namespace std;// 定义存储每个队伍的相关数据结构 struct TeamData {i…

【PyQt5教程 四】Qt Designer 样式表(styleSheet)实现基本小部件的自定义动态效果和资源浏览器背景添加方法

目录 一、成果演示&#xff1a; 二、样式表的使用方法: &#xff08;1&#xff09;样式表语法和属性&#xff1a; &#xff08;2&#xff09;样式表代码示例&#xff1a; &#xff08;3&#xff09;伪类和状态&#xff1a; &#xff08;4&#xff09;复合选择器&#xff…

【C++】输入三个整数,输出最大值的高级分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;问题描述&#x1f4af;解题思路&#x1f4af;实现与分析方法一&#xff1a;三元运算符的直接应用详细分析&#xff1a;优缺点剖析&#xff1a; 方法二&#xff1a;显式条件…

基于python+django+vue的高校成绩管理系统

系统展示 管理员后台界面 教师界面 学生界面 系统背景 随着教育信息化的不断推进&#xff0c;传统的手工成绩管理方式已经无法满足现代教育管理的需求。传统管理方式不仅效率低下&#xff0c;还容易出错&#xff0c;且难以实现数据的集中化管理和安全访问控制。因此&#xff0c…

怎么为开源项目做贡献提PR?

GitHub 慢的话&#xff0c;https://ask.csdn.net/questions/8166374 复刻项目 以 https://github.com/open-frame/uniapp-init 项目为例 复刻完就会在你的仓库里有个同样的项目 拉取复刻下来的项目 然后常规的改动项目、git推送。比如我改了一个忽略文件&#xff1a; 提交…

记录:ubuntu 使用chattts的过程。

你知道什么是穷人吗&#xff1f;穷人就是没钱还想学习。 git GitHub - 2noise/ChatTTS: A generative speech model for daily dialogue. 因为所以。cosyvoice&#xff0c;gpt-s . 0.先找一个目录吧。 1.命令行模式 duyichengduyicheng-computer:~/gitee$ git clone https:…

vulnhub靶场【hacksudo】之LPE的后续提权方法学习

前言 靶场&#xff1a;hacksudo-lpe的后几个challenge 基于上篇靶场hacksudo-ple的sudo提权 SUID文件提权 ar文件提权 使用find寻找具有SUID权限的文件 find / -perm -us -type f 2>/dev/null查看ar的SUID用法 sudo install -m xs $(which ar) .TF$(mktemp -u) LFILE&…

【 C语言练习(4)—可自己设置游戏规则的猜数字游戏】

C语言练习&#xff08;4&#xff09; 文章目录 C语言练习&#xff08;4&#xff09;前言题目题目解析结果总结 前言 本次写的猜字游戏有两大优点&#xff0c;可重复玩游戏、可自己设置猜数字规则&#xff0c;通过猜数字游戏锻炼循环体和选择结构体 题目 写一个给定猜数次数&a…

【4】数据分析基础(pandas中的series 1)

学习目标2 pandas模块的学习。 pandas是一个基于NumPy的模块&#xff0c;它的功能在于数据的筛选清洗和处理&#xff0c;与NumPy模块相比&#xff0c;pandas模块更擅长处理二维数据。 pandas模块主要有Series和DataFrame两种数据结构。 接下来&#xff0c;我们先学习Series…

创建项目,并且上传到git

第一步 本地新建新项目 第二步 git上新建空项目 第三步 将本地项目添加为git项目 1、复制初始化命令 在新建项目中登录git 2、将本地项目设置为git项目 在IDEA中执行一下命令 3、完成上述操作&#xff0c;IDEA会将本地项目识别为git项目&#xff0c;就可以执行git commit操…

Cisco Packet Tracer | Cisco Packet Tracer - VLAN 实验 - 交换机的 VLAN 划分

关注这个工具的其它相关笔记&#xff1a;Cisco Packet Tracer —— 使用教程合集-CSDN博客 0x01&#xff1a;VLAN 划分 - 单个交换机 0x0101&#xff1a;拓扑搭建流程 从软件底部拖出一台交换机&#xff08;笔者选择的型号是 2960 IOS15&#xff09;&#xff1a; 然后再拖出四…

ICP和EDI许可证办理审核专用的网站系统源码程序下载—专供审核易过使用

在现代互联网及电子商务企业中&#xff0c;ICP许可证和EDI许可证不仅是法律要求&#xff0c;更是企业立足市场的重要基础。这两种许可证能够帮助企业爬梳合规问题&#xff0c;规避法律风险&#xff0c;并提升自身的信誉&#xff0c;增强客户的信任感。本文将详细介绍ICP许可证和…