Web 音视频开发趟坑指南

本文涉及的产品
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 这不是一篇基于 MSE 开发 Web 播放器的入门文章,而是围绕 Web 播放器开发遇到的常见 问题与解决方案,毕竟入门文章常有而趟坑干货不常有。如果您有 Web 播放开发经验和音视频 技术基础,读起来会更有共鸣。

作者| 阿里文娱前端技术专家 归影

这不是一篇基于 MSE 开发 Web 播放器的入门文章,而是围绕 Web 播放器开发遇到的常见 问题与解决方案,毕竟入门文章常有而趟坑干货不常有。如果您有 Web 播放开发经验和音视频 技术基础,读起来会更有共鸣。

一、Web 播放器开发基础知识

先介绍 Web 播放器开发的一些基础知识。有人要问了,Web 播放器开发难道不是一个 video 标签就够了么?非也!

1.浏览器 Video 支持的格式非常有限

在 W3C 的标准里面 Video 只支持 MP4 格式 准确的说是 ISOBMFF(Fragment MP4)。当然 chrome 支持 WEBM,safari 支持 HLS(MPEG-TS)这都是自家的私有实现,做不得数。

2.浏览器 Video 无法逐个加载视频切片

现在主流的流媒体点播/直播技术,都会把视频切片。而 video 标签 src 只能挂载整个 MP4
资源。没法逐个的加载视频分段。
所以我们的主角出场—— MediaSource Extenstion,简称 MSE,是一套能不断的把音视频 二进制数据塞给 video 标签播放的 API。

image.png

(图 1:MSE 简明结构)

MSE 内部可以创建一系列的 sourcebuffer,一般是一个音频 buffer,一个视频 buffer。把 MSE 做成 blob url 之后绑定给 video 的 src。然后就可以通过appendBuffer 往 video 里追加音视频数据了。有了 MSE,播放器器的整体结构是什么样的呢,见下图。

image.png

(图 2:Web 播放器简明结构)

首先在浏览器层面,主要使用 video 标签、MSE、XHR 和 UI。
那么播放器主要由 Manager 驱动加载视频的playlist(比如 HLS 里的 m3u8,dash 里的 MPD, FLV 虽然不是 playlist 概念,但是是原理上差别不大,都是为了拿到视频的一个个的片段的地址), 并通过数据服务加载这一个个的分片。然后通过 transmuxer 也就是所谓的转封装器,把分片的 封装格式比如 TS 拆开(demux) 把连原始的音视频数据解出来,再重新打包成 fmp4(remux), 最后通过 MSE API 喂给 video 标签里,让 video 去播放。
因此播放器所做的事情最主要有两点:
1)转封装。即将 video 不支持的封装格式转码成 video 所支持的封装格式;
2)如何驱动整个播放进行。即决定何时下载下一个分片,何时需要解码插入到 video 的 buffer 里。

二、时间戳对齐

转封装除了的封装格式的解复用(demux)和再复用(remux)之外最重要的环节就是分片的 时间戳对齐策略,以及音视频同步。

image.png

图 3(传说中的“开局一张图 原理全靠猜”)

简单讲一下上图:
红色代表音频的时间轴。蓝色/青色是视频的时间轴。PTS(Presentation Time Stamp) 指的是 这一帧需要渲染的时间。 DTS(Decoding Time Stamp) 指的是这一帧需要解码的时间。

1.首片首帧的对齐策略

正常来说音频 PTS 和 DTS 是一样的,而视频如果有 B 帧的话 DTS 往往要比 PTS 早一些(因 为要预留一定的时间解码)。因此视频的首帧会有一个洞(gap/shift 随便你怎么叫),如果不经处理插到 video 里,那么 video 里的 buffer 也会呈现出一小段的洞,一般是 0.08s(比如 10s 的分片 插 进去可能出现 0.08~10.08 的情况)。现在主流的做法是削掉这个洞。就是把 DTS 跟 PTS 强行拉 平,一般来说 chrome 不会出现太大的问题。但是 safari 不行,如果不预留一定的 DTS/PTS 偏 移,safari 前两帧的播放会明显卡顿。

2.后续对齐策略

后续分片的对齐,会通过 DTS/PTS 两个尾部指针来做。如果发现后续分片时间轴有间隔就 往前推从而填上间隔。如果发现重叠,就把重叠帧后移。这样虽然会导致后续分片的前几帧重叠。但在播放的过程中几乎没有影响。

三、音视频同步

首先,什么情况下会导致音画不同步?
1)视频源流压根没对齐。没救了,看下一点。
2)还是因为有洞。很多时候视频切出来的每个分片之间都不一定是严丝合缝的,分片间的 音视频时间戳可能有洞。而且对于 TS 由于音频每一帧的duration(≈23ms) 跟视频每一帧的duration(40ms@25fps) 无法吻合(整除) 所以加剧了这种参差不齐的情况。 那么,重点来了!chrome 有个特殊的机制,如果发现音频之间有洞之后,为了保证音频的平顺, 会自动把后续音频往前推抹平这个洞。如果每个分片都有洞,悲剧了,这种往前推的操作就会 积累越来越多导致音视频不同步。
小 tips:
打开 chrome 的媒体调试页面 chrome://media-internals 可以看到媒体播放相关的所有 debug 信息和 error 信息非常有用。其中就会有一条关于音频处理的提示:
当然这条显示的具体原因是自动切掉重叠 overlap 导致的。其实 gap/overlap 本质是一样的。 怎么办?当然是播放器自己主动把洞填上。具体做法是插帧。目前主要是插静音帧,或者复制 前一帧。静音帧会带来毛刺音,复制帧会导致拖音。我们目前的优化方案是判断附近的音频数 据量,数据量大时说明此处声音丰富(其实不算靠谱,姑且这么处理,因为没有更好的判断方式), 如果插静音帧会毛刺很明显,所以此时用复制帧,反之插静音帧。

四、那些年我们躺过的坑

1.不同版本表现差异 容忍度不同

1)Chrome 35 分水岭。chrome35 之前要求关键帧之后的第一帧 dts 不允许跟关键帧 dts 相 同,否则抛错。
2)低延迟的模式。把转封装出来的 FMP4 中的视频轨 duration(tkhd box) 设置成 0xffffffff 时 会让 chrome 认为这是直播流,会开启低延迟模式,所谓低延迟模式就是会极大的减少帧缓存, 基本上视频帧立马解码立马播放减少每个分片的起播延迟。但是呢在 CPU 负载过高的情况下(解不过来)会造成视频频繁卡顿(网络无关的)。

2.不同浏览器表现有差异

1)timeupdate 事件。W3C 的标准是不能超过 250ms 触发一次。windows 下 360 等浏览器会 达到 500ms 左右。
2)safari 对每一帧 duration 平顺度更敏感。safari 需要对每一视频帧的 duration 标准化处理, 例如 TS 下要处理成 3600。
3)对洞的容忍度不同。chrome 遇到 buffer 中有 0.08 的间隔以内会自动跳过去。像 IE edge 等浏览器不行会卡住,所以播放器一定要有跳洞逻辑。比如判断当前卡在洞的边界,要主动跳 过去(seek)。

3. 内存限制

通过 MSE push 给 video 的视频数据会在内部维护一个 buffer,这个尺寸是有限制的。
1)chrome 系列约 100M 2)IE 系列约 30M
超过的话就会导致抛出 QuotaExceededError。所以需要处理好 buffer 的尺寸以及及时清除 不用的 buffer。比如已经播放过的,正常浏览器会自己清除,但是不那么的及时。

五、优化

简单说一下卡顿相关的优化。
 多级 Buffer 控制
 ABR 自适应码率算法
 基于 WebRTC 的 P2P

1.多级 buffer

为什么要有多级的 buffer?因为 video 本身的解码 buffer 有大小限制,而且 buffer 过长会导 致长时间解码,会导致 CPU 一直占用高。所以我们搞了两级 buffer 一级就是 video 的 buffer 另 外一级是内存中的,只负责下载,二级很长。可以消除网络抖动带来的卡顿影响。

2.ABR 自适应码率的算法

这个主要是来预测用户本身的带宽范围,然后选用不同码率的视频流来无缝切换播放。当 然还有一些策略算法,比如根据用户现在 buffer 的水位,或者检测到用户频繁超时,来采用不 同的策略。

3.基于 WebRTC 的 P2P

因为 P2P 是基于 UDP 的传输,可以突破一些带宽限制或网络拥塞而导致的卡顿问题。不 过 P2P 不一定靠谱所以还是要辅以普通的 HTTP 传输相结合。我们一般是利用 P2P 加 indexDB 来变相延长视频的缓冲区。因为 P2P 带宽成本便宜,我们利用 P2P 做了一个非常长又很便宜的 buffer。这样的话网络再波动也不会导致卡顿了。

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
18天前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
78 3
|
2月前
|
数据库 开发者 Python
web应用开发
【9月更文挑战第1天】web应用开发
50 1
|
1天前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
15 2
WK
|
1天前
|
安全 Java 编译器
C++和Java哪个更适合开发web网站
在Web开发领域,C++和Java各具优势。C++以其高性能、低级控制和跨平台性著称,适用于需要高吞吐量和低延迟的场景,如实时交易系统和在线游戏服务器。Java则凭借其跨平台性、丰富的生态系统和强大的安全性,广泛应用于企业级Web开发,如企业管理系统和电子商务平台。选择时需根据项目需求和技术储备综合考虑。
WK
7 0
|
24天前
|
设计模式 测试技术 持续交付
开发复杂Web应用程序
【10月更文挑战第3天】开发复杂Web应用程序
31 2
|
26天前
|
Java PHP
PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。理解其垃圾回收机制有助于开发高效稳定的PHP应用。
【10月更文挑战第1天】PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。其垃圾回收机制包括引用计数与循环垃圾回收,对提升应用性能和稳定性至关重要。本文通过具体案例分析,详细探讨PHP垃圾回收机制的工作原理,特别是如何解决循环引用问题。在PHP 8中,垃圾回收机制得到进一步优化,提高了效率和准确性。理解这些机制有助于开发高效稳定的PHP应用。
39 3
|
3天前
|
JavaScript 前端开发 Java
SpringBoot_web开发-webjars&静态资源映射规则
https://www.91chuli.com/ 举例:jquery前端框架
9 0
|
2月前
|
数据可视化 图形学 UED
只需四步,轻松开发三维模型Web应用
为了让用户更方便地应用三维模型,阿里云DataV提供了一套完整的三维模型Web模型开发方案,包括三维模型托管、应用开发、交互开发、应用分发等完整功能。只需69.3元/年,就能体验三维模型Web应用开发功能!
270 8
只需四步,轻松开发三维模型Web应用
|
2月前
|
安全 API 开发者
Web 开发新风尚!Python RESTful API 设计与实现,让你的接口更懂开发者心!
在当前的Web开发中,Python因能构建高效简洁的RESTful API而备受青睐,大大提升了开发效率和用户体验。本文将介绍RESTful API的基本原则及其在Python中的实现方法。以Flask为例,演示了如何通过不同的HTTP方法(如GET、POST、PUT、DELETE)来创建、读取、更新和删除用户信息。此示例还包括了基本的路由设置及操作,为开发者提供了清晰的API交互指南。
101 6
|
2月前
|
存储 JSON API
实战派教程!Python Web开发中RESTful API的设计哲学与实现技巧,一网打尽!
在数字化时代,Web API成为连接前后端及构建复杂应用的关键。RESTful API因简洁直观而广受欢迎。本文通过实战案例,介绍Python Web开发中的RESTful API设计哲学与技巧,包括使用Flask框架构建一个图书管理系统的API,涵盖资源定义、请求响应设计及实现示例。通过准确使用HTTP状态码、版本控制、错误处理及文档化等技巧,帮助你深入理解RESTful API的设计与实现。希望本文能助力你的API设计之旅。
61 3