前端流媒体播放从入门到入坑

前端流媒体播放从入门到入坑最近好奇主流视频网站的播放器似乎不是我们习惯的video标签加上src属性上一个mp4的url,基本清一色的以blob:开头的一个纯前端的地址,鉴于此对前端的一些流媒体播放做了一些调研,写了这篇文章

最近好奇主流视频网站的播放器似乎不是我们习惯的video标签加上src属性上一个mp4的url,基本清一色的以blob:开头的一个纯前端的地址,鉴于此对前端的一些流媒体播放做了一些调研,写了这篇文章,顺便加了些在调研的过程中发现的一些有趣的现象一并写上,希望看过之后大家对流媒体播放有个基本的了解,本文尽量不涉及很多晦涩复杂的代码,我们只以大家都能在视频网站看得到的东西作为例子去讲解😂。OK, let’s go…

主流视频网站video的blob地址基本介绍

当你进入B站/爱优腾,YouTube/Netflix等视频网站,查看他们video标签上src地址,你会发现基本都是用的 Blob URL的形式:

B站地址:

<video src="blob:https://www.bilibili.com/c21f2f47-52fb-46e6-a943-f02e708bceac"></video>

油管地址:

<video src="blob:https://www.youtube.com/250d7dd2-a387-4024-9325-ed4842c5c3d0"></video>

bili-video-tag.png 通过上面MDN上的Blob介绍,以blog:开头的地址是通过以下方式生成:

// blob:https://www.youtube.com/250d7dd2-a387-4024-9325-ed4842c5c3d0
const objectURL = URL.createObjectURL(object)

上面的object参数可以为:File,Blob,或者MediaSource(然而IOS不支持,后面我们会看下IOS上这些网站一般怎么处理),
对于流媒体播放来说这里通过MediaSource(MediaSource Extension API)来创建Object URL。

视频容器格式、视频编码

了解了基本的创建方式之后,我觉得我们还是先回顾下视频的基础知识,有助于我们后面对于不同浏览器需要采用不同的流媒体格式的理解,简单来说视频容器格式就是我们平时看到的视频文件的后缀名如.mp4, .mov, .mkv等这些格式,说白了就是不同形式的盒子,至于里面装了什么取决于编码的不同,常见的如h.264(AVC), h.265(HEVC), vp9, av1等,h.264应该是目前用的最多的视频编码,当然除了视频编码还有对应的音频编码如AAC, 对应前面的AVC视频编码,同属于MPEG-4下面, 更多的视频格式及编码可以参考这个MDN地址

这里插入一个Mac上Safari无法播放油管4K视频的🌰(当然这个问题已在macOS 11 big sur上解决😎):

image.png

如上图可以看到在10.15及之前的Safari上没有选择1080P以上的清晰度,而在谷歌的亲儿子Chrome里面是没问题的,问题就出在视频的编码选择上,油管的1080P以上的如4K用的编码主要是vp8/vp9、AV1编码(webm格式),这些编码在之前的Safari上是不支持的,所有就没有4K的选择,但在big sur 之后苹果支持了webm的格式,这样新版的Safari也就可以播放上面的4K视频了;

还有一个反过来的现象是当你用iPhone拍的视频(默认用h.265),放到Mac上去播放,Safari当然没问题,但是在Chrome里就放不了,那是因为Chrome还不支持h.265的视频编码,以上2中现象就是因不同的视频编码导致在不同的浏览器上兼容性不一样的问题。

常用流媒体协议

当我们用本地播放器播放一个本地几个G的视频文件时确实没啥问题,但是随着越来越多的人选择在线观看电影视频,我们不可能等浏览器下载完几G的视频后再开始播放,这样的速度简直比🐌还慢,所有就出现了流媒体协议,也就是所谓的边下边播,这样就大大提升了在线观看的体验,当然你流媒体协议不管怎么变,视频内容本身还是基于上面讲的这几种编码格式。

下面就是常见的几种流媒体协议:

协议 应用领域 支持音视频编码 优缺点
HTTP-FLV 直播 H.264 + AAC / MP3等 延迟低
HLS 直播/点播(自适应比特流) H.265, H.264 + AAC, MP3, Apple Lossless, FLAC… Apple搞的协议,兼容性好,延迟高(通过Low Latency HLS解决)
MPEG-DASH 直播/点播(自适应比特流) 不限编码 国际标准,对标苹果的HLS
RTMP 目前主要推流端 H.264, VP8 等 带宽消耗低,延迟低,浏览器播放需要Flash

首先回顾下历史,当年乔布斯决定把Flash干掉后,到现在Flash在浏览器里面基本已经没有存在的必要了,但是随Flash一起诞生的flv容器格式在浏览器里似乎还活的有滋有味,当然也要归功于B站开源的flv.js,即使浏览器里没有了Flash, 我们通过flv.js还是能够正常播放flv容器格式的视频内容,flv在国内网站直播中用的还是很多的,也主要是觉得http-flv的低延迟还是很有优势的。 HLS(Http Live Streming),苹果搞的协议,苹果说既然我们遵循乔帮主的思想不再支持Flash,那总得再造个轮子搞流媒体播放吧,我们呢也不想造太底层的轮子,还是基于http来吧,毕竟http服务已经很成熟了,而且兼容性不要太好,然后就诞生了HLS流媒体协议,依托于iphone的使用量,HLS在流媒体当中的占有率还是相当高的:

protocal-share.png

跟HLS相对应的MPEG-DASH(还是那个MPEG组织),MPEG想苹果你怎么老是喜欢自己造轮子,又不开源,哎,算了,为了不被你垄断,我们还是很有必要搞一个跟HLS类似的开源流媒体协议出来,然后MPEG-DASH就出来了,从上图看起来占有率似乎还不是很高,但是毕竟开源,各个视频大厂门都已经在用了包括国内的B站,国外的油管、网飞等,未来可期。

上面的表中说明了HLS, MPEG-DASH支持自适应比特流,简单来说就是对于这2种流媒体协议来说,一个源视频文件会根据需要支持的不同分辨率,切割成不同的一个个小的视频文件,一般在几百K到小几M之间,这样的话当网络速度变化的时候就可以快速切到满足当前网速的分辨率上对应的切片文件了,可以做到保证播放流畅度的时候无缝切换,大大提升用户体验,可以看下图感受下:

abs-demo.png

直播链路

HLS, MPEG-DASH主要用于点播,你在B站看up主视频,去爱优酷腾看个电视剧,这些都是点播,也就是所有的视频都提前进行了转码,生成了不同的分辨率,及选择HLS或DASH后生成了对应的切片文件;那在直播的情况下又是怎样呢,其实在用户端观看时基本差不多,主要区别在于推流端,点播情况下主要是用户上传视频,然后视频云进行转码等操作,那直播相当于是边录制边上传的过程,视频来源可以是摄像机,电脑摄像头,当然现在最简单的直播就是直接用手机app开个直播,基本类似于视频会议的感觉。

以下找了张图说明了直播的整个流程:首先在推流端,也就是主播那边,主播可能通过电脑上的软件(常用的如开源的OBS),打开摄像头,设置好推流连接、协议,现在用的比较多的是RTMP,也是Flash那时候的产物,没有了Flash, RTMP在浏览器端就基本没法用了,但是在推流端还是被广泛的使用着,可以回看下上面占有率的图,RTMP还有1/3主要的占有率,当主播的视频信息通过推流协议推送到平台的云端服务器后,会实时的进行转码转格式的操作,转完后实时推送到CDN上,然后利用CDN的速度,区域性,用户端就可以以更小的延迟观看直播了。

live-streaming.png

Flash Video(.flv文件) + flvjs

上面提到了flv格式的视频至少在国内还是在被大量的使用,如果去看下直播页面的网络请求的话,有很多都是以.flv结尾的请求,包括B站的直播(当然也不是全部),在主播的直播页面里可以看到:

live-flv.png 爱奇艺里的主播直播也是flv, 甚至在头条app里的一些直播,如果你去抓包的话也会发现很多flv,所有这些用flv作直播的情况只要在浏览器里面基本都是用的flv.js来处理的,所以下面我们不妨看一看flv.js大致的工作流程,先上图(取自flv.js官方github):

flvjs.png

当我们进入直播页面时,flvplayer就要先去请求.flv的地址了,首先会通过IO Loaders里的根据当前浏览器选择合适的loader去加载视频数据,我们看上图的直播地址(network里的type是fetch),应该用的是FetchStreamLoader, 因为fetch支持stream, 可以一块一块的获取数据,每当拿到一块完整的数据后,会经过FlvDemuxer处理,也就是把flv容器格式解开,拿到里面原始的AVC/AAC音视频数据,然后通过MP4Remuxer重新封装成合法的mp4格式,向上传给Transmuxer,通过浏览器自带的MediaSource喂给video标签,然后就可以播放flv格式的视频了。

所以如果浏览器不支持MediaSource, flv.js也就没有用了,在本文的开始说了iOS不支持MediaSource(iPad倒是支持🤪, 这里仅指iPhone), 也就是flv.js在ios的safari里是用不了的,因此我们如果在ios的safari里打开bilibili.com, 会发现它是直接用了一个MP4的地址,没走blob连接,类似下图:

bili-ios-player.png

再看看爱奇艺的情况,因为爱奇艺的播放主要基于HLS, 所以在ios端也可以完美的运用hls协议:

iqiyi.png

可以看到手机端H5上爱奇艺直接用的.m3u8的地址(当然不管是直接MP4, 还是原始hls, 他们在H5上的核心逻辑就是想尽各种办法让你下载或者跳到app里去🤪),m3u8是HLS协议的入口文件,就是个文本文件,通过这个文件系统可以去获取视频的各个切片文件,由于是苹果搞的协议,所有m3u8格式的文本文件可以直接扔到video的src标签上,safari可以做到原生支持(不需要额外的hls.js处理),有兴趣的同学可以把这个m3u8地址直接扔到Mac上的safari地址栏里,他会直接开始播放了,但是放到chrome就直接提示你下载这个文件,因为原生不支持,除非你安装了HLS的插件。

生成符合HLS、MPEG-DASH的工具及前端播放器

扯了这么多,那我们怎么自己能够把一个电影文件,生成支持这些流媒体协议的切片文件呢,当然已经有现成的各种工具了,以及我们前端能够用来播放这些流媒体文件的库了,这里就简单的列举下,怎么用也就是看这些文档的事情了😇

协议 命令行工具 支持的播放器/JS库
HTTP-FLV FFmpeg flv.js
HLS Apple HTTP Live Streaming tools;
FFmpeg;
Shaka Packager by Google;
mp4box by GPAC;
Bento4
hls.js, video.js, shaka-player
MPEG-DASH FFmpeg;
Shaka Packager by Google;
mp4box by GPAC;
Bento4
dash.js, video.js, shaka-player

Bonus: 手动下载个Bilibili视频吧

最后我们就来动动🖐吧,我们已经知道B站用的流媒体协议是MPEG-Dash, 而dash正常来说用的入口文件时以.mpd结尾的xml文件(类似HLS的m3u8文件),但是我们发现在浏览器的网络请求里压根没有mpd的请求,然后经过一番查找,发现他是把dash相关的数据直接都扔到了html里,大家可以点开一个视频页面,右键查看源代码,搜索dash,就可以发现类似下图所示的JS对象,里面的dash字段包含了视频的链接,各个支持的分辨率等信息:

source-dash.png

上图中我们还可以发现单独video, audio字段,也就他把视频和音频数据给拆开了,会用单独的url去加载,这样做的好处是音视频互相独立,当我们切换较低分辨率的时候,我们可以依然请求较高质量的音频数据,避免因为分辨率调低,音质也降低了。

接下来我们直接看浏览器里的Network请求, 用m4s过滤下, m4s是dash的切片文件后缀名,但是其内容其实就是mp4的部分内容,理论上来说只要把所有的m4s切片合成一个mp4,就可以播放了,不需要额外处理。我们这里看下图左边请求列表里,主要有2个path,xxx-30112.m4sxxx-30280.m4s,可以大致猜出来一个是视频一个是音频,然后我们分别复制他们对应的curl连接

image.png

再看下图我们可以发现对于视频文件来说,他并不是切成了不同的文件名,而是以Header里的Range头来获取文件的不同部分, 我们通过response里的Content-Range可以知道当前文件的总大小,在/后面的数字,这里我们就可以投机取巧下,不用单独下载所有的切片,直接把上面copy的curl请求里的Range改成0-181545880,这里结束处需要减1,因为是从0开始。

image.png

然后我们把刚才的curl可以放到命令行,或者其他发请求的工具上,这里我们用Insomnic为例,你可以把curl直接粘贴进去,他可以自动转化,然后把Range调整下,发送请求,把response原始数据保存下来为mp4文件(音频也做同样的操作) :

dl-video.png

当音视频全部下完后,你其实已经可以单独播放这2个文件了,只是一个只有视频信息,一个只有音频信息,有些播放器可以直接导入音频(列如iina),你都不需要合并了,当然这里为了完整性,我们还是借助ffmpeg把音视频文件合并成一个完整的MP4文件:

ffmpeg -i video.mp4 -i audio.mp4 -c:v copy -c:a copy output.mp4

这样最后出来的output.mp4就可以直接播放了🎉,这样我们就完成了一个手动下载流媒体视频的过程,给自己👏下吧!!!

总结

以上就是对前端流媒体播放的基本介绍,我们通过一些实际的例子,及在不同视频网站上看到的一些不同的处理,对前端视频相关的知识有了入门的理解,希望大家通过本文能够做到入门,甚至能够入了前端流媒体的坑,有兴趣的同学可以再做深入的研究💪。

今天的文章前端流媒体播放从入门到入坑分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/14500.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注