Web 音视频开发趟坑指南

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 这不是一篇基于 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实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
19天前
|
监控 JavaScript 前端开发
《理解 WebSocket:Java Web 开发的实时通信技术》
【4月更文挑战第4天】WebSocket是Java Web实时通信的关键技术,提供双向持久连接,实现低延迟、高效率的实时交互。适用于聊天应用、在线游戏、数据监控和即时通知。开发涉及服务器端实现、客户端连接及数据协议定义,注意安全、错误处理、性能和兼容性。随着实时应用需求增加,WebSocket在Java Web开发中的地位将更加重要。
|
30天前
|
Web App开发 前端开发 开发工具
介绍Web开发的基础知识
介绍Web开发的基础知识
29 7
|
1月前
|
存储 资源调度 应用服务中间件
浅谈本地开发好的 Web 应用部署到 ABAP 应用服务器上的几种方式
浅谈本地开发好的 Web 应用部署到 ABAP 应用服务器上的几种方式
26 0
|
1月前
|
存储 前端开发 JavaScript
从前端到后端,探索现代Web开发技术
本文探索了现代Web开发技术的各个方面,包括前端和后端开发以及多种编程语言的应用。通过对JavaScript、Java、Python、C、PHP和Go等语言的介绍,深入探讨了前端和后端开发的基本原理和常用工具。同时,还涵盖了数据库技术在Web开发中的重要性和应用场景。无论你是初学者还是有经验的开发者,本文都能为你提供全面的视角和实用的知识,帮助你在Web开发领域取得更好的成果。
|
1月前
|
缓存 关系型数据库 API
后端开发:构建高效、可扩展的Web应用程序的关键
后端开发:构建高效、可扩展的Web应用程序的关键
20 0
|
4天前
|
JSON Java fastjson
Spring Boot 底层级探索系列 04 - Web 开发(2)
Spring Boot 底层级探索系列 04 - Web 开发(2)
15 0
|
4天前
|
安全 编译器 PHP
PHP 8.1版本发布:引领Web开发新潮流
PHP编程语言一直是Web开发的主力军,而最新发布的PHP 8.1版本则为开发者们带来了更多创新和便利。本文将介绍PHP 8.1版本的主要特性,包括更快的性能、新的语言功能和增强的安全性,以及如何利用这些功能来提升Web应用程序的质量和效率。
|
8天前
|
PHP
web简易开发——通过php与HTML+css+mysql实现用户的登录,注册
web简易开发——通过php与HTML+css+mysql实现用户的登录,注册
|
8天前
|
前端开发 数据挖掘 API
使用Python中的Flask框架进行Web应用开发
【4月更文挑战第15天】在Python的Web开发领域,Flask是一个备受欢迎的轻量级Web框架。它简洁、灵活且易于扩展,使得开发者能够快速地构建出高质量的Web应用。本文将深入探讨Flask框架的核心特性、使用方法以及在实际开发中的应用。
|
17天前
|
安全 前端开发 Java
Java Web开发知识点学习总结
Java Web开发涉及Java基础、Servlet、JSP、数据库操作(SQL+JDBC)、MVC设计模式、Spring框架、Hibernate ORM、Web服务(SOAP&RESTful)、安全认证(HTTP Basic/Digest/OAuth)及性能优化(缓存、异步、负载均衡)。
16 3